From d92e80ce9233bdc29b60c006e6a1911fc564d151 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 09:46:07 +1000 Subject: [PATCH 001/746] Remove translation repo submodule --- .gitmodules | 3 --- lib/l10n | 1 - 2 files changed, 4 deletions(-) delete mode 160000 lib/l10n diff --git a/.gitmodules b/.gitmodules index 4de5b51..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "lib/l10n"] - path = lib/l10n - url = git@github.com:inventree/inventree-app-i18n.git diff --git a/lib/l10n b/lib/l10n deleted file mode 160000 index a1683e4..0000000 --- a/lib/l10n +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a1683e462bb8c91d481cdacb169cb98d63e93acc From 1f75fb4c92f0c705473cdd01c90e0a7ca02803f0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 09:56:58 +1000 Subject: [PATCH 002/746] Add latest translation files --- lib/l10n/.gitignore | 2 + lib/l10n/app_en.arb | 1085 ++++++++++++++++++++++++++++++ lib/l10n/collect_translations.py | 93 +++ lib/l10n/crowdin.yml | 3 + lib/l10n/cs/app_cs.arb | 5 + lib/l10n/de/app_de.arb | 745 ++++++++++++++++++++ lib/l10n/el/app_el.arb | 5 + lib/l10n/es-419/app_es.arb | 3 + lib/l10n/es-ES/app_es.arb | 635 +++++++++++++++++ lib/l10n/es-MX/app_es.arb | 17 + lib/l10n/fa/app_fa.arb | 5 + lib/l10n/fr/app_fr.arb | 743 ++++++++++++++++++++ lib/l10n/he/app_he.arb | 5 + lib/l10n/hu/app_hu.arb | 745 ++++++++++++++++++++ lib/l10n/id/app_id.arb | 5 + lib/l10n/it/app_it.arb | 505 ++++++++++++++ lib/l10n/ja/app_ja.arb | 682 +++++++++++++++++++ lib/l10n/ko/app_ko.arb | 105 +++ lib/l10n/nl/app_nl.arb | 5 + lib/l10n/no/app_no.arb | 5 + lib/l10n/pl/app_pl.arb | 739 ++++++++++++++++++++ lib/l10n/pt-BR/app_pt.arb | 5 + lib/l10n/pt-PT/app_pt.arb | 193 ++++++ lib/l10n/ru/app_ru.arb | 263 ++++++++ lib/l10n/sv-SE/app_sv.arb | 5 + lib/l10n/th/app_th.arb | 5 + lib/l10n/tr/app_tr.arb | 735 ++++++++++++++++++++ lib/l10n/vi/app_vi.arb | 5 + lib/l10n/zh-CN/app_zh.arb | 341 ++++++++++ 29 files changed, 7689 insertions(+) create mode 100644 lib/l10n/.gitignore create mode 100644 lib/l10n/app_en.arb create mode 100644 lib/l10n/collect_translations.py create mode 100644 lib/l10n/crowdin.yml create mode 100644 lib/l10n/cs/app_cs.arb create mode 100644 lib/l10n/de/app_de.arb create mode 100644 lib/l10n/el/app_el.arb create mode 100644 lib/l10n/es-419/app_es.arb create mode 100644 lib/l10n/es-ES/app_es.arb create mode 100644 lib/l10n/es-MX/app_es.arb create mode 100644 lib/l10n/fa/app_fa.arb create mode 100644 lib/l10n/fr/app_fr.arb create mode 100644 lib/l10n/he/app_he.arb create mode 100644 lib/l10n/hu/app_hu.arb create mode 100644 lib/l10n/id/app_id.arb create mode 100644 lib/l10n/it/app_it.arb create mode 100644 lib/l10n/ja/app_ja.arb create mode 100644 lib/l10n/ko/app_ko.arb create mode 100644 lib/l10n/nl/app_nl.arb create mode 100644 lib/l10n/no/app_no.arb create mode 100644 lib/l10n/pl/app_pl.arb create mode 100644 lib/l10n/pt-BR/app_pt.arb create mode 100644 lib/l10n/pt-PT/app_pt.arb create mode 100644 lib/l10n/ru/app_ru.arb create mode 100644 lib/l10n/sv-SE/app_sv.arb create mode 100644 lib/l10n/th/app_th.arb create mode 100644 lib/l10n/tr/app_tr.arb create mode 100644 lib/l10n/vi/app_vi.arb create mode 100644 lib/l10n/zh-CN/app_zh.arb diff --git a/lib/l10n/.gitignore b/lib/l10n/.gitignore new file mode 100644 index 0000000..585ff49 --- /dev/null +++ b/lib/l10n/.gitignore @@ -0,0 +1,2 @@ +# Ignore collected files +collected/ diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..dc95339 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,1085 @@ +{ + "@@locale": "en", + + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + + "ok": "OK", + "@ok": { + "description": "OK" + }, + + "about": "About", + "@about": {}, + + "accountDetails": "Account Details", + "@accountDetails": {}, + + "actions": "Actions", + "@actions": { + "description": "" + }, + + "actionsNone": "No actions available", + "@actionsNone": {}, + + "add": "Add", + "@add": { + "description": "add" + }, + + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + + "address": "Address", + "@address": {}, + + "appAbout": "About InvenTree", + "@appAbout": {}, + + "appCredits": "Additional app credits", + "@appCredits": {}, + + "appDetails": "App Details", + "@appDetails": {}, + + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + + "appSettings": "App Settings", + "@appSettings": {}, + + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + + "attachments": "Attachments", + "@attachments": {}, + + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + + "attachmentNonePartDetail": "No attachments found for this part", + "@attachmentNonePartDetail": {}, + + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + + "attention": "Attention", + "@attention": {}, + + "availableStock": "Available Stock", + "@availableStock": {}, + + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + + "barcodeScanInItems": "Scan stock items into location", + "@barcodeScanInItems": {}, + + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + + "batchCode": "Batch Code", + "@batchCode": {}, + + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + + "bom": "BOM", + "@bom": {}, + + "build": "Build", + "@build": {}, + + "building": "Building", + "@building": {}, + + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + + "category": "Category", + "@category": {}, + + "categoryCreate": "New Category", + "@categoryCreate": {}, + + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + + "company": "Company", + "@company": {}, + + "companyEdit": "Edit Company", + "@companyEdit": {}, + + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + + "companies": "Companies", + "@companies": {}, + + "configureServer": "Configure server settings", + "@configureServer": {}, + + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + + "count": "Count", + "@count": { + "description": "Count" + }, + + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + + "credits": "Credits", + "@credits": {}, + + "customers": "Customers", + "@customers": {}, + + "damaged": "Damaged", + "@damaged": {}, + + "delete": "Delete", + "@delete": {}, + + "deletePart": "Delete Part", + "@deletePart": {}, + + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + + "description": "Description", + "@description": {}, + + "destroyed": "Destroyed", + "@destroyed": {}, + + "details": "Details", + "@details": { + "description": "details" + }, + + "documentation": "Documentation", + "@documentation": {}, + + "downloading": "Downloading File", + "@downloading": {}, + + "downloadError": "Download Error", + "@downloadError": {}, + + "edit": "Edit", + "@edit": { + "description": "edit" + }, + + "editCategory": "Edit Category", + "@editCategory": {}, + + "editLocation": "Edit Location", + "@editLocation": {}, + + "editNotes": "Edit Notes", + "@editNotes": {}, + + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + + "editItem": "Edit Stock Item", + "@editItem": {}, + + "enterPassword": "Enter password", + "@enterPassword": {}, + + "enterUsername": "Enter username", + "@enterUsername": {}, + + "error": "Error", + "@error": { + "description": "Error" + }, + + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + + "errorDetails": "Error Details", + "@errorDetails": {}, + + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + + "errorReporting": "Error Reporting", + "@errorReporting": {}, + + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + + "feedback": "Feedback", + "@feedback": {}, + + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + + "formatException": "Format Exception", + "@formatException": {}, + + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + + "formError": "Form Error", + "@formError": {}, + + "history": "History", + "@history": { + "description": "history" + }, + + "homeScreen": "Home Screen", + "@homeScreen": {}, + + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + + "inactive": "Inactive", + "@inactive": {}, + + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + + "includeSubcategoriesDetail": "Display subcategory parts in list view", + "@includeSubcategoriesDetail": {}, + + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + + "includeSublocationsDetail": "Display sublocation items in list view", + "@includeSublocationsDetail": {}, + + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + + "info": "Info", + "@info": {}, + + "inProduction": "In Production", + "@inProduction": {}, + + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + + "invalidPart": "Invalid Part", + "@invalidPart": {}, + + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + + "issueDate": "Issue Date", + "@issueDate": {}, + + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + + "keywords": "Keywords", + "@keywords": {}, + + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + + "lineItem": "Line Item", + "@lineItem": {}, + + "lineItems": "Line Items", + "@lineItems": {}, + + "locationCreate": "New Location", + "@locationCreate": {}, + + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + + "locationNotSet": "No location specified", + "@locationNotSet": {}, + + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + + "link": "Link", + "@link": {}, + + "lost": "Lost", + "@lost": {}, + + "manufacturers": "Manufacturers", + "@manufacturers": {}, + + "missingData": "Missing Data", + "@missingData": {}, + + "name": "Name", + "@name": { + }, + + "notConnected": "Not Connected", + "@notConnected": {}, + + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + + "noResponse": "No Response from Server", + "@noResponse": {}, + + "noResults": "No Results", + "@noResults": {}, + + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + + "onOrder": "On Order", + "@onOrder": {}, + + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + + "packaging": "Packaging", + "@packaging": {}, + + "packageName": "Package Name", + "@packageName": {}, + + "parent": "Parent", + "@parent": {}, + + "parentCategory": "Parent Category", + "@parentCategory": {}, + + "parentLocation": "Parent Location", + "@parentLocation": {}, + + "part": "Part", + "@part": { + "description": "Part (single)" + }, + + "partCreate": "New Part", + "@partCreate": {}, + + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + + "partEdited": "Part updated", + "@partEdited": {}, + + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + + "partsNone": "No Parts", + "@partsNone": {}, + + "partNoResults": "No parts matching query", + "@partNoResults": {}, + + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + + "partCategory": "Part Category", + "@partCategory": {}, + + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + + "partCategories": "Part Categories", + "@partCategories": {}, + + "partDetails": "Part Details", + "@partDetails": {}, + + "partNotes": "Part Notes", + "@partNotes": {}, + + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + + "password": "Password", + "@password": {}, + + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + + "printLabel": "Print Label", + "@printLabel": {}, + + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + + "profile": "Profile", + "@profile": {}, + + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + + "profileConnect": "Connect to Server", + "@profileConnect": {}, + + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + + "profileName": "Profile Name", + "@profileName": {}, + + "profileNone": "No profiles available", + "@profileNone": {}, + + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + + "queryNoResults": "No results for query", + "@queryNoResults": {}, + + "received": "Received", + "@received": {}, + + "receiveItem": "Receive Item", + "@receiveItem": {}, + + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + + "refresh": "Refresh", + "@refresh": {}, + + "refreshing": "Refreshing", + "@refreshing": {}, + + "rejected": "Rejected", + "@rejected": {}, + + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + + "remove": "Remove", + "@remove": { + "description": "remove" + }, + + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + + "reportBug": "Report Bug", + "@reportBug": {}, + + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + + "results": "Results", + "@results": {}, + + "request": "Request", + "@request": {}, + + "requestingData": "Requesting Data", + "@requestingData": {}, + + "required": "Required", + "@required": { + "description": "This field is required" + }, + + "response400": "Bad Request", + "@response400": {}, + + "response401": "Unauthorized", + "@response401": {}, + + "response403": "Permission Denied", + "@response403": {}, + + "response404": "Resource Not Found", + "@response404": {}, + + "response405": "Method Not Allowed", + "@response405": {}, + + "response429": "Too Many Requests", + "@response429": {}, + + "response500": "Internal Server Error", + "@response500": {}, + + "response501": "Not Implemented", + "@response501": {}, + + "response502": "Bad Gateway", + "@response502": {}, + + "response503": "Service Unavailable", + "@response503": {}, + + "response504": "Gateway Timeout", + "@response504": {}, + + "response505": "HTTP Version Not Supported", + "@response505": {}, + + "responseData": "Response data", + "@responseData": {}, + + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + + "result": "Result", + "@result": { + "description": "" + }, + + "returned": "Returned", + "@returned": {}, + + "salesOrders": "Sales Orders", + "@salesOrders": {}, + + "save": "Save", + "@save": { + "description": "Save" + }, + + "scanBarcode": "Scan Barcode", + "@scanBarcode": { + }, + + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + + "search": "Search", + "@search": { + "description": "search" + }, + + "searchLocation": "Search for location", + "@searchLocation": {}, + + "searchParts": "Search Parts", + "@searchParts": {}, + + "searchStock": "Search Stock", + "@searchStock": {}, + + "select": "Select", + "@select": {}, + + "selectFile": "Select File", + "@selectFile": {}, + + "selectImage": "Select Image", + "@selectImage": {}, + + "selectLocation": "Select a location", + "@selectLocation": {}, + + "send": "Send", + "@send": {}, + + "serialNumber": "Serial Number", + "@serialNumber": {}, + + "server": "Server", + "@server": {}, + + "serverAddress": "Server Address", + "@serverAddress": {}, + + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + + "serverConnected": "Connected to Server", + "@serverConnected": {}, + + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + + "serverError": "Server Error", + "@serverError": {}, + + "serverDetails": "Server Details", + "@serverDetails": {}, + + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + + "serverOld": "Old Server Version", + "@serverOld": {}, + + "serverSettings": "Server Settings", + "@serverSettings": {}, + + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + + "settings": "Settings", + "@settings": {}, + + "serverInstance": "Server Instance", + "@serverInstance": {}, + + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + + "sounds": "Sounds", + "@sounds": {}, + + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + + "status": "Status", + "@status": {}, + + "statusCode": "Status Code", + "@statusCode": {}, + + "stock": "Stock", + "@stock": { + "description": "stock" + }, + + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + + "stockItems": "Stock Items", + "@stockItems": {}, + + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + + "stockLocations": "Stock Locations", + "@stockLocations": {}, + + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + + "subcategory": "Subcategory", + "@subcategory": {}, + + "subcategories": "Subcategories", + "@subcategories": {}, + + "sublocation": "Sublocation", + "@sublocation": {}, + + "sublocations": "Sublocations", + "@sublocations": {}, + + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + + "supplier": "Supplier", + "@supplier": {}, + + "suppliers": "Suppliers", + "@suppliers": {}, + + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + + "takePicture": "Take Picture", + "@takePicture": {}, + + "targetDate": "Target Date", + "@targetDate": {}, + + "templatePart": "Parent Template Part", + "@templatePart": {}, + + "testName": "Test Name", + "@testName": {}, + + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + + "testsRequired": "Required Tests", + "@testsRequired": {}, + + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + + "testResultNone": "No Test Results", + "@testResultNone": {}, + + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + + "tokenError": "Token Error", + "@tokenError": {}, + + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + + "translate": "Translate", + "@translate": {}, + + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + + "units": "Units", + "@units": {}, + + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + + "upload": "Upload", + "@upload": {}, + + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + + "usedIn": "Used In", + "@usedIn": {}, + + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + + "username": "Username", + "@username": {}, + + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + + "value": "Value", + "@value": { + "description": "value" + }, + + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + + "valueRequired": "Value is required", + "@valueRequired": {}, + + "version": "Version", + "@version": {}, + + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + + "website": "Website", + "@website": {} +} diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py new file mode 100644 index 0000000..56e3dbe --- /dev/null +++ b/lib/l10n/collect_translations.py @@ -0,0 +1,93 @@ +""" +Collect translation files into a single directory, +where they can be accessed by the flutter i18n library. + +Translations provided from crowdin are located in subdirectories, +but we need the .arb files to appear in this top level directory +to be accessed by the app. + +So, simply copy them here! + +""" + +import os +import shutil +import re +import json + +def process_locale_file(filename): + """ + Process a locale file after copying + + - Ensure the 'locale' matches + """ + + # Extract the locale name from the filename + f = os.path.basename(filename) + locale = re.search(r"^app\_(\w+)\.arb$", f).groups()[0] + + # TODO: Use JSON processing instead of manual + # Need to work out unicode issues for this to work + + with open(filename, 'r', encoding='utf-8') as input_file: + + lines = input_file.readlines() + + with open(filename, 'w', encoding='utf-8') as output_file: + # Using JSON processing would be simpler here, + # but it does not preserve unicode data! + for line in lines: + if '@@locale' in line: + new_line = f' "@@locale": "{locale}"' + + if ',' in line: + new_line += ',' + + new_line += '\n' + + line = new_line + + output_file.write(line) + + +def copy_locale_file(path): + """ + Locate and copy the locale file from the provided directory + """ + + here = os.path.abspath(os.path.dirname(__file__)) + + for f in os.listdir(path): + + src = os.path.join(path, f) + dst = os.path.join(here, 'collected', f) + + if os.path.exists(src) and os.path.isfile(src) and f.endswith('.arb'): + + shutil.copyfile(src, dst) + print(f"Copied file '{f}'") + + process_locale_file(dst) + + +if __name__ == '__main__': + + here = os.path.abspath(os.path.dirname(__file__)) + + for item in os.listdir(here): + + # Ignore the output directory + if item == 'collected': + continue + + f = os.path.join(here, item) + + if os.path.exists(f) and os.path.isdir(item): + copy_locale_file(f) + + # Ensure the translation source file ('app_en.arb') is copied also + # Note that this does not require any further processing + src = os.path.join(here, 'app_en.arb') + dst = os.path.join(here, 'collected', 'app_en.arb') + + shutil.copyfile(src, dst) diff --git a/lib/l10n/crowdin.yml b/lib/l10n/crowdin.yml new file mode 100644 index 0000000..dfa2384 --- /dev/null +++ b/lib/l10n/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: app_en.arb + translation: app_%two_letters_code%.arb diff --git a/lib/l10n/cs/app_cs.arb b/lib/l10n/cs/app_cs.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/cs/app_cs.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/de/app_de.arb b/lib/l10n/de/app_de.arb new file mode 100644 index 0000000..799c802 --- /dev/null +++ b/lib/l10n/de/app_de.arb @@ -0,0 +1,745 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Über", + "@about": {}, + "accountDetails": "Konto Details", + "@accountDetails": {}, + "actions": "Aktionen", + "@actions": { + "description": "" + }, + "actionsNone": "Keine Aktionen verfügbar", + "@actionsNone": {}, + "add": "Hinzufügen", + "@add": { + "description": "add" + }, + "addStock": "Bestand hinzufügen", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "Über InvenTree", + "@appAbout": {}, + "appCredits": "Weitere App-Danksagungen", + "@appCredits": {}, + "appDetails": "App-Informationen", + "@appDetails": {}, + "appReleaseNotes": "App-Versionshinweise anzeigen", + "@appReleaseNotes": {}, + "appSettings": "App-Einstellungen", + "@appSettings": {}, + "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", + "@appSettingsDetails": {}, + "attachments": "Anhänge", + "@attachments": {}, + "attachImage": "Bild hinzufügen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Keine Anhänge gefunden", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Anhang auswählen", + "@attachmentSelect": {}, + "attention": "Achtung", + "@attention": {}, + "availableStock": "Verfügbarer Lagerbestand", + "@availableStock": {}, + "barcodeAssign": "Barcode zuweisen", + "@barcodeAssign": {}, + "barcodeAssigned": "Barcode zugewiesen", + "@barcodeAssigned": {}, + "barcodeError": "Fehler beim Scannen des Barcodes", + "@barcodeError": {}, + "barcodeInUse": "Barcode wurde bereits zugewiesen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Prüfsumme fehlt in Antwort", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Keine Übereinstimmung für den Barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode nicht zugewiesen", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scannen um Barcode zuzuweisen", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Einen InvenTree Barcode scannen", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Artikel per Barcode-Scan zu Lagerort hinzufügen", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Lagerort scannen", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Artikel scannen", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode-Ton", + "@barcodeTones": {}, + "barcodeUnassign": "Barcode entfernen", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode wurde nicht erkannt", + "@barcodeUnknown": {}, + "batchCode": "Losnummer", + "@batchCode": {}, + "billOfMaterials": "Stückliste", + "@billOfMaterials": {}, + "bom": "Stückliste", + "@bom": {}, + "build": "Bauauftrag", + "@build": {}, + "building": "Gebäude", + "@building": {}, + "cancel": "Abbrechen", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategorie", + "@category": {}, + "categoryCreate": "Neue Kategorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Teile-Kategorie anlegen", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategorie aktualisiert", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Firma bearbeiten", + "@companyEdit": {}, + "companyNoResults": "Keine Firmen entsprechen der Anfrage", + "@companyNoResults": {}, + "companyUpdated": "Firmendetails aktualisiert", + "@companyUpdated": {}, + "companies": "Firmen", + "@companies": {}, + "configureServer": "Server-Einstellungen konfigurieren", + "@configureServer": {}, + "connectionRefused": "Verbindung verweigert", + "@connectionRefused": {}, + "count": "Zählen", + "@count": { + "description": "Count" + }, + "countStock": "Bestand zählen", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Danksagungen", + "@credits": {}, + "customers": "Kunden", + "@customers": {}, + "damaged": "Beschädigt", + "@damaged": {}, + "delete": "Löschen", + "@delete": {}, + "deletePart": "Teil löschen", + "@deletePart": {}, + "deletePartDetail": "Dieses Teil aus der Datenbank löschen", + "@deletePartDetail": {}, + "description": "Beschreibung", + "@description": {}, + "destroyed": "Vernichtet", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloading": "Datei wird heruntergeladen", + "@downloading": {}, + "downloadError": "Fehler beim Herunterladen", + "@downloadError": {}, + "edit": "Bearbeiten", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategorie bearbeiten", + "@editCategory": {}, + "editLocation": "Ort bearbeiten", + "@editLocation": {}, + "editNotes": "Notizen bearbeiten", + "@editNotes": {}, + "editPart": "Teil bearbeiten", + "@editPart": { + "description": "edit part" + }, + "editItem": "Artikel bearbeiten", + "@editItem": {}, + "enterPassword": "Passwort eingeben", + "@enterPassword": {}, + "enterUsername": "Benutzername eingeben", + "@enterUsername": {}, + "error": "Fehler", + "@error": { + "description": "Error" + }, + "errorCreate": "Fehler beim Erstellen des Datenbankeintrages", + "@errorCreate": {}, + "errorDelete": "Fehler beim Löschen von Datenbankeintrag", + "@errorDelete": {}, + "errorDetails": "Fehlerdetails", + "@errorDetails": {}, + "errorFetch": "Fehler beim Abrufen der Daten vom Server", + "@errorFetch": {}, + "errorReporting": "Fehlerberichterstattung", + "@errorReporting": {}, + "errorReportUpload": "Fehlerberichte hochladen", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fehler beim Senden des Feedbacks", + "@feedbackError": {}, + "feedbackSuccess": "Feedback gesendet", + "@feedbackSuccess": {}, + "formatException": "Formatfehler", + "@formatException": {}, + "formatExceptionJson": "Format-Fehler im JSON", + "@formatExceptionJson": {}, + "formError": "Formular-Fehler", + "@formError": {}, + "history": "Verlauf", + "@history": { + "description": "history" + }, + "homeScreen": "Startseite", + "@homeScreen": {}, + "homeScreenSettings": "Einstellungen für Startseite konfigurieren", + "@homeScreenSettings": {}, + "homeShowPo": "Bestellungen anzeigen", + "@homeShowPo": {}, + "homeShowSubscribed": "Abonnierte Teile", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Lieferanten anzeigen", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Hersteller anzeigen", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Hersteller auf Startseite anzeigen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Kunden anzeigen", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Kunden auf Startseite anzeigen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Das Bild konnte nicht hochgeladen werden", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Bild hochgeladen", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveDetail": "Teil als inaktiv gekennzeichnet", + "@inactiveDetail": {}, + "includeSubcategories": "Unter-Kategorien einschließen", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Teile aus Unter-Kategorien anzeigen", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Unter-Lagerorte einschließen", + "@includeSublocations": {}, + "includeSublocationsDetail": "Liste der Unter-Lagerorte anzeigen", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil unvollständig", + "@incompleteDetails": {}, + "internalPartNumber": "Interne Teilenummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Produktion", + "@inProduction": {}, + "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", + "@inProductionDetail": {}, + "invalidHost": "Ungültiger Hostname", + "@invalidHost": {}, + "invalidHostDetails": "Der angegebener Hostname ist ungültig", + "@invalidHostDetails": {}, + "invalidPart": "Ungültiges Teil", + "@invalidPart": {}, + "invalidPartCategory": "Ungültige Teil-Kategorie", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ungültiger Lagerort", + "@invalidStockLocation": {}, + "invalidStockItem": "Ungültiger Artikel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", + "@invalidUsernamePassword": {}, + "issueDate": "Ausstellungsdatum", + "@issueDate": {}, + "itemInLocation": "Artikel ist bereits in diesem Lagerort", + "@itemInLocation": {}, + "keywords": "Schlüsselwörter", + "@keywords": {}, + "lastStocktake": "Letzte Inventur", + "@lastStocktake": {}, + "lastUpdated": "Letzte Änderung", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Positionen", + "@lineItems": {}, + "locationCreate": "Neuer Lagerort", + "@locationCreate": {}, + "locationCreateDetail": "Neuen Lagerort erstellen", + "@locationCreateDetail": {}, + "locationNotSet": "Lagerort nicht angegeben", + "@locationNotSet": {}, + "locationUpdated": "Lagerort aktualisiert", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "manufacturers": "Hersteller", + "@manufacturers": {}, + "missingData": "Fehlende Daten", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Nicht verbunden", + "@notConnected": {}, + "notes": "Notizen", + "@notes": { + "description": "Notes" + }, + "noResponse": "Keine Antwort vom Server", + "@noResponse": {}, + "noResults": "Keine Ergebnisse", + "@noResults": {}, + "noSubcategories": "Keine Unter-Kategorien", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Keine gültige Zahl", + "@numberInvalid": {}, + "onOrder": "Bestellt", + "@onOrder": {}, + "onOrderDetails": "Artikel wurde bestellt", + "@onOrderDetails": {}, + "packaging": "Paket", + "@packaging": {}, + "packageName": "Paket-Name", + "@packageName": {}, + "parent": "Übergeordnetes", + "@parent": {}, + "parentCategory": "Übergeordnete Kategorie", + "@parentCategory": {}, + "parentLocation": "Übergeordneter Lagerort", + "@parentLocation": {}, + "part": "Teil", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Teil anlegen", + "@partCreate": {}, + "partCreateDetail": "Teil in dieser Kategorie anlegen", + "@partCreateDetail": {}, + "partEdited": "Teil aktualisiert", + "@partEdited": {}, + "parts": "Teile", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Keine Teile", + "@partsNone": {}, + "partNoResults": "Keine Teile entsprechen der Anfrage", + "@partNoResults": {}, + "partsStarred": "Abonnierte Teile", + "@partsStarred": {}, + "partsStarredNone": "Keine Teile abonniert", + "@partsStarredNone": {}, + "partSuppliers": "Teile-Lieferanten", + "@partSuppliers": {}, + "partCategory": "Teil-Kategorie", + "@partCategory": {}, + "partCategoryTopLevel": "Oberste Teile-Kategorie", + "@partCategoryTopLevel": {}, + "partCategories": "Teil-Kategorien", + "@partCategories": {}, + "partDetails": "Teil-Details", + "@partDetails": {}, + "partNotes": "Teil-Bemerkungen", + "@partNotes": {}, + "partStock": "Teilbestand", + "@partStock": { + "description": "part stock" + }, + "password": "Passwort", + "@password": {}, + "passwordEmpty": "Passwort darf nicht leer sein", + "@passwordEmpty": {}, + "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", + "@permissionAccountDenied": {}, + "permissionRequired": "Berechtigung erforderlich", + "@permissionRequired": {}, + "printLabel": "Label drucken", + "@printLabel": {}, + "printLabelFailure": "Labeldruck fehlgeschlagen", + "@printLabelFailure": {}, + "printLabelSuccess": "Label an den Drucker gesendet", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Server-Profil anlegen", + "@profileAdd": {}, + "profileConnect": "Mit Server verbinden", + "@profileConnect": {}, + "profileEdit": "Server-Profil bearbeiten", + "@profileEdit": {}, + "profileDelete": "Server-Profil löschen", + "@profileDelete": {}, + "profileName": "Profil-Name", + "@profileName": {}, + "profileNone": "Keine Profile angelegt", + "@profileNone": {}, + "profileNotSelected": "Kein Profil ausgewählt", + "@profileNotSelected": {}, + "profileSelect": "InvenTree-Server auswählen", + "@profileSelect": {}, + "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", + "@profileTapToCreate": {}, + "purchaseOrder": "Bestellung", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Bestellung bearbeiten", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Bestellungen", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bestellung aktualisiert", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Einkaufspreis", + "@purchasePrice": {}, + "quantity": "Anzahl", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Menge ist leer", + "@quantityEmpty": {}, + "quantityInvalid": "Menge ist ungültig", + "@quantityInvalid": {}, + "quantityPositive": "Menge muss positiv sein", + "@quantityPositive": {}, + "queryNoResults": "Keine Ergebnisse für die Anfrage", + "@queryNoResults": {}, + "received": "Empfangen", + "@received": {}, + "receiveItem": "Artikel erhalten", + "@receiveItem": {}, + "receivedItem": "Artikel wurde erhalten", + "@receivedItem": {}, + "refresh": "Neu laden", + "@refresh": {}, + "refreshing": "Aktualisiere", + "@refreshing": {}, + "rejected": "Zurückgewiesen", + "@rejected": {}, + "releaseNotes": "Versionshinweise", + "@releaseNotes": {}, + "remove": "Entfernen", + "@remove": { + "description": "remove" + }, + "removeStock": "Bestand entfernen", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Fehler melden", + "@reportBug": {}, + "reportBugDescription": "Fehlerbericht senden (erfordert GitHub Konto)", + "@reportBugDescription": {}, + "results": "Ergebnisse", + "@results": {}, + "request": "Anfrage", + "@request": {}, + "requestingData": "Daten werden angefordert", + "@requestingData": {}, + "required": "Erforderlich", + "@required": { + "description": "This field is required" + }, + "response400": "Ungültige Anfrage", + "@response400": {}, + "response401": "Nicht autorisiert", + "@response401": {}, + "response403": "Zugriff verweigert", + "@response403": {}, + "response404": "Ressource nicht gefunden", + "@response404": {}, + "response405": "Methode nicht erlaubt", + "@response405": {}, + "response429": "Zu viele Anfragen", + "@response429": {}, + "response500": "Interner Serverfehler", + "@response500": {}, + "response501": "Nicht Implementiert", + "@response501": {}, + "response502": "Fehlerhaftes Gateway", + "@response502": {}, + "response503": "Dienst nicht verfügbar", + "@response503": {}, + "response504": "Gateway-Zeitüberschreitung", + "@response504": {}, + "response505": "HTTP-Version wird nicht unterstützt", + "@response505": {}, + "responseData": "Antwort-Daten", + "@responseData": {}, + "responseInvalid": "Ungültiger Antwort-Code", + "@responseInvalid": {}, + "responseUnknown": "Unbekannte Antwort", + "@responseUnknown": {}, + "result": "Ergebnis", + "@result": { + "description": "" + }, + "returned": "Retourniert", + "@returned": {}, + "salesOrders": "Kundenauftrag", + "@salesOrders": {}, + "save": "Speichern", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barcode scannen", + "@scanBarcode": {}, + "scanIntoLocation": "In Lagerorten buchen", + "@scanIntoLocation": {}, + "search": "Suchen", + "@search": { + "description": "search" + }, + "searchLocation": "Lagerort suchen", + "@searchLocation": {}, + "searchParts": "Teile suchen", + "@searchParts": {}, + "searchStock": "Bestand durchsuchen", + "@searchStock": {}, + "select": "Auswählen", + "@select": {}, + "selectFile": "Datei auswählen", + "@selectFile": {}, + "selectImage": "Bild auswählen", + "@selectImage": {}, + "selectLocation": "Wähle einen Lagerort", + "@selectLocation": {}, + "send": "Senden", + "@send": {}, + "serialNumber": "Seriennummer", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradresse", + "@serverAddress": {}, + "serverApiRequired": "Erforderliche API-Version", + "@serverApiRequired": {}, + "serverApiVersion": "API-Version des Servers", + "@serverApiVersion": {}, + "serverAuthenticationError": "Anmeldung fehlgeschlagen", + "@serverAuthenticationError": {}, + "serverCertificateError": "Zertifikatsfehler", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Zertifikat des Servers ist ungültig", + "@serverCertificateInvalid": {}, + "serverConnected": "Verbunden mit Server", + "@serverConnected": {}, + "serverConnecting": "Verbindung zum Server wird aufgebaut", + "@serverConnecting": {}, + "serverCouldNotConnect": "Verbindung zum Server nicht möglich", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server darf nicht leer sein", + "@serverEmpty": {}, + "serverError": "Serverfehler", + "@serverError": {}, + "serverDetails": "Serverdetails", + "@serverDetails": {}, + "serverMissingData": "In der Server-Antwort fehlen erforderliche Felder", + "@serverMissingData": {}, + "serverOld": "Alte Server Version", + "@serverOld": {}, + "serverSettings": "Server Einstellungen", + "@serverSettings": {}, + "serverStart": "Server muss mit http[s] beginnen", + "@serverStart": {}, + "settings": "Einstellungen", + "@settings": {}, + "serverInstance": "Server Instanz", + "@serverInstance": {}, + "serverNotConnected": "Server nicht verbunden", + "@serverNotConnected": {}, + "sounds": "Töne", + "@sounds": {}, + "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Ton bei Serverfehler abspielen", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuscode", + "@statusCode": {}, + "stock": "Bestand", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktuell verfügbare Lagermenge", + "@stockDetails": {}, + "stockItem": "Artikel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Artikel", + "@stockItems": {}, + "stockItemCreate": "Neuen Artikel anlegen", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Neuen Artikel an diesem Lagerort erstellen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Lagerartikel löschen", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Sind Sie sicher, dass Sie diesen Lagerartikel löschen wollen?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Lagerbestand konnte nicht gelöscht werden", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagerbestand gelöscht", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historie des Artikels", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Zeige historische Bestandsverfolgungsdaten", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Artikel umgezogen", + "@stockItemTransferred": {}, + "stockItemUpdated": "Artikel aktualisiert", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Keine Artikel verfügbar", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notizen zum Artikel", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Artikel aktualisiert", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Fehler bei Artikel-Aktualisierung", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerort", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerorte", + "@stockLocations": {}, + "stockTopLevel": "Oberster Lagerort", + "@stockTopLevel": {}, + "strictHttps": "Striktes HTTPS verwenden", + "@strictHttps": {}, + "strictHttpsDetails": "Erzwinge strenge Überprüfung von HTTPs-Zertifikaten", + "@strictHttpsDetails": {}, + "subcategory": "Unterkategorie", + "@subcategory": {}, + "subcategories": "Unterkategorien", + "@subcategories": {}, + "sublocation": "Unter-Lagerort", + "@sublocation": {}, + "sublocations": "Unter-Lagerorte", + "@sublocations": {}, + "sublocationNone": "Keine Unter-Lagerorte", + "@sublocationNone": {}, + "sublocationNoneDetail": "Keine Unter-Lagerorte verfügbar", + "@sublocationNoneDetail": {}, + "submitFeedback": "Feedback geben", + "@submitFeedback": {}, + "suppliedParts": "Gelieferte Teile", + "@suppliedParts": {}, + "supplier": "Lieferant", + "@supplier": {}, + "suppliers": "Lieferanten", + "@suppliers": {}, + "supplierReference": "Lieferanten-Referenz", + "@supplierReference": {}, + "takePicture": "Foto aufnehmen", + "@takePicture": {}, + "targetDate": "Zieldatum", + "@targetDate": {}, + "templatePart": "Übergeordnetes Vorlagenteil", + "@templatePart": {}, + "testName": "Test-Name", + "@testName": {}, + "testPassedOrFailed": "Test erfolgreich oder fehlgeschlagen", + "@testPassedOrFailed": {}, + "testsRequired": "Erforderliche Tests", + "@testsRequired": {}, + "testResults": "Testergebnisse", + "@testResults": { + "description": "" + }, + "testResultAdd": "Testergebnis hinzufügen", + "@testResultAdd": {}, + "testResultNone": "Keine Testergebnisse", + "@testResultNone": {}, + "testResultNoneDetail": "Keine Testergebnisse vorhanden", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fehler beim Hochladen des Testergebnisses", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testergebnis hochgeladen", + "@testResultUploadPass": {}, + "timeout": "Zeitüberschreitung", + "@timeout": { + "description": "" + }, + "tokenError": "Token-Fehler", + "@tokenError": {}, + "tokenMissing": "Token fehlt", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", + "@tokenMissingFromResponse": {}, + "transfer": "Verschieben", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Bestand verschieben", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Übersetzen", + "@translate": {}, + "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", + "@translateHelp": {}, + "units": "Einheiten", + "@units": {}, + "unknownResponse": "Unbekannte Antwort", + "@unknownResponse": {}, + "upload": "Hochladen", + "@upload": {}, + "uploadFailed": "Datei hochladen fehlgeschlagen", + "@uploadFailed": {}, + "uploadSuccess": "Datei hochgeladen", + "@uploadSuccess": {}, + "usedIn": "Verwendet in", + "@usedIn": {}, + "usedInDetails": "Baugruppen, die dieses Teil benötigen", + "@usedInDetails": {}, + "username": "Benutzername", + "@username": {}, + "usernameEmpty": "Der Benutzername darf nicht leer sein", + "@usernameEmpty": {}, + "value": "Wert", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Dieser Wert darf nicht leer sein", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wert erforderlich", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Zulieferer-Teil anzeigen", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/el/app_el.arb b/lib/l10n/el/app_el.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/el/app_el.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/es-419/app_es.arb b/lib/l10n/es-419/app_es.arb new file mode 100644 index 0000000..9dae4a2 --- /dev/null +++ b/lib/l10n/es-419/app_es.arb @@ -0,0 +1,3 @@ +{ + "@@locale": "en" +} \ No newline at end of file diff --git a/lib/l10n/es-ES/app_es.arb b/lib/l10n/es-ES/app_es.arb new file mode 100644 index 0000000..03bfe46 --- /dev/null +++ b/lib/l10n/es-ES/app_es.arb @@ -0,0 +1,635 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Acerca de", + "@about": {}, + "accountDetails": "Detalles de cuenta", + "@accountDetails": {}, + "actions": "Acciones", + "@actions": { + "description": "" + }, + "actionsNone": "No hay acciones disponibles", + "@actionsNone": {}, + "add": "Añadir", + "@add": { + "description": "add" + }, + "addStock": "Añadir stock", + "@addStock": { + "description": "add stock" + }, + "address": "Dirección", + "@address": {}, + "appAbout": "Acerca de InvenTree", + "@appAbout": {}, + "appCredits": "Créditos de aplicación adicionales", + "@appCredits": {}, + "appDetails": "Detalles de la aplicación", + "@appDetails": {}, + "appReleaseNotes": "Mostrar notas de versión de la aplicación", + "@appReleaseNotes": {}, + "appSettings": "Configuración de la aplicación", + "@appSettings": {}, + "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", + "@appSettingsDetails": {}, + "attachments": "Archivos adjuntos", + "@attachments": {}, + "attachImage": "Adjuntar imagen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No se encontraron archivos adjuntos", + "@attachmentNone": {}, + "attachmentNonePartDetail": "No se encontraron archivos adjuntos para esta parte", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Seleccionar archivo adjunto", + "@attachmentSelect": {}, + "attention": "Atención", + "@attention": {}, + "availableStock": "Stock Disponible", + "@availableStock": {}, + "barcodeAssign": "Asignar código de barras", + "@barcodeAssign": {}, + "barcodeAssigned": "Código de barras asignado", + "@barcodeAssigned": {}, + "barcodeError": "Error al escanear código de barras", + "@barcodeError": {}, + "barcodeInUse": "Código de barras ya asignado", + "@barcodeInUse": {}, + "barcodeMissingHash": "Faltan datos de código de barras en la respuesta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No hay coincidencia para código de barras", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Código de barras no asignado", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Escanear para asignar código de barras", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Escanear un código de barras de InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Escanear artículos de stock a la ubicación", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear ubicación de stock", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artículo no escaneado en", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Escanear artículo de stock", + "@barcodeScanItem": {}, + "barcodeTones": "Tonos de código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Desasignar código de barras", + "@barcodeUnassign": {}, + "barcodeUnknown": "El código de barras no reconocido", + "@barcodeUnknown": {}, + "batchCode": "Numero de lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiales", + "@billOfMaterials": {}, + "build": "Construcción", + "@build": {}, + "building": "Construyendo", + "@building": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nueva Categoría", + "@categoryCreate": {}, + "categoryCreateDetail": "Crear nueva categoría de partes", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoría actualizada", + "@categoryUpdated": {}, + "company": "Companía", + "@company": {}, + "companyEdit": "Editar compañía", + "@companyEdit": {}, + "companyNoResults": "No hay compañías que coincidan con la consulta", + "@companyNoResults": {}, + "companyUpdated": "Detalles de la compañía actualizados", + "@companyUpdated": {}, + "companies": "Compañías", + "@companies": {}, + "configureServer": "Configurar ajustes del servidor", + "@configureServer": {}, + "connectionRefused": "Conexión rechazada", + "@connectionRefused": {}, + "count": "Número", + "@count": { + "description": "Count" + }, + "countStock": "Cantidad de stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "customers": "Clientes", + "@customers": {}, + "damaged": "Dañado", + "@damaged": {}, + "delete": "Eliminar", + "@delete": {}, + "deletePart": "Eliminar parte", + "@deletePart": {}, + "deletePartDetail": "Eliminar esta parte de la base de datos", + "@deletePartDetail": {}, + "description": "Descripción", + "@description": {}, + "destroyed": "Destruido", + "@destroyed": {}, + "details": "Detalles", + "@details": { + "description": "details" + }, + "documentation": "Documentación", + "@documentation": {}, + "downloading": "Descargando archivo", + "@downloading": {}, + "downloadError": "Error de descarga", + "@downloadError": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editCategory": "Editar categoría", + "@editCategory": {}, + "editLocation": "Editar ubicación", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editPart": "Editar Parte", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar artículo de stock", + "@editItem": {}, + "enterPassword": "Introducir contraseña", + "@enterPassword": {}, + "enterUsername": "Introducir usuario", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error al crear entrada de base de datos", + "@errorCreate": {}, + "errorDelete": "Error al eliminar la entrada de base de datos", + "@errorDelete": {}, + "errorDetails": "Detalles del error", + "@errorDetails": {}, + "errorFetch": "Error obteniendo datos del servidor", + "@errorFetch": {}, + "errorReporting": "Error al reportar", + "@errorReporting": {}, + "errorReportUpload": "Subir informe de errores", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Subir informes de errores anónimos y registros de errores", + "@errorReportUploadDetails": {}, + "feedback": "Comentarios", + "@feedback": {}, + "feedbackError": "Error al enviar comentarios", + "@feedbackError": {}, + "feedbackSuccess": "Comentarios enviados", + "@feedbackSuccess": {}, + "formatException": "Excepción de formato", + "@formatException": {}, + "formatExceptionJson": "Excepción en formato de datos JSON", + "@formatExceptionJson": {}, + "formError": "Error de formulario", + "@formError": {}, + "history": "Historial", + "@history": { + "description": "history" + }, + "homeScreen": "Pantalla de Inicio", + "@homeScreen": {}, + "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", + "@homeScreenSettings": {}, + "homeShowPo": "Mostrar órdenes de compra", + "@homeShowPo": {}, + "homeShowSubscribed": "Partes Suscritas", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostrar las partes suscritas en la página principal", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Mostrar Proveedores", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Mostrar botón de proveedores en la pantalla de inicio", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Mostrar fabricantes", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Mostrar botón de fabricantes en la pantalla de inicio", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Mostrar clientes", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Mostrar botón de clientes en la pantalla de inicio", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Error al subir la imagen", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Imagen subida", + "@imageUploadSuccess": {}, + "inactive": "Inactivo", + "@inactive": {}, + "inactiveDetail": "Esta parte está marcada como inactiva", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir subcategorías", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar partes de subcategorías en la vista de lista", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incluir sub-localizaciones", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Detalles del perfil incompletos", + "@incompleteDetails": {}, + "internalPartNumber": "Número de parte interno", + "@internalPartNumber": {}, + "info": "Información", + "@info": {}, + "inProduction": "En producción", + "@inProduction": {}, + "inProductionDetail": "El artículo de stock está en producción", + "@inProductionDetail": {}, + "invalidPart": "Parte inválida", + "@invalidPart": {}, + "invalidPartCategory": "Categoría de parte inválida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ubicación inválida", + "@invalidStockLocation": {}, + "invalidStockItem": "Artículo de stock inválido", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nombre de usuario / contraseña no válido", + "@invalidUsernamePassword": {}, + "itemInLocation": "El artículo ya está en la ubicación", + "@itemInLocation": {}, + "keywords": "Palabras claves", + "@keywords": {}, + "lastUpdated": "Última actualización", + "@lastUpdated": {}, + "lineItems": "Elementos de línea", + "@lineItems": {}, + "locationCreate": "Nueva ubicación", + "@locationCreate": {}, + "locationCreateDetail": "Crear nueva ubicación de stock", + "@locationCreateDetail": {}, + "locationNotSet": "No se especificó ninguna ubicación", + "@locationNotSet": {}, + "locationUpdated": "Ubicación de stock actualizada", + "@locationUpdated": {}, + "link": "Vincular", + "@link": {}, + "lost": "Perdido", + "@lost": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "name": "Nombre", + "@name": {}, + "notConnected": "No conectado", + "@notConnected": {}, + "notes": "Notas", + "@notes": { + "description": "Notes" + }, + "noResponse": "Sin respuesta del servidor", + "@noResponse": {}, + "noResults": "Sin resultados", + "@noResults": {}, + "noSubcategories": "No hay subcategorías", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No hay subcategorías disponibles", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Número inválido", + "@numberInvalid": {}, + "onOrder": "En pedido", + "@onOrder": {}, + "onOrderDetails": "Artículos actualmente en pedido", + "@onOrderDetails": {}, + "packaging": "Paquete", + "@packaging": {}, + "packageName": "Nombre de Paquete", + "@packageName": {}, + "parent": "Principal", + "@parent": {}, + "parentCategory": "Categoría superior", + "@parentCategory": {}, + "parentLocation": "Ubicación superior", + "@parentLocation": {}, + "part": "Parte", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nueva Parte", + "@partCreate": {}, + "partCreateDetail": "Crear nueva parte en esta categoría", + "@partCreateDetail": {}, + "partEdited": "Parte actualizada", + "@partEdited": {}, + "parts": "Partes", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Sin Partes", + "@partsNone": {}, + "partNoResults": "No hay partes que coincidan", + "@partNoResults": {}, + "partsStarred": "Parte suscrita", + "@partsStarred": {}, + "partsStarredNone": "No hay partes destacadas disponibles", + "@partsStarredNone": {}, + "partSuppliers": "Proveedores de partes", + "@partSuppliers": {}, + "partCategory": "Categoría de parte", + "@partCategory": {}, + "partCategoryTopLevel": "Categoría de partes de nivel superior", + "@partCategoryTopLevel": {}, + "partCategories": "Categorías de parte", + "@partCategories": {}, + "partDetails": "Detalles de Parte", + "@partDetails": {}, + "partNotes": "Notas de parte", + "@partNotes": {}, + "partStock": "Stock de parte", + "@partStock": { + "description": "part stock" + }, + "password": "Contraseña", + "@password": {}, + "passwordEmpty": "La contraseña no puede estar vacía", + "@passwordEmpty": {}, + "permissionAccountDenied": "Tu usuario no cuenta con los permisos necesarios para realizar esta acción", + "@permissionAccountDenied": {}, + "permissionRequired": "Se requiere autorización", + "@permissionRequired": {}, + "printLabel": "Imprimir etiqueta", + "@printLabel": {}, + "printLabelFailure": "Impresión de etiquetas fallida", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiqueta enviada a la impresora", + "@printLabelSuccess": {}, + "profile": "Perfil", + "@profile": {}, + "profileAdd": "Añadir perfil de servidor", + "@profileAdd": {}, + "profileConnect": "Conectar a Servidor", + "@profileConnect": {}, + "profileEdit": "Editar perfil de servidor", + "@profileEdit": {}, + "profileDelete": "Eliminar perfil del servidor", + "@profileDelete": {}, + "profileName": "Nombre de perfil", + "@profileName": {}, + "profileNone": "No hay perfiles disponibles", + "@profileNone": {}, + "profileNotSelected": "Ningún perfil seleccionado", + "@profileNotSelected": {}, + "profileSelect": "Seleccionar servidor de InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Toca para crear o seleccionar un perfil", + "@profileTapToCreate": {}, + "purchaseOrder": "Orden de compra", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modificar orden de compra", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Ordenes de compra", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Orden de compra actualizada", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Precio de compra", + "@purchasePrice": {}, + "quantity": "Cantidad", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Cantidad está vacía", + "@quantityEmpty": {}, + "quantityInvalid": "La cantidad no es válida", + "@quantityInvalid": {}, + "quantityPositive": "La cantidad debe ser positiva", + "@quantityPositive": {}, + "queryNoResults": "No hay resultados para la consulta", + "@queryNoResults": {}, + "received": "Recibido", + "@received": {}, + "receiveItem": "Recibir artículo", + "@receiveItem": {}, + "receivedItem": "Articulo de stock recibido", + "@receivedItem": {}, + "refresh": "Actualizar", + "@refresh": {}, + "refreshing": "Actualizando", + "@refreshing": {}, + "rejected": "Rechazado", + "@rejected": {}, + "releaseNotes": "Notas informativas", + "@releaseNotes": {}, + "remove": "Eliminar", + "@remove": { + "description": "remove" + }, + "removeStock": "Eliminar Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Reportar un error", + "@reportBug": {}, + "reportBugDescription": "Enviar informe de error (requiere cuenta de GitHub)", + "@reportBugDescription": {}, + "results": "Resultados", + "@results": {}, + "required": "Requerido", + "@required": { + "description": "This field is required" + }, + "response400": "Petición incorrecta", + "@response400": {}, + "response401": "No autorizado (Unauthorized)", + "@response401": {}, + "response403": "Permiso denegado", + "@response403": {}, + "response404": "Recurso no encontrado", + "@response404": {}, + "response405": "Método no permitido", + "@response405": {}, + "response429": "Demasiadas peticiones", + "@response429": {}, + "response500": "Error interno del servidor", + "@response500": {}, + "response501": "No implementado", + "@response501": {}, + "response502": "Puerta de enlace incorrecta (Bad Gateway)", + "@response502": {}, + "response503": "Servicio no disponible", + "@response503": {}, + "response504": "Tiempo de espera de puerta de enlace (Gateway Timeout)", + "@response504": {}, + "response505": "Versión de HTTP no compatible", + "@response505": {}, + "responseData": "Datos de respuesta", + "@responseData": {}, + "responseInvalid": "Código de respuesta inválido", + "@responseInvalid": {}, + "responseUnknown": "Respuesta desconocida", + "@responseUnknown": {}, + "result": "Resultado", + "@result": { + "description": "" + }, + "returned": "Devuelto", + "@returned": {}, + "salesOrders": "Órdenes de venta", + "@salesOrders": {}, + "save": "Guardar", + "@save": { + "description": "Save" + }, + "scanBarcode": "Escanear código de barras", + "@scanBarcode": {}, + "scanIntoLocation": "Escanear a la ubicación", + "@scanIntoLocation": {}, + "search": "Buscar", + "@search": { + "description": "search" + }, + "searchLocation": "Buscar ubicaciones", + "@searchLocation": {}, + "searchParts": "Buscar partes", + "@searchParts": {}, + "searchStock": "Buscar Stock", + "@searchStock": {}, + "select": "Seleccionar", + "@select": {}, + "selectFile": "Seleccionar archivo", + "@selectFile": {}, + "selectImage": "Seleccionar imagen", + "@selectImage": {}, + "selectLocation": "Seleccione una ubicación", + "@selectLocation": {}, + "send": "Enviar", + "@send": {}, + "serialNumber": "Número de serie", + "@serialNumber": {}, + "server": "Servidor", + "@server": {}, + "serverApiRequired": "Versión de API requerida", + "@serverApiRequired": {}, + "serverApiVersion": "Versión de la API del servidor", + "@serverApiVersion": {}, + "serverAuthenticationError": "Error de autenticación", + "@serverAuthenticationError": {}, + "serverCertificateError": "Error de certificado", + "@serverCertificateError": {}, + "serverCertificateInvalid": "El certificado del servidor no es válido", + "@serverCertificateInvalid": {}, + "serverConnected": "Conectado al servidor", + "@serverConnected": {}, + "serverConnecting": "Conectando a servidor", + "@serverConnecting": {}, + "serverCouldNotConnect": "No se pudo conectar al servidor", + "@serverCouldNotConnect": {}, + "serverEmpty": "El servidor no puede estar vacío", + "@serverEmpty": {}, + "serverError": "Error del servidor", + "@serverError": {}, + "serverDetails": "Detalles del Servidor", + "@serverDetails": {}, + "serverMissingData": "Faltan campos requeridos de respuesta del servidor", + "@serverMissingData": {}, + "serverOld": "Versión del servidor anterior", + "@serverOld": {}, + "serverSettings": "Configuración del Servidor", + "@serverSettings": {}, + "serverStart": "El servidor debe comenzar con http[s]", + "@serverStart": {}, + "settings": "Configuración", + "@settings": {}, + "serverInstance": "Instancia del servidor", + "@serverInstance": {}, + "serverNotConnected": "Servidor no conectado", + "@serverNotConnected": {}, + "sounds": "Sonidos", + "@sounds": {}, + "soundOnBarcodeAction": "Reproducir tono audible en la acción de código de barras", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Reproducir tono audible en error del servidor", + "@soundOnServerError": {}, + "status": "Estado", + "@status": {}, + "statusCode": "Código de estado", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Cantidad actual de stock disponible", + "@stockDetails": {}, + "stockItem": "Artículo de stock", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Elementos de Stock", + "@stockItems": {}, + "stockItemCreate": "Nuevo artículo de stock", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Crear nuevo artículo de stock en esta ubicación", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Eliminar elemento de stock", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "¿Está seguro que desea eliminar este elemento de stock?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "No se pudo eliminar el elemento de stock", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Elemento de stock eliminado", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historial de Stock", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Mostrar información de seguimiento de stock histórico", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Artículo de stock transferido", + "@stockItemTransferred": {}, + "stockItemUpdated": "Artículo de stock actualizado", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No hay artículos de stock disponibles", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notas del artículo de stock", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Artículo de stock actualizado", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Error al actualizar el artículo de stock", + "@stockItemUpdateFailure": {}, + "stockLocation": "Ubicaciones de stock", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Ubicaciones de Stock", + "@stockLocations": {}, + "stockTopLevel": "Ubicación de stock superior", + "@stockTopLevel": {}, + "strictHttps": "Usar HTTPS estricto", + "@strictHttps": {}, + "strictHttpsDetails": "Forzar un control estricto de los certificados HTTPs", + "@strictHttpsDetails": {}, + "subcategory": "Subcategoría", + "@subcategory": {}, + "subcategories": "Subcategorías", + "@subcategories": {}, + "sublocation": "Sublocalización", + "@sublocation": {}, + "sublocations": "Sublocalizaciones", + "@sublocations": {}, + "sublocationNone": "Sin sublocalizaciones", + "@sublocationNone": {}, + "sublocationNoneDetail": "No hay sublocalizaciones disponibles", + "@sublocationNoneDetail": {} +} \ No newline at end of file diff --git a/lib/l10n/es-MX/app_es.arb b/lib/l10n/es-MX/app_es.arb new file mode 100644 index 0000000..91793f1 --- /dev/null +++ b/lib/l10n/es-MX/app_es.arb @@ -0,0 +1,17 @@ +{ + "@@locale": "en", + "barcodeScanInItems": "Escanear artículos de stock en su ubicación", + "@barcodeScanInItems": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", + "@includeSublocationsDetail": {}, + "lineItems": "Ítems de línea", + "@lineItems": {}, + "onOrderDetails": "Artículos actualmente en pedido", + "@onOrderDetails": {}, + "stockItems": "Elementos de stock", + "@stockItems": {}, + "stockItemsNotAvailable": "No hay artículos de stock disponibles", + "@stockItemsNotAvailable": {} +} \ No newline at end of file diff --git a/lib/l10n/fa/app_fa.arb b/lib/l10n/fa/app_fa.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/fa/app_fa.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/fr/app_fr.arb b/lib/l10n/fr/app_fr.arb new file mode 100644 index 0000000..f5434c0 --- /dev/null +++ b/lib/l10n/fr/app_fr.arb @@ -0,0 +1,743 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "À propos", + "@about": {}, + "accountDetails": "Détails du compte", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "Aucune action disponible", + "@actionsNone": {}, + "add": "Ajouter", + "@add": { + "description": "add" + }, + "addStock": "Ajouter un stock", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "À propos d'InvenTree", + "@appAbout": {}, + "appCredits": "Crédits d'application supplémentaires", + "@appCredits": {}, + "appDetails": "Détails de l'application", + "@appDetails": {}, + "appReleaseNotes": "Afficher les notes de version de l'application", + "@appReleaseNotes": {}, + "appSettings": "Réglages de l'application", + "@appSettings": {}, + "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", + "@appSettingsDetails": {}, + "attachments": "Pieces jointes", + "@attachments": {}, + "attachImage": "Ajouter une image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Aucune pièce jointe trouvée", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Sélectionner une pièce jointe", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "availableStock": "Stock disponible", + "@availableStock": {}, + "barcodeAssign": "Affecter un code-barres", + "@barcodeAssign": {}, + "barcodeAssigned": "Code-barres affecté", + "@barcodeAssigned": {}, + "barcodeError": "Erreur lors du scan du code-barres", + "@barcodeError": {}, + "barcodeInUse": "Le code-barres est déjà en cours d’utilisation", + "@barcodeInUse": {}, + "barcodeMissingHash": "Les données de hachage du code-barres sont manquantes dans la réponse", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Pas de correspondance pour ce code-barres", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Code-barres non assigné", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scanner pour attribuer un code-barres", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scanner un code-barres InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scannez les items de stock à l'emplacement", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scanner la localisation du stock", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item non scanné dans", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scanner l'article en stock", + "@barcodeScanItem": {}, + "barcodeTones": "Types de code-barre", + "@barcodeTones": {}, + "barcodeUnassign": "Désaffecter le code-barres", + "@barcodeUnassign": {}, + "barcodeUnknown": "Code-barres non reconnu", + "@barcodeUnknown": {}, + "batchCode": "Code de lot", + "@batchCode": {}, + "billOfMaterials": "Liste des matériaux", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Assemblage", + "@build": {}, + "building": "Assemblage en cours", + "@building": {}, + "cancel": "Annuler", + "@cancel": { + "description": "Cancel" + }, + "category": "Catégorie", + "@category": {}, + "categoryCreate": "Nouvelle catégorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Créer une nouvelle catégorie de pièce", + "@categoryCreateDetail": {}, + "categoryUpdated": "Catégorie de pièce mise à jour", + "@categoryUpdated": {}, + "company": "Société", + "@company": {}, + "companyEdit": "Modifier la société", + "@companyEdit": {}, + "companyNoResults": "Aucune société ne correspond à la requête", + "@companyNoResults": {}, + "companyUpdated": "Détails de la société mis à jour", + "@companyUpdated": {}, + "companies": "Sociétés", + "@companies": {}, + "configureServer": "Configurer les paramètres serveur", + "@configureServer": {}, + "connectionRefused": "Connexion refusée", + "@connectionRefused": {}, + "count": "Nombre", + "@count": { + "description": "Count" + }, + "countStock": "Nombre de stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Crédits", + "@credits": {}, + "customers": "Clients", + "@customers": {}, + "damaged": "Endommagé", + "@damaged": {}, + "delete": "Supprimer", + "@delete": {}, + "deletePart": "Supprimer la pièce", + "@deletePart": {}, + "deletePartDetail": "Supprimer cette pièce de la base de données", + "@deletePartDetail": {}, + "description": "Description", + "@description": {}, + "destroyed": "Détruit", + "@destroyed": {}, + "details": "Détails", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Téléchargement du fichier", + "@downloading": {}, + "downloadError": "Erreur lors du téléchargement", + "@downloadError": {}, + "edit": "Modifier", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifier la catégorie", + "@editCategory": {}, + "editLocation": "Modifier l’emplacement", + "@editLocation": {}, + "editNotes": "Modifier les notes", + "@editNotes": {}, + "editPart": "Modifier la pièce", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editer l'article en stock", + "@editItem": {}, + "enterPassword": "Saisissez le mot de passe", + "@enterPassword": {}, + "enterUsername": "Saisissez le nom d'utilisateur", + "@enterUsername": {}, + "error": "Erreur", + "@error": { + "description": "Error" + }, + "errorCreate": "Erreur lors de la création de l'entrée de la base de données", + "@errorCreate": {}, + "errorDelete": "Erreur lors de la suppression de l'entrée de la base de données", + "@errorDelete": {}, + "errorDetails": "Détails de l'erreur", + "@errorDetails": {}, + "errorFetch": "Erreur de récupération des données du serveur", + "@errorFetch": {}, + "errorReporting": "Rapport d'erreur", + "@errorReporting": {}, + "errorReportUpload": "Envoyer le rapport d 'erreur", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", + "@errorReportUploadDetails": {}, + "feedback": "Donner votre avis", + "@feedback": {}, + "feedbackError": "Erreur lors de l'envoi du commentaire", + "@feedbackError": {}, + "feedbackSuccess": "Commentaire envoyé", + "@feedbackSuccess": {}, + "formatException": "Exception de format", + "@formatException": {}, + "formatExceptionJson": "Exception de format de données JSON", + "@formatExceptionJson": {}, + "formError": "Erreur de formulaire", + "@formError": {}, + "history": "Historique", + "@history": { + "description": "history" + }, + "homeScreen": "Ecran d'accueil", + "@homeScreen": {}, + "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", + "@homeScreenSettings": {}, + "homeShowPo": "Afficher les commandes d'achat", + "@homeShowPo": {}, + "homeShowSubscribed": "Pièces suivies", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Afficher les fournisseurs", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Afficher les fabriquants", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Afficher le bouton fabriquant sur l'écran d'accueil", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Afficher les clients", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Afficher le bouton clients sur l'écran d'accueil", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Échec de l'envoi de l'image", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image transférée", + "@imageUploadSuccess": {}, + "inactive": "Inactif", + "@inactive": {}, + "inactiveDetail": "Cette pièce est marquée comme inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Inclure les sous-catégories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Afficher les sous-catégories dans la vue liste", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclure les sous-emplacements", + "@includeSublocations": {}, + "includeSublocationsDetail": "Afficher les sous-emplacements des articles dans la vue liste", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil incomplet", + "@incompleteDetails": {}, + "internalPartNumber": "Numéro de pièce interne", + "@internalPartNumber": {}, + "info": "Information", + "@info": {}, + "inProduction": "En production", + "@inProduction": {}, + "inProductionDetail": "Cet article de stock est en production", + "@inProductionDetail": {}, + "invalidHost": "Nom d’hôte invalide", + "@invalidHost": {}, + "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", + "@invalidHostDetails": {}, + "invalidPart": "Article non valide", + "@invalidPart": {}, + "invalidPartCategory": "Catégorie d'article invalide", + "@invalidPartCategory": {}, + "invalidStockLocation": "Emplacement invalide", + "@invalidStockLocation": {}, + "invalidStockItem": "Article en stock non valide", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", + "@invalidUsernamePassword": {}, + "issueDate": "Date d'émission", + "@issueDate": {}, + "itemInLocation": "Article déjà dans l'emplacement", + "@itemInLocation": {}, + "keywords": "Mots clés", + "@keywords": {}, + "lastStocktake": "Dernier inventaire", + "@lastStocktake": {}, + "lastUpdated": "Dernière mise à jour", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Position", + "@lineItems": {}, + "locationCreate": "Nouvel emplacement", + "@locationCreate": {}, + "locationCreateDetail": "Créer un nouvel emplacement de stock", + "@locationCreateDetail": {}, + "locationNotSet": "Aucun emplacement spécifié", + "@locationNotSet": {}, + "locationUpdated": "Emplacement du stock mis à jour", + "@locationUpdated": {}, + "link": "Lien", + "@link": {}, + "lost": "Perdu", + "@lost": {}, + "manufacturers": "Fabricants", + "@manufacturers": {}, + "missingData": "Données manquantes", + "@missingData": {}, + "name": "Nom", + "@name": {}, + "notConnected": "Non connecté", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "noResponse": "Aucune réponse du serveur", + "@noResponse": {}, + "noResults": "Aucun résultat", + "@noResults": {}, + "noSubcategories": "Pas de sous-catégorie", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nombre invalide", + "@numberInvalid": {}, + "onOrder": "Sur Commande", + "@onOrder": {}, + "onOrderDetails": "Articles en cours de commande", + "@onOrderDetails": {}, + "packaging": "Emballage", + "@packaging": {}, + "packageName": "Nom du package", + "@packageName": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Catégorie parent", + "@parentCategory": {}, + "parentLocation": "Emplacement parent", + "@parentLocation": {}, + "part": "Pièce", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nouvelle pièce", + "@partCreate": {}, + "partCreateDetail": "Créer une nouvelle pièce dans cette catégorie", + "@partCreateDetail": {}, + "partEdited": "Pièce mise à jour", + "@partEdited": {}, + "parts": "Pièces", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Aucune pièces", + "@partsNone": {}, + "partNoResults": "Pas de pièces correspondant à la requête", + "@partNoResults": {}, + "partsStarred": "Pièces suivies", + "@partsStarred": {}, + "partsStarredNone": "Aucune pièce favorite disponible", + "@partsStarredNone": {}, + "partSuppliers": "Fournisseurs de pièces", + "@partSuppliers": {}, + "partCategory": "Catégorie de la pièce", + "@partCategory": {}, + "partCategoryTopLevel": "Catégorie de pièce parente", + "@partCategoryTopLevel": {}, + "partCategories": "Catégories de pièce", + "@partCategories": {}, + "partDetails": "Détails de la pièce", + "@partDetails": {}, + "partNotes": "Notes de la pièce", + "@partNotes": {}, + "partStock": "Stock de la pièce", + "@partStock": { + "description": "part stock" + }, + "password": "Mot de passe", + "@password": {}, + "passwordEmpty": "Le mot de passe peut pas être vide", + "@passwordEmpty": {}, + "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorisation requise", + "@permissionRequired": {}, + "printLabel": "Imprimer l'étiquette", + "@printLabel": {}, + "printLabelFailure": "Echec de l'impression", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiquette envoyée à l'imprimante", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Ajouter un profil serveur", + "@profileAdd": {}, + "profileConnect": "Se connecter au serveur", + "@profileConnect": {}, + "profileEdit": "Editer le profil du serveur", + "@profileEdit": {}, + "profileDelete": "Supprimer le profil du serveur", + "@profileDelete": {}, + "profileName": "Nom du profil", + "@profileName": {}, + "profileNone": "Aucun profil disponible", + "@profileNone": {}, + "profileNotSelected": "Aucun profil sélectionné", + "@profileNotSelected": {}, + "profileSelect": "Sélectionner le serveur InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Commande d’achat", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifier la commande d'achat", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Commandes d'achat", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bon de commande mis à jour", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Prix d'achat", + "@purchasePrice": {}, + "quantity": "Quantité", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "La quantité est vide", + "@quantityEmpty": {}, + "quantityInvalid": "La quantité n'est pas valide", + "@quantityInvalid": {}, + "quantityPositive": "La quantité doit être positive", + "@quantityPositive": {}, + "queryNoResults": "Pas de résultat pour votre requête", + "@queryNoResults": {}, + "received": "Reçu", + "@received": {}, + "receiveItem": "Articles reçus", + "@receiveItem": {}, + "receivedItem": "Article de stock reçu", + "@receivedItem": {}, + "refresh": "Actualiser", + "@refresh": {}, + "refreshing": "Actualisation en cours", + "@refreshing": {}, + "rejected": "Rejeté", + "@rejected": {}, + "releaseNotes": "Notes de Version", + "@releaseNotes": {}, + "remove": "Supprimer", + "@remove": { + "description": "remove" + }, + "removeStock": "Supprimer le stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Signaler un bug", + "@reportBug": {}, + "reportBugDescription": "Envoyer un rapport de bug (nécessite un compte GitHub)", + "@reportBugDescription": {}, + "results": "Résultats", + "@results": {}, + "request": "Requête", + "@request": {}, + "requestingData": "Demande de données", + "@requestingData": {}, + "required": "Requis", + "@required": { + "description": "This field is required" + }, + "response400": "Mauvaise requête", + "@response400": {}, + "response401": "Non autorisé", + "@response401": {}, + "response403": "Autorisation refusée", + "@response403": {}, + "response404": "Ressource non trouvée", + "@response404": {}, + "response405": "Méthode non autorisé", + "@response405": {}, + "response429": "Trop de requêtes", + "@response429": {}, + "response500": "Erreur interne du serveur", + "@response500": {}, + "response501": "Non implémenté", + "@response501": {}, + "response502": "Mauvaise passerelle", + "@response502": {}, + "response503": "Service indisponible", + "@response503": {}, + "response504": "Délai d'attente de la passerelle expiré", + "@response504": {}, + "response505": "Version HTTP non prise en charge", + "@response505": {}, + "responseData": "Données de la réponse", + "@responseData": {}, + "responseInvalid": "Code de réponse invalide", + "@responseInvalid": {}, + "responseUnknown": "Réponse inconnue", + "@responseUnknown": {}, + "result": "Résultat ", + "@result": { + "description": "" + }, + "returned": "Retourné", + "@returned": {}, + "salesOrders": "Ventes", + "@salesOrders": {}, + "save": "Enregistrer", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanner un code-barres", + "@scanBarcode": {}, + "scanIntoLocation": "Scanner vers l'emplacement", + "@scanIntoLocation": {}, + "search": "Rechercher", + "@search": { + "description": "search" + }, + "searchLocation": "Rechercher un emplacement", + "@searchLocation": {}, + "searchParts": "Rechercher de pièces", + "@searchParts": {}, + "searchStock": "Rechercher un stock", + "@searchStock": {}, + "select": "Sélectionner", + "@select": {}, + "selectFile": "Sélectionner un fichier", + "@selectFile": {}, + "selectImage": "Sélectionner une image", + "@selectImage": {}, + "selectLocation": "Sélectionnez un emplacement", + "@selectLocation": {}, + "send": "Envoyer", + "@send": {}, + "serialNumber": "Numéro de série", + "@serialNumber": {}, + "server": "Serveur", + "@server": {}, + "serverAddress": "Adresse du serveur", + "@serverAddress": {}, + "serverApiRequired": "Version de l'API requise", + "@serverApiRequired": {}, + "serverApiVersion": "Version de l'API du serveur", + "@serverApiVersion": {}, + "serverAuthenticationError": "Erreur lors de l'authentification", + "@serverAuthenticationError": {}, + "serverCertificateError": "Erreur de certificat", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Le certificat HTTPS du serveur n'est pas valide", + "@serverCertificateInvalid": {}, + "serverConnected": "Connecté au serveur", + "@serverConnected": {}, + "serverConnecting": "Connexion au serveur", + "@serverConnecting": {}, + "serverCouldNotConnect": "Connexion au serveur impossible", + "@serverCouldNotConnect": {}, + "serverEmpty": "Le serveur ne peut pas être vide", + "@serverEmpty": {}, + "serverError": "Erreur serveur", + "@serverError": {}, + "serverDetails": "Détails du serveur", + "@serverDetails": {}, + "serverMissingData": "La réponse du serveur ne possède pas les champs obligatoires", + "@serverMissingData": {}, + "serverOld": "Ancienne version du serveur", + "@serverOld": {}, + "serverSettings": "Paramètres du serveur", + "@serverSettings": {}, + "serverStart": "Le serveur doit débuter par http[s]", + "@serverStart": {}, + "settings": "Réglages", + "@settings": {}, + "serverInstance": "Instance du serveur", + "@serverInstance": {}, + "serverNotConnected": "Le serveur n'est pas connecté", + "@serverNotConnected": {}, + "sounds": "Sons", + "@sounds": {}, + "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Jouer une tonalité sonore en cas d'erreur du serveur", + "@soundOnServerError": {}, + "status": "État", + "@status": {}, + "statusCode": "Code d'état", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Quantité actuelle de stock disponible", + "@stockDetails": {}, + "stockItem": "Article en stock", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Articles en stock", + "@stockItems": {}, + "stockItemCreate": "Nouvel article en stock", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Créer un nouvel article en stock dans cet emplacement", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Supprimer l'article du stock", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Êtes-vous certain de vouloir supprimer cet article ?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Impossible de supprmer cet article", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Article supprimé", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historique du stock", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Afficher les informations de suivi de stock", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Article en stock transféré", + "@stockItemTransferred": {}, + "stockItemUpdated": "Article en stock mis à jour", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Aucun article en stock", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notes de l'article en stock", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Article en stock mis à jour", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Echec de la mise à jour de l'article en stock", + "@stockItemUpdateFailure": {}, + "stockLocation": "Emplacement du stock", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Emplacements du stock", + "@stockLocations": {}, + "stockTopLevel": "Emplacement de stock de premier niveau", + "@stockTopLevel": {}, + "strictHttps": "Utiliser HTTPS strict", + "@strictHttps": {}, + "strictHttpsDetails": "Obliger une vérification stricte des certificats HTTP", + "@strictHttpsDetails": {}, + "subcategory": "Sous-catégorie", + "@subcategory": {}, + "subcategories": "Sous-catégories", + "@subcategories": {}, + "sublocation": "Sous-emplacement", + "@sublocation": {}, + "sublocations": "Sous-emplacements", + "@sublocations": {}, + "sublocationNone": "Aucun sous-emplacement", + "@sublocationNone": {}, + "sublocationNoneDetail": "Aucun sous-emplacement disponible", + "@sublocationNoneDetail": {}, + "submitFeedback": "Soumettre le commentaire", + "@submitFeedback": {}, + "suppliedParts": "Composants fournis", + "@suppliedParts": {}, + "supplier": "Fournisseur", + "@supplier": {}, + "suppliers": "Fournisseurs", + "@suppliers": {}, + "supplierReference": "Référence du fournisseur", + "@supplierReference": {}, + "takePicture": "Prendre une photo", + "@takePicture": {}, + "targetDate": "Date Cible", + "@targetDate": {}, + "testName": "Nom de test", + "@testName": {}, + "testPassedOrFailed": "Test réussi ou échoué", + "@testPassedOrFailed": {}, + "testsRequired": "Tests requis", + "@testsRequired": {}, + "testResults": "Résultats du test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Ajouter un résultat de test", + "@testResultAdd": {}, + "testResultNone": "Aucun résultat de test", + "@testResultNone": {}, + "testResultNoneDetail": "Aucun résultat de test disponible", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Erreur lors de l'envoi du résultat du test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Résultats du test chargés", + "@testResultUploadPass": {}, + "timeout": "Délai dépassé", + "@timeout": { + "description": "" + }, + "tokenError": "Erreur du jeton", + "@tokenError": {}, + "tokenMissing": "Jeton manquant", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", + "@tokenMissingFromResponse": {}, + "transfer": "Transfert", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transférer le stock", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Traduire", + "@translate": {}, + "translateHelp": "Aidez à traduire l'application InvenTree", + "@translateHelp": {}, + "units": "Unités", + "@units": {}, + "unknownResponse": "Réponse inconnue", + "@unknownResponse": {}, + "upload": "Importer le fichier", + "@upload": {}, + "uploadFailed": "Échec du chargement du fichier", + "@uploadFailed": {}, + "uploadSuccess": "Fichier transféré", + "@uploadSuccess": {}, + "usedIn": "Utilisé dans", + "@usedIn": {}, + "usedInDetails": "Assemblages qui requièrent ce composant", + "@usedInDetails": {}, + "username": "Nom d'utilisateur", + "@username": {}, + "usernameEmpty": "Le nom d'utilisateur peut pas être vide", + "@usernameEmpty": {}, + "value": "Valeur", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "La valeur ne peut pas être vide", + "@valueCannotBeEmpty": {}, + "valueRequired": "La valeur est requise", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Voir la pièce du fournisseur", + "@viewSupplierPart": {}, + "website": "Site web", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/he/app_he.arb b/lib/l10n/he/app_he.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/he/app_he.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/hu/app_hu.arb b/lib/l10n/hu/app_hu.arb new file mode 100644 index 0000000..b4624dc --- /dev/null +++ b/lib/l10n/hu/app_hu.arb @@ -0,0 +1,745 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Névjegy", + "@about": {}, + "accountDetails": "Felhasználó adatok", + "@accountDetails": {}, + "actions": "Műveletek", + "@actions": { + "description": "" + }, + "actionsNone": "Nincsenek műveletek", + "@actionsNone": {}, + "add": "Hozzáadás", + "@add": { + "description": "add" + }, + "addStock": "Készlet növelése", + "@addStock": { + "description": "add stock" + }, + "address": "Cím", + "@address": {}, + "appAbout": "InvenTree névjegy", + "@appAbout": {}, + "appCredits": "További közreműködők", + "@appCredits": {}, + "appDetails": "App részletek", + "@appDetails": {}, + "appReleaseNotes": "Kiadási közlemények", + "@appReleaseNotes": {}, + "appSettings": "Alkalmazásbeállítások", + "@appSettings": {}, + "appSettingsDetails": "Inventree alkalmazás beállításai", + "@appSettingsDetails": {}, + "attachments": "Mellékletek", + "@attachments": {}, + "attachImage": "Kép csatolása", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nem találhatók mellékletek", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Melléklet kiválasztása", + "@attachmentSelect": {}, + "attention": "Figyelem", + "@attention": {}, + "availableStock": "Elérhető készlet", + "@availableStock": {}, + "barcodeAssign": "Vonalkód hozzárendelése", + "@barcodeAssign": {}, + "barcodeAssigned": "Vonalkód hozzárendelve", + "@barcodeAssigned": {}, + "barcodeError": "Vonalkód olvasási hiba", + "@barcodeError": {}, + "barcodeInUse": "Vonalkód már hozzárendelve", + "@barcodeInUse": {}, + "barcodeMissingHash": "Vonalkód hash hiányzik a válaszból", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nincs egyezés vonalkódra", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Készlet bevételezése az adott helyre", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Hely beolvasása", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Készlet tétel beolvasása", + "@barcodeScanItem": {}, + "barcodeTones": "Vonalkód hangszín", + "@barcodeTones": {}, + "barcodeUnassign": "Vonalkód leválasztása", + "@barcodeUnassign": {}, + "barcodeUnknown": "Vonalkód nem ismerhető fel", + "@barcodeUnknown": {}, + "batchCode": "Batch kód", + "@batchCode": {}, + "billOfMaterials": "Alkatrészjegyzék", + "@billOfMaterials": {}, + "bom": "Alkatrészjegyzék", + "@bom": {}, + "build": "Gyártás", + "@build": {}, + "building": "Gyártásban", + "@building": {}, + "cancel": "Mégsem", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategória", + "@category": {}, + "categoryCreate": "Új kategória", + "@categoryCreate": {}, + "categoryCreateDetail": "Alkatrész kategória létrehozása", + "@categoryCreateDetail": {}, + "categoryUpdated": "Alkatrész kategória módosítva", + "@categoryUpdated": {}, + "company": "Cég", + "@company": {}, + "companyEdit": "Cég szerkesztése", + "@companyEdit": {}, + "companyNoResults": "Nincs a lekérdezésnek megfelelő cég", + "@companyNoResults": {}, + "companyUpdated": "Cég adatai frissítve", + "@companyUpdated": {}, + "companies": "Cégek", + "@companies": {}, + "configureServer": "Kiszolgáló beállítások konfigurálása", + "@configureServer": {}, + "connectionRefused": "A kapcsolat visszautasítva", + "@connectionRefused": {}, + "count": "Mennyiség", + "@count": { + "description": "Count" + }, + "countStock": "Leltározás", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Közreműködők", + "@credits": {}, + "customers": "Vevők", + "@customers": {}, + "damaged": "Sérült", + "@damaged": {}, + "delete": "Törlés", + "@delete": {}, + "deletePart": "Alkatrész törlése", + "@deletePart": {}, + "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", + "@deletePartDetail": {}, + "description": "Leírás", + "@description": {}, + "destroyed": "Megsemmisült", + "@destroyed": {}, + "details": "Részletek", + "@details": { + "description": "details" + }, + "documentation": "Dokumentáció", + "@documentation": {}, + "downloading": "Fájl letöltése", + "@downloading": {}, + "downloadError": "Letöltési hiba", + "@downloadError": {}, + "edit": "Szerkesztés", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategória szerkesztése", + "@editCategory": {}, + "editLocation": "Hely szerkesztése", + "@editLocation": {}, + "editNotes": "Megjegyzések szerkesztése", + "@editNotes": {}, + "editPart": "Alkatrész szerkesztése", + "@editPart": { + "description": "edit part" + }, + "editItem": "Készlet tétel szerkesztése", + "@editItem": {}, + "enterPassword": "Jelszó megadása", + "@enterPassword": {}, + "enterUsername": "Felhasználó megadása", + "@enterUsername": {}, + "error": "Hiba", + "@error": { + "description": "Error" + }, + "errorCreate": "Hiba az adatbázis bejegyzés létrehozása közben", + "@errorCreate": {}, + "errorDelete": "Hiba az adatbázis bejegyzés törlése közben", + "@errorDelete": {}, + "errorDetails": "Hiba részletei", + "@errorDetails": {}, + "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", + "@errorFetch": {}, + "errorReporting": "Hibajelentés", + "@errorReporting": {}, + "errorReportUpload": "Hibajelentések feltöltése", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", + "@errorReportUploadDetails": {}, + "feedback": "Visszajelzés", + "@feedback": {}, + "feedbackError": "Visszajelzés küldése sikertelen", + "@feedbackError": {}, + "feedbackSuccess": "Visszajelzés elküldve", + "@feedbackSuccess": {}, + "formatException": "Formátum hiba", + "@formatException": {}, + "formatExceptionJson": "JSON adatformátum hiba", + "@formatExceptionJson": {}, + "formError": "Form hiba", + "@formError": {}, + "history": "Előzmények", + "@history": { + "description": "history" + }, + "homeScreen": "Főképernyő", + "@homeScreen": {}, + "homeScreenSettings": "Főképernyő beállítások konfigurálása", + "@homeScreenSettings": {}, + "homeShowPo": "Beszerzési rendelések megjelenítése", + "@homeShowPo": {}, + "homeShowSubscribed": "Értesítésre beállított alkatrészek", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Beszállítók megjelenítése", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Gyártók megjelenítése", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Gyártók gomb megjelenítése a főoldalon", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Vevők megjelenítése", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Vevők gomb megjelenítése a főoldalon", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Kép feltöltése sikertelen", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Kép feltöltve", + "@imageUploadSuccess": {}, + "inactive": "Inaktív", + "@inactive": {}, + "inactiveDetail": "Ez az alkatrész inaktív lett", + "@inactiveDetail": {}, + "includeSubcategories": "Alkategóriákkal együtt", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Al-kategóriájú alkatrészek megjelenítése a lista nézetben", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alhelyekkel együtt", + "@includeSublocations": {}, + "includeSublocationsDetail": "Al-helyen lévő alkatrészek megjelenítése a lista nézetben", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Nem teljes profil adatok", + "@incompleteDetails": {}, + "internalPartNumber": "Belső alkatrész azonosító", + "@internalPartNumber": {}, + "info": "Infó", + "@info": {}, + "inProduction": "Gyártásban", + "@inProduction": {}, + "inProductionDetail": "Ez a készlet tétel gyártásban van", + "@inProductionDetail": {}, + "invalidHost": "Érvénytelen hostnév", + "@invalidHost": {}, + "invalidHostDetails": "A megadott hostnév nem érvényes", + "@invalidHostDetails": {}, + "invalidPart": "Érvénytelen alkatrész", + "@invalidPart": {}, + "invalidPartCategory": "Érvénytelen kategória", + "@invalidPartCategory": {}, + "invalidStockLocation": "Érvénytelen készlet hely", + "@invalidStockLocation": {}, + "invalidStockItem": "Érvénytelen készlet tétel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", + "@invalidUsernamePassword": {}, + "issueDate": "Kiállítás dátuma", + "@issueDate": {}, + "itemInLocation": "A tétel már a megadott helyen van", + "@itemInLocation": {}, + "keywords": "Kulcsszavak", + "@keywords": {}, + "lastStocktake": "Utolsó leltár", + "@lastStocktake": {}, + "lastUpdated": "Utoljára módosítva", + "@lastUpdated": {}, + "lineItem": "Sortétel", + "@lineItem": {}, + "lineItems": "Sortételek", + "@lineItems": {}, + "locationCreate": "Új hely", + "@locationCreate": {}, + "locationCreateDetail": "Új készlet hely létrehozása", + "@locationCreateDetail": {}, + "locationNotSet": "Nincs megadva hely", + "@locationNotSet": {}, + "locationUpdated": "Készlet hely adatai frissítve", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Elveszett", + "@lost": {}, + "manufacturers": "Gyártók", + "@manufacturers": {}, + "missingData": "Hiányzó adatok", + "@missingData": {}, + "name": "Név", + "@name": {}, + "notConnected": "Nincs kapcsolódva", + "@notConnected": {}, + "notes": "Megjegyzések", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nincs válasz a kiszolgálótól", + "@noResponse": {}, + "noResults": "Nincs találat", + "@noResults": {}, + "noSubcategories": "Nincsenek alkategóriák", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nincsenek alkategóriák", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Érvénytelen szám", + "@numberInvalid": {}, + "onOrder": "Beszállítás alatt", + "@onOrder": {}, + "onOrderDetails": "Alaktrészek beszállítás alatt", + "@onOrderDetails": {}, + "packaging": "Csomagolás", + "@packaging": {}, + "packageName": "Csomag neve", + "@packageName": {}, + "parent": "Szülő", + "@parent": {}, + "parentCategory": "Szülő kategória", + "@parentCategory": {}, + "parentLocation": "Szülő hely", + "@parentLocation": {}, + "part": "Alkatrész", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Új alkatrész", + "@partCreate": {}, + "partCreateDetail": "Alkatrész létrehozása ebben a kategóriában", + "@partCreateDetail": {}, + "partEdited": "Alkatrész frissítve", + "@partEdited": {}, + "parts": "Alkatrészek", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Nincsenek alkatrészek", + "@partsNone": {}, + "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", + "@partNoResults": {}, + "partsStarred": "Értesítésre beállított alkatrészek", + "@partsStarred": {}, + "partsStarredNone": "Nincsenek csillagozott alkatrészek", + "@partsStarredNone": {}, + "partSuppliers": "Alkatrész beszállítók", + "@partSuppliers": {}, + "partCategory": "Alkatrész kategória", + "@partCategory": {}, + "partCategoryTopLevel": "Legfelső szintű alkatrész kategória", + "@partCategoryTopLevel": {}, + "partCategories": "Alkatrész kategóriák", + "@partCategories": {}, + "partDetails": "Alkatrész részletei", + "@partDetails": {}, + "partNotes": "Alkatrész megjegyzések", + "@partNotes": {}, + "partStock": "Alkatrész készlet", + "@partStock": { + "description": "part stock" + }, + "password": "Jelszó", + "@password": {}, + "passwordEmpty": "Jelszó nem lehet üres", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", + "@permissionAccountDenied": {}, + "permissionRequired": "Engedély szükséges", + "@permissionRequired": {}, + "printLabel": "Címke nyomtatása", + "@printLabel": {}, + "printLabelFailure": "Címkenyomtatás sikertelen", + "@printLabelFailure": {}, + "printLabelSuccess": "Címke nyomtatónak elküldve", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Kiszolgáló profil hozzáadása", + "@profileAdd": {}, + "profileConnect": "Kapcsolódás a kiszolgálóhoz", + "@profileConnect": {}, + "profileEdit": "Kiszolgáló profil szerkesztése", + "@profileEdit": {}, + "profileDelete": "Kiszolgáló profil törlése", + "@profileDelete": {}, + "profileName": "Profil neve", + "@profileName": {}, + "profileNone": "Nincsenek profilok", + "@profileNone": {}, + "profileNotSelected": "Nincs kiválasztva profil", + "@profileNotSelected": {}, + "profileSelect": "Válassz InvenTree kiszolgálót", + "@profileSelect": {}, + "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", + "@profileTapToCreate": {}, + "purchaseOrder": "Beszerzési rendelés", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Beszerzési rendelések", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Beszerzési rendelés frissítve", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Beszerzési ár", + "@purchasePrice": {}, + "quantity": "Mennyiség", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Mennyiség üres", + "@quantityEmpty": {}, + "quantityInvalid": "Mennyiség érvénytelen", + "@quantityInvalid": {}, + "quantityPositive": "Mennyiség pozitív kell legyen", + "@quantityPositive": {}, + "queryNoResults": "Nincs találat", + "@queryNoResults": {}, + "received": "Beérkezett", + "@received": {}, + "receiveItem": "Bevételezés", + "@receiveItem": {}, + "receivedItem": "Beérkezett készlet", + "@receivedItem": {}, + "refresh": "Frissítés", + "@refresh": {}, + "refreshing": "Frissítés...", + "@refreshing": {}, + "rejected": "Elutasított", + "@rejected": {}, + "releaseNotes": "Kiadási közlemények", + "@releaseNotes": {}, + "remove": "Törlés", + "@remove": { + "description": "remove" + }, + "removeStock": "Készlet csökkentése", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hibabejelentés", + "@reportBug": {}, + "reportBugDescription": "Hibabejelentés küldése (GitHub fiók szükséges)", + "@reportBugDescription": {}, + "results": "Eredmények", + "@results": {}, + "request": "Kérés", + "@request": {}, + "requestingData": "Adatok lekérése", + "@requestingData": {}, + "required": "Kötelező", + "@required": { + "description": "This field is required" + }, + "response400": "Rossz kérés", + "@response400": {}, + "response401": "Jogosulatlan", + "@response401": {}, + "response403": "Hozzáférés megtagadva", + "@response403": {}, + "response404": "Erőforrás nem található", + "@response404": {}, + "response405": "Metódus nincs engedélyezve", + "@response405": {}, + "response429": "Túl sok kérés", + "@response429": {}, + "response500": "Belső kiszolgáló hiba", + "@response500": {}, + "response501": "Nincs implementálva", + "@response501": {}, + "response502": "Rossz átjáró", + "@response502": {}, + "response503": "A szolgáltatás nem érhető el", + "@response503": {}, + "response504": "Átjáró időtúllépés", + "@response504": {}, + "response505": "HTTP verzió nem támogatott", + "@response505": {}, + "responseData": "Válasz adatok", + "@responseData": {}, + "responseInvalid": "Érvénytelen válasz kód", + "@responseInvalid": {}, + "responseUnknown": "Ismeretlen válasz", + "@responseUnknown": {}, + "result": "Eredmény", + "@result": { + "description": "" + }, + "returned": "Visszaküldve", + "@returned": {}, + "salesOrders": "Vevői rendelések", + "@salesOrders": {}, + "save": "Mentés", + "@save": { + "description": "Save" + }, + "scanBarcode": "Vonalkód beolvasása", + "@scanBarcode": {}, + "scanIntoLocation": "Beolvasás helyre", + "@scanIntoLocation": {}, + "search": "Keresés", + "@search": { + "description": "search" + }, + "searchLocation": "Hely keresése", + "@searchLocation": {}, + "searchParts": "Alkatrészek keresése", + "@searchParts": {}, + "searchStock": "Készlet keresése", + "@searchStock": {}, + "select": "Kiválaszt", + "@select": {}, + "selectFile": "Fájl kiválasztása", + "@selectFile": {}, + "selectImage": "Válassz képet", + "@selectImage": {}, + "selectLocation": "Válassz helyet", + "@selectLocation": {}, + "send": "Küldés", + "@send": {}, + "serialNumber": "Sorozatszám", + "@serialNumber": {}, + "server": "Kiszolgáló", + "@server": {}, + "serverAddress": "Kiszolgáló címe", + "@serverAddress": {}, + "serverApiRequired": "Szükséges API verzió", + "@serverApiRequired": {}, + "serverApiVersion": "Szerver API verzió", + "@serverApiVersion": {}, + "serverAuthenticationError": "Hitelesítési hiba", + "@serverAuthenticationError": {}, + "serverCertificateError": "Tanúsítvány hiba", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Érvénytelen kiszolgáló HTTPS tanúsítvány", + "@serverCertificateInvalid": {}, + "serverConnected": "Kapcsolódva a kiszolgálóhoz", + "@serverConnected": {}, + "serverConnecting": "Kapcsolódás a kiszolgálóhoz", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nem sikerült kapcsolódni a kiszolgálóhoz", + "@serverCouldNotConnect": {}, + "serverEmpty": "A kiszolgálónév nem lehet üres", + "@serverEmpty": {}, + "serverError": "Kiszolgálóhiba", + "@serverError": {}, + "serverDetails": "Kiszolgáló részletei", + "@serverDetails": {}, + "serverMissingData": "A kiszolgáló válaszából szükséges mezők hiányoznak", + "@serverMissingData": {}, + "serverOld": "Régi kiszolgáló verzió", + "@serverOld": {}, + "serverSettings": "Kiszolgáló beállítások", + "@serverSettings": {}, + "serverStart": "A kiszolgálónak http(s) kezdetűnek kell lennie", + "@serverStart": {}, + "settings": "Beállítások", + "@settings": {}, + "serverInstance": "Kiszolgáló példány", + "@serverInstance": {}, + "serverNotConnected": "Kiszolgáló nem csatlakozik", + "@serverNotConnected": {}, + "sounds": "Hangok", + "@sounds": {}, + "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", + "@soundOnServerError": {}, + "status": "Állapot", + "@status": {}, + "statusCode": "Állapot kód", + "@statusCode": {}, + "stock": "Készlet", + "@stock": { + "description": "stock" + }, + "stockDetails": "Jelenleg elérhető készlet mennyiség", + "@stockDetails": {}, + "stockItem": "Készlet tétel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Készlet tételek", + "@stockItems": {}, + "stockItemCreate": "Új készlet tétel", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Új készlet tétel létrehozása ezen a helyen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Készlet tétel törlése", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Biztosan törölni szeretnéd ezt a készlet tételt?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Készlet tétel nem törölhető", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Készlet tétel törölve", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Készlettörténet", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Készlettörténet megjelenítése", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Készlet áthelyezve", + "@stockItemTransferred": {}, + "stockItemUpdated": "Készlet tétel feltöltve", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nincs elérhető készlet", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Készlet tétel megjegyzések", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Készlet tétel feltöltve", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Készlet tétel módosítása sikertelen", + "@stockItemUpdateFailure": {}, + "stockLocation": "Készlet hely", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Készlethelyek", + "@stockLocations": {}, + "stockTopLevel": "Legfelső szintű készlet hely", + "@stockTopLevel": {}, + "strictHttps": "Kizárólag HTTPS használata", + "@strictHttps": {}, + "strictHttpsDetails": "HTTPS tanúsítványok szigorú ellenőrzése", + "@strictHttpsDetails": {}, + "subcategory": "Alkategória", + "@subcategory": {}, + "subcategories": "Alkategóriák", + "@subcategories": {}, + "sublocation": "Alhely", + "@sublocation": {}, + "sublocations": "Alhelyek", + "@sublocations": {}, + "sublocationNone": "Nincsenek alhelyek", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nincsenek elérhető alhelyek", + "@sublocationNoneDetail": {}, + "submitFeedback": "Visszajelzés Küldése", + "@submitFeedback": {}, + "suppliedParts": "Szállított alkatrészek", + "@suppliedParts": {}, + "supplier": "Beszállító", + "@supplier": {}, + "suppliers": "Beszállítók", + "@suppliers": {}, + "supplierReference": "Beszállítói azonosító", + "@supplierReference": {}, + "takePicture": "Fotó készítése", + "@takePicture": {}, + "targetDate": "Cél dátum", + "@targetDate": {}, + "templatePart": "Szülő sablon alkatrész", + "@templatePart": {}, + "testName": "Teszt neve", + "@testName": {}, + "testPassedOrFailed": "Teszt sikeres vagy sikertelen", + "@testPassedOrFailed": {}, + "testsRequired": "Szükséges tesztek", + "@testsRequired": {}, + "testResults": "Teszt eredmények", + "@testResults": { + "description": "" + }, + "testResultAdd": "Teszt eredmény hozzáadása", + "@testResultAdd": {}, + "testResultNone": "Nincsenek teszt eredmények", + "@testResultNone": {}, + "testResultNoneDetail": "Teszt eredmény nem áll rendelkezésre", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hiba a teszt eredmény feltöltése közben", + "@testResultUploadFail": {}, + "testResultUploadPass": "Teszt eredmény feltöltve", + "@testResultUploadPass": {}, + "timeout": "Időtúllépés", + "@timeout": { + "description": "" + }, + "tokenError": "Token hiba", + "@tokenError": {}, + "tokenMissing": "Hiányzó token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", + "@tokenMissingFromResponse": {}, + "transfer": "Áthelyezés", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Készlet áthelyezése", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Fordítás", + "@translate": {}, + "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", + "@translateHelp": {}, + "units": "Mértékegységek", + "@units": {}, + "unknownResponse": "Ismeretlen válasz", + "@unknownResponse": {}, + "upload": "Feltöltés", + "@upload": {}, + "uploadFailed": "Fájl feltöltése sikertelen", + "@uploadFailed": {}, + "uploadSuccess": "Fájl feltöltve", + "@uploadSuccess": {}, + "usedIn": "Felhasználva ebben", + "@usedIn": {}, + "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", + "@usedInDetails": {}, + "username": "Felhasználónév", + "@username": {}, + "usernameEmpty": "Felhasználónév nem lehet üres", + "@usernameEmpty": {}, + "value": "Érték", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Az érték nem lehet üres", + "@valueCannotBeEmpty": {}, + "valueRequired": "Érték megadása szükséges", + "@valueRequired": {}, + "version": "Verzió", + "@version": {}, + "viewSupplierPart": "Beszállítói alkatrész megtekintése", + "@viewSupplierPart": {}, + "website": "Weboldal", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/id/app_id.arb b/lib/l10n/id/app_id.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/id/app_id.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/it/app_it.arb b/lib/l10n/it/app_it.arb new file mode 100644 index 0000000..b5f5571 --- /dev/null +++ b/lib/l10n/it/app_it.arb @@ -0,0 +1,505 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Info", + "@about": {}, + "accountDetails": "Dettagli account", + "@accountDetails": {}, + "actions": "Azioni", + "@actions": { + "description": "" + }, + "actionsNone": "Nessuna azione disponibile", + "@actionsNone": {}, + "add": "Aggiungi", + "@add": { + "description": "add" + }, + "address": "Indirizzo", + "@address": {}, + "appAbout": "Info su InvenTree", + "@appAbout": {}, + "appCredits": "Riconoscimenti addizionali", + "@appCredits": {}, + "appDetails": "Dettagli App", + "@appDetails": {}, + "appReleaseNotes": "Mostra le note di rilascio dell'app", + "@appReleaseNotes": {}, + "appSettings": "Impostazioni App", + "@appSettings": {}, + "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", + "@appSettingsDetails": {}, + "attachments": "Allegati", + "@attachments": {}, + "attachImage": "Allega Immagine", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nessun allegato trovato", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Seleziona allegato", + "@attachmentSelect": {}, + "attention": "Attenzione", + "@attention": {}, + "barcodeAssign": "Assegna Codice A Barre", + "@barcodeAssign": {}, + "barcodeAssigned": "Codice a barre assegnato", + "@barcodeAssigned": {}, + "barcodeError": "Errore scansione codice a barre", + "@barcodeError": {}, + "barcodeInUse": "Codice a barre già in uso", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dati hash codice a barre mancanti dalla risposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nessuna corrispondenza per il codice a barre", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Codice a barre non assegnato", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scansiona per assegnare codice a barre", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeTones": "Toni Codice a Barre", + "@barcodeTones": {}, + "barcodeUnassign": "Deseleziona Il Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Codice a barre non leggibile", + "@barcodeUnknown": {}, + "batchCode": "Codice Lotto", + "@batchCode": {}, + "billOfMaterials": "Distinta materiali", + "@billOfMaterials": {}, + "bom": "Distinta materiali", + "@bom": {}, + "build": "Crea", + "@build": {}, + "cancel": "Annulla", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nuova categoria", + "@categoryCreate": {}, + "company": "Azienda", + "@company": {}, + "companyEdit": "Modifica azienda", + "@companyEdit": {}, + "companyNoResults": "Nessuna azienda corrispondente alla query", + "@companyNoResults": {}, + "companies": "Aziende", + "@companies": {}, + "connectionRefused": "Connessione rifiutata", + "@connectionRefused": {}, + "count": "Quantità", + "@count": { + "description": "Count" + }, + "credits": "Riconoscimenti", + "@credits": {}, + "customers": "Clienti", + "@customers": {}, + "damaged": "Danneggiato", + "@damaged": {}, + "delete": "Cancella", + "@delete": {}, + "description": "Descrizione", + "@description": {}, + "destroyed": "Distrutto", + "@destroyed": {}, + "details": "Dettagli", + "@details": { + "description": "details" + }, + "documentation": "Documentazione", + "@documentation": {}, + "downloading": "File in download", + "@downloading": {}, + "downloadError": "Errore download", + "@downloadError": {}, + "edit": "Modifica", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifica Categoria", + "@editCategory": {}, + "enterPassword": "Inserire la password", + "@enterPassword": {}, + "enterUsername": "Inserisci nome utente", + "@enterUsername": {}, + "error": "Errore", + "@error": { + "description": "Error" + }, + "errorCreate": "Errore nella creazione della voce del database", + "@errorCreate": {}, + "errorDetails": "Dettagli errore", + "@errorDetails": {}, + "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", + "@errorFetch": {}, + "feedback": "Commenti e suggerimenti", + "@feedback": {}, + "feedbackError": "Errore nell'invio del feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback inviato", + "@feedbackSuccess": {}, + "formatException": "Eccezione Formato", + "@formatException": {}, + "formatExceptionJson": "Eccezione formato dati JSON", + "@formatExceptionJson": {}, + "formError": "Errore Modulo", + "@formError": {}, + "history": "Cronologia", + "@history": { + "description": "history" + }, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Il caricamento della foto è fallito", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Immagine caricata", + "@imageUploadSuccess": {}, + "inactive": "Inattivo", + "@inactive": {}, + "includeSubcategories": "Includi sottocategorie", + "@includeSubcategories": {}, + "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", + "@incompleteDetails": {}, + "info": "Info", + "@info": {}, + "invalidHost": "Nome host non valido", + "@invalidHost": {}, + "invalidHostDetails": "Il nome host fornito non è valido", + "@invalidHostDetails": {}, + "invalidUsernamePassword": "Combinazione nome utente e password non valida", + "@invalidUsernamePassword": {}, + "issueDate": "Data di emissione", + "@issueDate": {}, + "itemInLocation": "Elemento già in posizione", + "@itemInLocation": {}, + "keywords": "Parole Chiave", + "@keywords": {}, + "lastUpdated": "Ultimo aggiornamento", + "@lastUpdated": {}, + "lost": "Perso", + "@lost": {}, + "manufacturers": "Produttori", + "@manufacturers": {}, + "missingData": "Dati mancanti", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "notConnected": "Non connesso", + "@notConnected": {}, + "notes": "Note", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nessuna risposta dal server", + "@noResponse": {}, + "noResults": "Nessun risultato", + "@noResults": {}, + "noSubcategories": "Nessuna sotto categoria", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Numero non valido", + "@numberInvalid": {}, + "onOrderDetails": "Articoli attualmente in ordine", + "@onOrderDetails": {}, + "packaging": "Confezionamento", + "@packaging": {}, + "packageName": "Nome pacchetto", + "@packageName": {}, + "parent": "Superiore", + "@parent": {}, + "parentCategory": "Categoria Superiore", + "@parentCategory": {}, + "parts": "Articoli", + "@parts": { + "description": "Part (multiple)" + }, + "partSuppliers": "Fornitori articoli", + "@partSuppliers": {}, + "password": "Password", + "@password": {}, + "passwordEmpty": "La password non può essere vuota", + "@passwordEmpty": {}, + "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorizzazione necessaria", + "@permissionRequired": {}, + "profile": "Profilo", + "@profile": {}, + "profileAdd": "Aggiungi Profilo Server", + "@profileAdd": {}, + "profileConnect": "Connetti al Server", + "@profileConnect": {}, + "profileEdit": "Modifica il profilo del Server", + "@profileEdit": {}, + "profileDelete": "Elimina Profilo Del Server", + "@profileDelete": {}, + "profileName": "Nome Profilo", + "@profileName": {}, + "profileNone": "Nessun profilo disponibile", + "@profileNone": {}, + "profileNotSelected": "Nessun profilo selezionato", + "@profileNotSelected": {}, + "profileSelect": "Seleziona Server InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Tocca per creare o selezionare un profilo", + "@profileTapToCreate": {}, + "purchaseOrder": "Ordine d'acquisto", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifica ordine d'acquisto", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Ordini d'acquisto", + "@purchaseOrders": {}, + "purchasePrice": "Prezzo d'acquisto", + "@purchasePrice": {}, + "quantity": "Quantità", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Quantità vuota", + "@quantityEmpty": {}, + "quantityInvalid": "La quantità non è valida", + "@quantityInvalid": {}, + "quantityPositive": "La quantità deve essere positiva", + "@quantityPositive": {}, + "queryNoResults": "Nessun risultato per la tua ricerca", + "@queryNoResults": {}, + "received": "Ricevuto", + "@received": {}, + "receiveItem": "Ricevi Articolo", + "@receiveItem": {}, + "refresh": "Aggiorna", + "@refresh": {}, + "refreshing": "In aggiornamento", + "@refreshing": {}, + "rejected": "Respinto", + "@rejected": {}, + "releaseNotes": "Note di Rilascio", + "@releaseNotes": {}, + "remove": "Rimuovi", + "@remove": { + "description": "remove" + }, + "reportBug": "Segnala un bug", + "@reportBug": {}, + "results": "Risultati", + "@results": {}, + "request": "Richiesta", + "@request": {}, + "requestingData": "Dati in richiesta", + "@requestingData": {}, + "required": "Richiesto", + "@required": { + "description": "This field is required" + }, + "response400": "Richiesta non valida", + "@response400": {}, + "response401": "Non Autorizzato", + "@response401": {}, + "response403": "Permesso negato", + "@response403": {}, + "response404": "Risorsa non trovata", + "@response404": {}, + "response405": "Metodo non consentito", + "@response405": {}, + "response429": "Troppe richieste", + "@response429": {}, + "response500": "Errore Interno del Server", + "@response500": {}, + "response501": "Non implementato", + "@response501": {}, + "response502": "Gateway Errato", + "@response502": {}, + "response503": "Servizio Non Disponibile", + "@response503": {}, + "response504": "Timeout del gateway", + "@response504": {}, + "response505": "Versione HTTP non supportata", + "@response505": {}, + "responseData": "Dati risposta", + "@responseData": {}, + "responseInvalid": "Codice Risposta Non Valido", + "@responseInvalid": {}, + "responseUnknown": "Risposta Sconosciuta", + "@responseUnknown": {}, + "result": "Risultato", + "@result": { + "description": "" + }, + "returned": "Restituito", + "@returned": {}, + "salesOrders": "Ordini di vendita", + "@salesOrders": {}, + "save": "Salva", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scansiona codice a barre", + "@scanBarcode": {}, + "search": "Cerca", + "@search": { + "description": "search" + }, + "select": "Seleziona", + "@select": {}, + "selectFile": "Seleziona file", + "@selectFile": {}, + "selectImage": "Seleziona un'immagine", + "@selectImage": {}, + "send": "Invia", + "@send": {}, + "serialNumber": "Numero seriale", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Indirizzo del server", + "@serverAddress": {}, + "serverApiRequired": "Versione API Richiesta", + "@serverApiRequired": {}, + "serverApiVersion": "Versione API Server", + "@serverApiVersion": {}, + "serverAuthenticationError": "Errore di autenticazione", + "@serverAuthenticationError": {}, + "serverCertificateError": "Errore certificato", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Il certificato del server non è valido", + "@serverCertificateInvalid": {}, + "serverConnected": "Connesso al Server", + "@serverConnected": {}, + "serverConnecting": "Connessione al server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Impossibile connettersi al server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Nome server non può essere vuoto", + "@serverEmpty": {}, + "serverError": "Errore del server", + "@serverError": {}, + "serverDetails": "Dettagli del server", + "@serverDetails": {}, + "serverMissingData": "Dati mancanti nella risposta del server", + "@serverMissingData": {}, + "serverOld": "Versione Vecchia Del Server", + "@serverOld": {}, + "serverSettings": "Impostazioni Server", + "@serverSettings": {}, + "serverStart": "Il server deve iniziare con http[s]", + "@serverStart": {}, + "settings": "Impostazioni", + "@settings": {}, + "serverInstance": "Istanza Del Server", + "@serverInstance": {}, + "serverNotConnected": "Server non connesso", + "@serverNotConnected": {}, + "sounds": "Audio", + "@sounds": {}, + "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Riproduci il tono sonoro su un errore del server", + "@soundOnServerError": {}, + "status": "Stato", + "@status": {}, + "statusCode": "Codice di stato", + "@statusCode": {}, + "stock": "Magazzino", + "@stock": { + "description": "stock" + }, + "subcategory": "Sottocategoria", + "@subcategory": {}, + "subcategories": "Sottocategorie", + "@subcategories": {}, + "submitFeedback": "Invia feedback", + "@submitFeedback": {}, + "supplier": "Fornitore", + "@supplier": {}, + "suppliers": "Fornitori", + "@suppliers": {}, + "supplierReference": "Riferimento fornitore", + "@supplierReference": {}, + "takePicture": "Scatta Foto", + "@takePicture": {}, + "testName": "Nome del test", + "@testName": {}, + "testPassedOrFailed": "Test superato o fallito", + "@testPassedOrFailed": {}, + "testsRequired": "Test Richiesti", + "@testsRequired": {}, + "testResults": "Risultati del test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Aggiungi Risultato Test", + "@testResultAdd": {}, + "testResultNone": "Nessun Risultato Del Test", + "@testResultNone": {}, + "testResultNoneDetail": "Nessun risultato del test disponibile", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Errore nel caricamento del risultato del test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Risultato del test caricato", + "@testResultUploadPass": {}, + "timeout": "Tempo Scaduto", + "@timeout": { + "description": "" + }, + "tokenError": "Errore Token", + "@tokenError": {}, + "tokenMissing": "Token Mancante", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", + "@tokenMissingFromResponse": {}, + "transfer": "Trasferisci", + "@transfer": { + "description": "transfer" + }, + "translate": "Traduci", + "@translate": {}, + "translateHelp": "Aiuta a tradurre l'app InvenTree", + "@translateHelp": {}, + "units": "Unità", + "@units": {}, + "unknownResponse": "Risposta Sconosciuta", + "@unknownResponse": {}, + "upload": "Carica", + "@upload": {}, + "uploadFailed": "Caricamento di file non riuscito", + "@uploadFailed": {}, + "uploadSuccess": "File caricato", + "@uploadSuccess": {}, + "usedIn": "Viene utilizzato in", + "@usedIn": {}, + "username": "Nome utente", + "@username": {}, + "usernameEmpty": "Il nome utente non può essere vuoto", + "@usernameEmpty": {}, + "value": "Valore", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Il valore non può essere vuoto", + "@valueCannotBeEmpty": {}, + "valueRequired": "È richiesto un valore", + "@valueRequired": {}, + "version": "Versione", + "@version": {}, + "viewSupplierPart": "Visualizza Fornitore", + "@viewSupplierPart": {}, + "website": "Sito Web", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/ja/app_ja.arb b/lib/l10n/ja/app_ja.arb new file mode 100644 index 0000000..36bf7fc --- /dev/null +++ b/lib/l10n/ja/app_ja.arb @@ -0,0 +1,682 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "概要", + "@about": {}, + "accountDetails": "アカウントの詳細", + "@accountDetails": {}, + "actions": "アクション", + "@actions": { + "description": "" + }, + "actionsNone": "利用可能なアクションはありません", + "@actionsNone": {}, + "add": "追加", + "@add": { + "description": "add" + }, + "addStock": "在庫を追加", + "@addStock": { + "description": "add stock" + }, + "address": "アドレス", + "@address": {}, + "appAbout": "InvenTree について", + "@appAbout": {}, + "appCredits": "すぺしゃる★さんくす!", + "@appCredits": {}, + "appDetails": "アプリ詳細", + "@appDetails": {}, + "appReleaseNotes": "アプリのリリースノートを表示", + "@appReleaseNotes": {}, + "appSettings": "アプリ設定", + "@appSettings": {}, + "appSettingsDetails": "アプリ設定を構成します", + "@appSettingsDetails": {}, + "attachments": "添付ファイル", + "@attachments": {}, + "attachImage": "画像を添付", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "添付ファイルが見つかりません。", + "@attachmentNone": {}, + "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "添付ファイルを選択", + "@attachmentSelect": {}, + "attention": "注意", + "@attention": {}, + "availableStock": "在庫あり", + "@availableStock": {}, + "barcodeAssign": "バーコードを割り当てる", + "@barcodeAssign": {}, + "barcodeAssigned": "バーコードが割り当てられました", + "@barcodeAssigned": {}, + "barcodeError": "バーコードのスキャンエラー", + "@barcodeError": {}, + "barcodeInUse": "バーコードは既に割り当てられています", + "@barcodeInUse": {}, + "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "バーコードが一致しません", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "バーコードが割り当てられていません", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "スキャンしてバーコードを割り当てます", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "InvenTree バーコードをスキャンする", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "在庫アイテムを在庫場所にスキャン", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "在庫場所をスキャン", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "在庫アイテムをスキャン", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "バーコードの割り当てを解除", + "@barcodeUnassign": {}, + "barcodeUnknown": "バーコードが認識されません", + "@barcodeUnknown": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "ビルド", + "@build": {}, + "building": "ビルド", + "@building": {}, + "cancel": "キャンセル", + "@cancel": { + "description": "Cancel" + }, + "category": "カテゴリ", + "@category": {}, + "categoryCreate": "新規カテゴリ", + "@categoryCreate": {}, + "categoryCreateDetail": "新しい部品カテゴリを作成", + "@categoryCreateDetail": {}, + "categoryUpdated": "部品カテゴリを更新しました", + "@categoryUpdated": {}, + "company": "会社", + "@company": {}, + "companyEdit": "会社を編集", + "@companyEdit": {}, + "companyNoResults": "検索条件に一致する会社はありません", + "@companyNoResults": {}, + "companyUpdated": "会社の詳細を更新しました", + "@companyUpdated": {}, + "companies": "会社", + "@companies": {}, + "configureServer": "サーバー設定", + "@configureServer": {}, + "connectionRefused": "接続を拒否しました", + "@connectionRefused": {}, + "count": "カウント", + "@count": { + "description": "Count" + }, + "countStock": "在庫数", + "@countStock": { + "description": "Count Stock" + }, + "credits": "謝辞", + "@credits": {}, + "customers": "顧客", + "@customers": {}, + "damaged": "破損", + "@damaged": {}, + "delete": "削除", + "@delete": {}, + "deletePart": "部品を削除", + "@deletePart": {}, + "deletePartDetail": "データベースからこの部品を削除します", + "@deletePartDetail": {}, + "description": "説明", + "@description": {}, + "destroyed": "破壊", + "@destroyed": {}, + "details": "詳細", + "@details": { + "description": "details" + }, + "documentation": "ドキュメント", + "@documentation": {}, + "downloading": "ファイルをダウンロード中", + "@downloading": {}, + "downloadError": "ダウンロードエラー", + "@downloadError": {}, + "edit": "編集", + "@edit": { + "description": "edit" + }, + "editCategory": "カテゴリの編集", + "@editCategory": {}, + "editLocation": "在庫場所を編集", + "@editLocation": {}, + "editNotes": "メモを編集", + "@editNotes": {}, + "editPart": "パートの編集", + "@editPart": { + "description": "edit part" + }, + "editItem": "在庫商品を編集", + "@editItem": {}, + "enterPassword": "パスワードを入力してください", + "@enterPassword": {}, + "enterUsername": "ユーザー名を入力してください", + "@enterUsername": {}, + "error": "エラー", + "@error": { + "description": "Error" + }, + "errorCreate": "データベースの作成中にエラーが発生しました", + "@errorCreate": {}, + "errorDelete": "データベースの削除中にエラーが発生しました", + "@errorDelete": {}, + "errorDetails": "エラーの詳細", + "@errorDetails": {}, + "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", + "@errorFetch": {}, + "errorReporting": "エラー報告", + "@errorReporting": {}, + "errorReportUpload": "エラー報告をアップロード", + "@errorReportUpload": {}, + "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", + "@errorReportUploadDetails": {}, + "feedback": "フィードバック", + "@feedback": {}, + "feedbackError": "フィードバックの送信エラー", + "@feedbackError": {}, + "feedbackSuccess": "フィードバックが送信されました", + "@feedbackSuccess": {}, + "formatException": "フォーマットの例外エラー", + "@formatException": {}, + "formatExceptionJson": "JSONデータフォーマット例外エラー", + "@formatExceptionJson": {}, + "formError": "フォームエラー", + "@formError": {}, + "history": "履歴", + "@history": { + "description": "history" + }, + "homeScreen": "ホーム画面", + "@homeScreen": {}, + "homeScreenSettings": "ホーム画面の設定", + "@homeScreenSettings": {}, + "homeShowPo": "注文書を表示", + "@homeShowPo": {}, + "homeShowSubscribed": "購読済みのパーツ", + "@homeShowSubscribed": {}, + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "仕入先を表示", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "メーカーを表示", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "顧客を表示", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "画像のアップロードに失敗しました", + "@imageUploadFailure": {}, + "imageUploadSuccess": "アップロードされた画像", + "@imageUploadSuccess": {}, + "inactive": "無効", + "@inactive": {}, + "inactiveDetail": "この部品は無効としてマークされています", + "@inactiveDetail": {}, + "includeSubcategories": "サブカテゴリを含む", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "サブカテゴリをリストビューに表示します", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "サブ在庫場所を含める", + "@includeSublocations": {}, + "includeSublocationsDetail": "サブ在庫場所を表示します", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完全なプロフィールの詳細", + "@incompleteDetails": {}, + "internalPartNumber": "内部パーツ番号", + "@internalPartNumber": {}, + "info": "情報", + "@info": {}, + "inProduction": "生産中", + "@inProduction": {}, + "inProductionDetail": "この在庫品は生産中です", + "@inProductionDetail": {}, + "invalidHost": "無効なホスト名", + "@invalidHost": {}, + "invalidHostDetails": "このホスト名は無効です。", + "@invalidHostDetails": {}, + "invalidPart": "無効なパーツ", + "@invalidPart": {}, + "invalidPartCategory": "無効なパーツカテゴリー", + "@invalidPartCategory": {}, + "invalidStockLocation": "無効な在庫場所", + "@invalidStockLocation": {}, + "invalidStockItem": "無効な在庫アイテム", + "@invalidStockItem": {}, + "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", + "@invalidUsernamePassword": {}, + "issueDate": "発行日", + "@issueDate": {}, + "itemInLocation": "アイテムは既に在庫場所にあります", + "@itemInLocation": {}, + "keywords": "キーワード", + "@keywords": {}, + "lastUpdated": "最終更新", + "@lastUpdated": {}, + "locationCreate": "新しい場所", + "@locationCreate": {}, + "locationCreateDetail": "新しい在庫場所を作成", + "@locationCreateDetail": {}, + "locationNotSet": "在庫場所が指定されていません", + "@locationNotSet": {}, + "locationUpdated": "在庫場所を更新しました", + "@locationUpdated": {}, + "link": "リンク", + "@link": {}, + "lost": "損失", + "@lost": {}, + "missingData": "データ消失", + "@missingData": {}, + "name": "名前", + "@name": {}, + "notConnected": "接続されていません", + "@notConnected": {}, + "notes": "メモ", + "@notes": { + "description": "Notes" + }, + "noResponse": "サーバーからの応答がありません", + "@noResponse": {}, + "noResults": "一致する結果なし", + "@noResults": {}, + "noSubcategories": "サブカテゴリはありません", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "無効な値", + "@numberInvalid": {}, + "onOrder": "注文中", + "@onOrder": {}, + "packaging": "梱包中", + "@packaging": {}, + "packageName": "パッケージ名", + "@packageName": {}, + "parent": "親", + "@parent": {}, + "parentCategory": "親カテゴリ", + "@parentCategory": {}, + "parentLocation": "上位の場所", + "@parentLocation": {}, + "part": "パーツ", + "@part": { + "description": "Part (single)" + }, + "parts": "パーツ", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "パーツがありません", + "@partsNone": {}, + "partsStarredNone": "お気に入りのパーツはありません", + "@partsStarredNone": {}, + "partCategory": "パーツカテゴリー", + "@partCategory": {}, + "partCategoryTopLevel": "トップレベルのパーツカテゴリ", + "@partCategoryTopLevel": {}, + "partCategories": "パーツカテゴリー", + "@partCategories": {}, + "partDetails": "パーツ詳細", + "@partDetails": {}, + "partNotes": "パーツメモ", + "@partNotes": {}, + "partStock": "パーツ在庫:", + "@partStock": { + "description": "part stock" + }, + "password": "パスワード", + "@password": {}, + "passwordEmpty": "パスワードは空欄にできません。", + "@passwordEmpty": {}, + "permissionAccountDenied": "操作を行う権限がありません", + "@permissionAccountDenied": {}, + "permissionRequired": "権限が必要です", + "@permissionRequired": {}, + "printLabel": "ラベルを印刷", + "@printLabel": {}, + "printLabelFailure": "ラベルの印刷に失敗しました", + "@printLabelFailure": {}, + "printLabelSuccess": "ラベルをプリンタに送信しました", + "@printLabelSuccess": {}, + "profile": "プロフィール", + "@profile": {}, + "profileAdd": "サーバープロファイルを追加", + "@profileAdd": {}, + "profileConnect": "サーバーに接続", + "@profileConnect": {}, + "profileEdit": "サーバープロファイルを編集", + "@profileEdit": {}, + "profileDelete": "サーバープロファイルの削除", + "@profileDelete": {}, + "profileName": "プロファイル名", + "@profileName": {}, + "profileNone": "利用可能なプロファイルがありません", + "@profileNone": {}, + "profileNotSelected": "プロフィールが選択されていません", + "@profileNotSelected": {}, + "profileSelect": "InvenTreeサーバーを選択", + "@profileSelect": {}, + "profileTapToCreate": "タップしてプロフィールを作成または選択します", + "@profileTapToCreate": {}, + "purchaseOrder": "発注書", + "@purchaseOrder": {}, + "purchaseOrderEdit": "発注書の更新", + "@purchaseOrderEdit": {}, + "purchaseOrders": "発注書", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "発注書が更新されました", + "@purchaseOrderUpdated": {}, + "purchasePrice": "購入金額", + "@purchasePrice": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "数量が空です", + "@quantityEmpty": {}, + "quantityInvalid": "数量が無効です", + "@quantityInvalid": {}, + "quantityPositive": "数量は1以上", + "@quantityPositive": {}, + "queryNoResults": "検索結果はありません", + "@queryNoResults": {}, + "refresh": "更新", + "@refresh": {}, + "refreshing": "更新中", + "@refreshing": {}, + "rejected": "却下済み", + "@rejected": {}, + "releaseNotes": "リリースノート", + "@releaseNotes": {}, + "remove": "削除", + "@remove": { + "description": "remove" + }, + "removeStock": "在庫を削除", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "不具合の報告", + "@reportBug": {}, + "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", + "@reportBugDescription": {}, + "results": "結果", + "@results": {}, + "request": "リクエスト", + "@request": {}, + "requestingData": "データをリクエスト中", + "@requestingData": {}, + "required": "必須", + "@required": { + "description": "This field is required" + }, + "response400": "不正なリクエスト", + "@response400": {}, + "response401": "認証されていません", + "@response401": {}, + "response403": "権限がありません", + "@response403": {}, + "response404": "リソースが見つかりません", + "@response404": {}, + "response405": "メソッドが許可されていません", + "@response405": {}, + "response429": "リクエストが多すぎます", + "@response429": {}, + "response501": "未実装", + "@response501": {}, + "response503": "サービスは利用できません", + "@response503": {}, + "response505": "このHTTP バージョンはサポートされていません", + "@response505": {}, + "responseData": "応答データ", + "@responseData": {}, + "responseInvalid": "無効な応答", + "@responseInvalid": {}, + "responseUnknown": "不明な応答コード", + "@responseUnknown": {}, + "result": "結果", + "@result": { + "description": "" + }, + "returned": "返品済", + "@returned": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "バーコードをスキャン", + "@scanBarcode": {}, + "scanIntoLocation": "スキャンされた在庫場所", + "@scanIntoLocation": {}, + "search": "検索", + "@search": { + "description": "search" + }, + "searchLocation": "在庫場所場所を検索", + "@searchLocation": {}, + "searchParts": "パーツの検索", + "@searchParts": {}, + "searchStock": "在庫を検索", + "@searchStock": {}, + "select": "選択", + "@select": {}, + "selectFile": "ファイルを選択", + "@selectFile": {}, + "selectImage": "画像を選択", + "@selectImage": {}, + "selectLocation": "在庫場所を選択", + "@selectLocation": {}, + "send": "送信", + "@send": {}, + "serialNumber": "シリアルナンバー", + "@serialNumber": {}, + "server": "サーバー", + "@server": {}, + "serverAddress": "サーバーアドレス:", + "@serverAddress": {}, + "serverApiRequired": "必要なAPIバージョン", + "@serverApiRequired": {}, + "serverApiVersion": "サーバー API バージョン", + "@serverApiVersion": {}, + "serverAuthenticationError": "認証エラー", + "@serverAuthenticationError": {}, + "serverCertificateError": "認証エラー", + "@serverCertificateError": {}, + "serverCertificateInvalid": "サーバー HTTPS 証明書が無効です", + "@serverCertificateInvalid": {}, + "serverConnected": "サーバへ接続しました\n", + "@serverConnected": {}, + "serverConnecting": "サーバに接続中", + "@serverConnecting": {}, + "serverCouldNotConnect": "サーバーに接続できませんでした", + "@serverCouldNotConnect": {}, + "serverError": "サーバーエラー", + "@serverError": {}, + "serverDetails": "サーバの詳細", + "@serverDetails": {}, + "serverOld": "旧サーバーのバージョン", + "@serverOld": {}, + "serverSettings": "サーバー設定:", + "@serverSettings": {}, + "serverStart": "サーバーは http[s] で開始する必要があります", + "@serverStart": {}, + "settings": "設定", + "@settings": {}, + "serverInstance": "サーバインスタンス", + "@serverInstance": {}, + "serverNotConnected": "サーバーに接続されていません", + "@serverNotConnected": {}, + "sounds": "サウンド", + "@sounds": {}, + "soundOnBarcodeAction": "バーコード動作で音を鳴らす", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "サーバーのエラー時に音を鳴らす", + "@soundOnServerError": {}, + "status": "ステータス", + "@status": {}, + "statusCode": "ステータスコード", + "@statusCode": {}, + "stock": "在庫", + "@stock": { + "description": "stock" + }, + "stockItem": "在庫アイテム", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "在庫アイテム", + "@stockItems": {}, + "stockItemCreate": "新しい在庫アイテム", + "@stockItemCreate": {}, + "stockItemCreateDetail": "この場所に新しい在庫アイテムを作成", + "@stockItemCreateDetail": {}, + "stockItemDelete": "在庫アイテムを削除", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "この在庫アイテムを削除しますか?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "在庫アイテムを削除できませんでした。", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "在庫アイテムを削除しました", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "在庫履歴", + "@stockItemHistory": {}, + "stockItemTransferred": "在庫アイテムが転送されました", + "@stockItemTransferred": {}, + "stockItemUpdated": "在庫アイテムが更新されました", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "在庫アイテムがありません", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "在庫アイテムメモ", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "在庫アイテムが更新されました", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", + "@stockItemUpdateFailure": {}, + "stockLocation": "在庫場所", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "在庫場所", + "@stockLocations": {}, + "stockTopLevel": "トップレベルの在庫場所", + "@stockTopLevel": {}, + "strictHttps": "厳格なHTTPSを使用", + "@strictHttps": {}, + "subcategory": "サブカテゴリー", + "@subcategory": {}, + "subcategories": "サブカテゴリー", + "@subcategories": {}, + "sublocation": "サブ在庫場所", + "@sublocation": {}, + "sublocations": "サブ在庫場所", + "@sublocations": {}, + "sublocationNone": "サブ在庫場所がありません", + "@sublocationNone": {}, + "sublocationNoneDetail": "利用可能なサブ在庫場所がありません", + "@sublocationNoneDetail": {}, + "submitFeedback": "フィードバックを送信", + "@submitFeedback": {}, + "supplier": "サプライヤー", + "@supplier": {}, + "suppliers": "サプライヤー", + "@suppliers": {}, + "takePicture": "画像を撮影", + "@takePicture": {}, + "templatePart": "上位テンプレートパーツ", + "@templatePart": {}, + "testName": "テスト名", + "@testName": {}, + "testPassedOrFailed": "テストの合格または失敗", + "@testPassedOrFailed": {}, + "testsRequired": "必須テスト", + "@testsRequired": {}, + "testResults": "テスト結果", + "@testResults": { + "description": "" + }, + "testResultAdd": "テスト結果を追加", + "@testResultAdd": {}, + "testResultNone": "テスト結果がありません", + "@testResultNone": {}, + "testResultNoneDetail": "利用可能なテスト結果がありません", + "@testResultNoneDetail": {}, + "testResultUploadFail": "テスト結果のアップロードエラー", + "@testResultUploadFail": {}, + "testResultUploadPass": "テスト結果がアップロードされました", + "@testResultUploadPass": {}, + "timeout": "タイムアウト", + "@timeout": { + "description": "" + }, + "tokenError": "トークンエラー", + "@tokenError": {}, + "tokenMissing": "トークンがありません", + "@tokenMissing": {}, + "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", + "@tokenMissingFromResponse": {}, + "transfer": "転送", + "@transfer": { + "description": "transfer" + }, + "transferStock": "在庫の転送", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "翻訳", + "@translate": {}, + "translateHelp": "InvenTree アプリの翻訳に協力する", + "@translateHelp": {}, + "units": "単位", + "@units": {}, + "unknownResponse": "不明な応答", + "@unknownResponse": {}, + "upload": "アップロード", + "@upload": {}, + "uploadFailed": "ファイルのアップロードに失敗しました。", + "@uploadFailed": {}, + "uploadSuccess": "アップロードされたファイル", + "@uploadSuccess": {}, + "username": "ユーザー名", + "@username": {}, + "usernameEmpty": "ユーザー名は空にできません。", + "@usernameEmpty": {}, + "value": "設定値", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "値を空にすることはできません。", + "@valueCannotBeEmpty": {}, + "valueRequired": "値が必要です", + "@valueRequired": {}, + "version": "バージョン", + "@version": {}, + "website": "Webサイト", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/ko/app_ko.arb b/lib/l10n/ko/app_ko.arb new file mode 100644 index 0000000..6dd3712 --- /dev/null +++ b/lib/l10n/ko/app_ko.arb @@ -0,0 +1,105 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "add": "추가", + "@add": { + "description": "add" + }, + "address": "주소", + "@address": {}, + "appAbout": "InvenTree 소개", + "@appAbout": {}, + "appReleaseNotes": "앱 릴리즈 노트 표시", + "@appReleaseNotes": {}, + "appSettings": "앱 설정", + "@appSettings": {}, + "billOfMaterials": "부품 명세서", + "@billOfMaterials": {}, + "cancel": "취소", + "@cancel": { + "description": "Cancel" + }, + "company": "회사", + "@company": {}, + "companyEdit": "회사 수정", + "@companyEdit": {}, + "error": "오류", + "@error": { + "description": "Error" + }, + "errorDetails": "오류 세부 정보", + "@errorDetails": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "keywords": "키워드", + "@keywords": {}, + "noResults": "결과 없음", + "@noResults": {}, + "password": "비밀번호", + "@password": {}, + "passwordEmpty": "비밀번호는 비워둘 수 없습니다", + "@passwordEmpty": {}, + "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", + "@permissionAccountDenied": {}, + "profileConnect": "서버에 연결", + "@profileConnect": {}, + "quantity": "수량", + "@quantity": { + "description": "Quantity" + }, + "reportBug": "버그 신고", + "@reportBug": {}, + "response505": "지원되지 않는 HTTP 버전", + "@response505": {}, + "save": "저장", + "@save": { + "description": "Save" + }, + "select": "선택", + "@select": {}, + "selectFile": "파일 선택", + "@selectFile": {}, + "server": "서버", + "@server": {}, + "serverAddress": "서버 주소", + "@serverAddress": {}, + "serverApiRequired": "필요한 API 버전", + "@serverApiRequired": {}, + "serverApiVersion": "서버 API 버전", + "@serverApiVersion": {}, + "serverAuthenticationError": "인증 오류", + "@serverAuthenticationError": {}, + "serverConnecting": "서버에 연결하는 중", + "@serverConnecting": {}, + "serverError": "서버 오류", + "@serverError": {}, + "serverOld": "오래된 서버 버전", + "@serverOld": {}, + "serverSettings": "서버 설정", + "@serverSettings": {}, + "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", + "@serverStart": {}, + "status": "상태", + "@status": {}, + "statusCode": "상태 코드", + "@statusCode": {}, + "targetDate": "목표 날짜", + "@targetDate": {}, + "timeout": "시간 초과", + "@timeout": { + "description": "" + }, + "tokenError": "토큰 오류", + "@tokenError": {}, + "translate": "번역", + "@translate": {}, + "translateHelp": "InvenTree 앱의 번역을 도와주세요", + "@translateHelp": {}, + "version": "버전", + "@version": {}, + "website": "웹사이트", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/nl/app_nl.arb b/lib/l10n/nl/app_nl.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/nl/app_nl.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/no/app_no.arb b/lib/l10n/no/app_no.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/no/app_no.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/pl/app_pl.arb b/lib/l10n/pl/app_pl.arb new file mode 100644 index 0000000..af617ea --- /dev/null +++ b/lib/l10n/pl/app_pl.arb @@ -0,0 +1,739 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "O nas", + "@about": {}, + "accountDetails": "Szczegóły konta", + "@accountDetails": {}, + "actions": "Działania", + "@actions": { + "description": "" + }, + "actionsNone": "Brak dostępnych działań", + "@actionsNone": {}, + "add": "Dodaj", + "@add": { + "description": "add" + }, + "addStock": "Dodaj stan", + "@addStock": { + "description": "add stock" + }, + "address": "Adresy", + "@address": {}, + "appAbout": "O InvenTree", + "@appAbout": {}, + "appCredits": "Dodatkowe podziękowania autorskie", + "@appCredits": {}, + "appDetails": "Szczegóły aplikacji", + "@appDetails": {}, + "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", + "@appReleaseNotes": {}, + "appSettings": "Ustawienia aplikacji", + "@appSettings": {}, + "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", + "@appSettingsDetails": {}, + "attachments": "Załączniki", + "@attachments": {}, + "attachImage": "Dodaj zdjęcie", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nie znaleziono załączników", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Brak załączników dla tego komponentu", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Wybierz załącznik", + "@attachmentSelect": {}, + "attention": "Uwaga", + "@attention": {}, + "barcodeAssign": "Przypisz kod kreskowy", + "@barcodeAssign": {}, + "barcodeAssigned": "Kod kreskowy przypisany", + "@barcodeAssigned": {}, + "barcodeError": "Błąd czytnika kodów kreskowych", + "@barcodeError": {}, + "barcodeInUse": "Kod kreskowy jest już przypisany", + "@barcodeInUse": {}, + "barcodeMissingHash": "Brak danych haszujących w odpowiedzi kodu kreskowego", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Brak dopasowania dla kodu kreskowego", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Kod kreskowy nieprzypisany", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Zeskanuj przedmioty do lokalizacji", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skanuj lokalizację zapasów", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skanuj element magazynowy", + "@barcodeScanItem": {}, + "barcodeTones": "Dźwięki kodów kreskowych", + "@barcodeTones": {}, + "barcodeUnassign": "Nieprzydzielony kod kreskowy", + "@barcodeUnassign": {}, + "barcodeUnknown": "Nie rozpoznano kodu kreskowego", + "@barcodeUnknown": {}, + "batchCode": "Kod partii", + "@batchCode": {}, + "billOfMaterials": "Zestawienie materiałów", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Budowa", + "@build": {}, + "building": "Budowanie", + "@building": {}, + "cancel": "Anuluj", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategoria", + "@category": {}, + "categoryCreate": "Nowa Kategoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Utwórz nową kategorię komponentu", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategoria części została zmieniona", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Edytuj Firmę", + "@companyEdit": {}, + "companyNoResults": "Brak firm pasujących do zapytania", + "@companyNoResults": {}, + "companyUpdated": "Szczegóły firmy zostały zaktualizowane", + "@companyUpdated": {}, + "companies": "Firmy", + "@companies": {}, + "configureServer": "Konfiguruj ustawienia serwera", + "@configureServer": {}, + "connectionRefused": "Połączenie odrzucone", + "@connectionRefused": {}, + "count": "Ilość", + "@count": { + "description": "Count" + }, + "countStock": "Przelicz stan", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Podziękowania", + "@credits": {}, + "customers": "Klienci", + "@customers": {}, + "damaged": "Uszkodzone", + "@damaged": {}, + "delete": "Usuń", + "@delete": {}, + "deletePart": "Usuń Komponent", + "@deletePart": {}, + "deletePartDetail": "Usuń ten komponent z bazy danych", + "@deletePartDetail": {}, + "description": "Opis", + "@description": {}, + "destroyed": "Zniszczony", + "@destroyed": {}, + "details": "Szczegóły", + "@details": { + "description": "details" + }, + "documentation": "Dokumentacja", + "@documentation": {}, + "downloading": "Pobieranie Pliku", + "@downloading": {}, + "downloadError": "Błąd Pobierania", + "@downloadError": {}, + "edit": "Edytuj", + "@edit": { + "description": "edit" + }, + "editCategory": "Edytuj kategorię", + "@editCategory": {}, + "editLocation": "Edytuj lokację", + "@editLocation": {}, + "editNotes": "Edytuj Notatki", + "@editNotes": {}, + "editPart": "Edytuj część", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edytuj Pozycję Magazynową", + "@editItem": {}, + "enterPassword": "Wprowadź hasło", + "@enterPassword": {}, + "enterUsername": "Wprowadź nazwę użytkownika", + "@enterUsername": {}, + "error": "Błąd", + "@error": { + "description": "Error" + }, + "errorCreate": "Błąd tworzenia wpisu w bazie danych", + "@errorCreate": {}, + "errorDelete": "Błąd podczas usuwania wpisu bazy danych", + "@errorDelete": {}, + "errorDetails": "Szczegóły błędu", + "@errorDetails": {}, + "errorFetch": "Błąd pobierania danych z serwea", + "@errorFetch": {}, + "errorReporting": "Raportowanie błędów", + "@errorReporting": {}, + "errorReportUpload": "Prześlij raport o błędach", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", + "@errorReportUploadDetails": {}, + "feedback": "Opinie", + "@feedback": {}, + "feedbackError": "Błąd dodawania opinii", + "@feedbackError": {}, + "feedbackSuccess": "Opinia przesłana", + "@feedbackSuccess": {}, + "formatException": "Wyjątek formatowania", + "@formatException": {}, + "formatExceptionJson": "Wyjątek formatu danych JSON", + "@formatExceptionJson": {}, + "formError": "Błąd Formularza", + "@formError": {}, + "history": "Historia", + "@history": { + "description": "history" + }, + "homeScreen": "Ekran główny", + "@homeScreen": {}, + "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", + "@homeScreenSettings": {}, + "homeShowPo": "Pokaż zamówienia zakupu", + "@homeShowPo": {}, + "homeShowSubscribed": "Obserwowane części", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Pokaż dostawców", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Pokaż producentów", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Pokaż przycisk producentów na ekranie głównym", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Pokaż klientów", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Pokaż przycisk klientów na ekranie głównym", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Przesyłanie zdjęcia nie powiodło się", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Obraz przesłany", + "@imageUploadSuccess": {}, + "inactive": "Nieaktywny", + "@inactive": {}, + "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", + "@inactiveDetail": {}, + "includeSubcategories": "Zawieraj podkategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Wyświetl części z podkategorii w widoku listy", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Zawieraj sublokacje", + "@includeSublocations": {}, + "includeSublocationsDetail": "Wyświetl części z sublokacji w widoku listy", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Niekompletne szczegóły profilu", + "@incompleteDetails": {}, + "internalPartNumber": "Wewnętrzny numer części", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "W produkcji", + "@inProduction": {}, + "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", + "@inProductionDetail": {}, + "invalidHost": "Nieprawidłowa nazwa hosta", + "@invalidHost": {}, + "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", + "@invalidHostDetails": {}, + "invalidPart": "Nieprawidłowa część", + "@invalidPart": {}, + "invalidPartCategory": "Nieprawidłowa kategoria części", + "@invalidPartCategory": {}, + "invalidStockLocation": "Nieprawidłowa lokacja magazynowa", + "@invalidStockLocation": {}, + "invalidStockItem": "Nieprawidłowa część magazynowa", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nieprawidłowy login lub hasło", + "@invalidUsernamePassword": {}, + "issueDate": "Data Wystawienia", + "@issueDate": {}, + "itemInLocation": "Część jest już w lokacji", + "@itemInLocation": {}, + "keywords": "Słowa kluczowe", + "@keywords": {}, + "lastStocktake": "Ostatnia inwentaryzacja", + "@lastStocktake": {}, + "lastUpdated": "Ostatnia aktualizacja", + "@lastUpdated": {}, + "lineItem": "Pozycja", + "@lineItem": {}, + "lineItems": "Pozycje", + "@lineItems": {}, + "locationCreate": "Nowa Lokalizacja", + "@locationCreate": {}, + "locationCreateDetail": "Utwórz nową pozycję magazynową", + "@locationCreateDetail": {}, + "locationNotSet": "Nie określono lokacji", + "@locationNotSet": {}, + "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Zagubiono", + "@lost": {}, + "manufacturers": "Producenci", + "@manufacturers": {}, + "missingData": "Brakujące dane", + "@missingData": {}, + "name": "Nazwa", + "@name": {}, + "notConnected": "Nie połączony", + "@notConnected": {}, + "notes": "Notatki", + "@notes": { + "description": "Notes" + }, + "noResponse": "Brak odpowiedzi od serwera", + "@noResponse": {}, + "noResults": "Brak wyników", + "@noResults": {}, + "noSubcategories": "Brak podkategorii", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Brak dostępnych podkategorii", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Błędny numer", + "@numberInvalid": {}, + "onOrder": "W Zamówieniu", + "@onOrder": {}, + "onOrderDetails": "Pozycje obecnie w zamówieniu", + "@onOrderDetails": {}, + "packaging": "Opakowanie", + "@packaging": {}, + "packageName": "Nazwa pakietu", + "@packageName": {}, + "parent": "Nadrzędny", + "@parent": {}, + "parentCategory": "Kategoria nadrzędna", + "@parentCategory": {}, + "parentLocation": "Lokalizacja Nadrzędna", + "@parentLocation": {}, + "part": "Część", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nowy Komponent", + "@partCreate": {}, + "partCreateDetail": "Utwórz nowy komponent w tej kategorii", + "@partCreateDetail": {}, + "partEdited": "Część zaktualizowana", + "@partEdited": {}, + "parts": "Części", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Brak części", + "@partsNone": {}, + "partNoResults": "Brak komponentów pasujących do zapytania", + "@partNoResults": {}, + "partsStarred": "Obserwowane części", + "@partsStarred": {}, + "partsStarredNone": "Brak części oznaczonych gwiazdką", + "@partsStarredNone": {}, + "partSuppliers": "Dostawcy Części", + "@partSuppliers": {}, + "partCategory": "Kategoria części", + "@partCategory": {}, + "partCategoryTopLevel": "Kategoria części najwyższego poziomu", + "@partCategoryTopLevel": {}, + "partCategories": "Kategorie części", + "@partCategories": {}, + "partDetails": "Szczegóły części", + "@partDetails": {}, + "partNotes": "Notatki do części", + "@partNotes": {}, + "partStock": "Zapasy cześci", + "@partStock": { + "description": "part stock" + }, + "password": "Hasło", + "@password": {}, + "passwordEmpty": "Hasło nie może być puste", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", + "@permissionAccountDenied": {}, + "permissionRequired": "Wymagane uprawnienia", + "@permissionRequired": {}, + "printLabel": "Drukuj etykietę", + "@printLabel": {}, + "printLabelFailure": "Drukowanie etykiet nie powiodło się", + "@printLabelFailure": {}, + "printLabelSuccess": "Etykieta wysłana do drukarki", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Dodaj profil serwera", + "@profileAdd": {}, + "profileConnect": "Połącz się z serwerem", + "@profileConnect": {}, + "profileEdit": "Edytuj profil serwera", + "@profileEdit": {}, + "profileDelete": "Usuń profil serwera", + "@profileDelete": {}, + "profileName": "Nazwa Profilu", + "@profileName": {}, + "profileNone": "Brak dostępnych profili", + "@profileNone": {}, + "profileNotSelected": "Nie wybrano profilu", + "@profileNotSelected": {}, + "profileSelect": "Wybierz serwer InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Zlecenie Zakupu", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Zlecenia zakupu", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Cena Zakupu", + "@purchasePrice": {}, + "quantity": "Ilość", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Ilość jest pusta", + "@quantityEmpty": {}, + "quantityInvalid": "Ilość jest nieprawidłowa", + "@quantityInvalid": {}, + "quantityPositive": "Ilość musi być dodatnia", + "@quantityPositive": {}, + "queryNoResults": "Nie znaleziono wyników dla zapytania", + "@queryNoResults": {}, + "received": "Odebrane", + "@received": {}, + "receiveItem": "Przyjmij artykuły", + "@receiveItem": {}, + "receivedItem": "Przyjęta Pozycja Magazynowa", + "@receivedItem": {}, + "refresh": "Odśwież", + "@refresh": {}, + "refreshing": "Odświeżanie", + "@refreshing": {}, + "rejected": "Odrzucono", + "@rejected": {}, + "releaseNotes": "Lista zmian", + "@releaseNotes": {}, + "remove": "Usuń", + "@remove": { + "description": "remove" + }, + "removeStock": "Usuń stan", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Zgłoś błąd", + "@reportBug": {}, + "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", + "@reportBugDescription": {}, + "results": "Wyniki", + "@results": {}, + "request": "Żądanie", + "@request": {}, + "requestingData": "Żądanie danych", + "@requestingData": {}, + "required": "Wymagane", + "@required": { + "description": "This field is required" + }, + "response400": "Błędne żądanie", + "@response400": {}, + "response401": "Nieautoryzowany", + "@response401": {}, + "response403": "Odmowa dostępu", + "@response403": {}, + "response404": "Nie znaleziono", + "@response404": {}, + "response405": "Metoda niedozwolona", + "@response405": {}, + "response429": "Zbyt wiele żądań", + "@response429": {}, + "response500": "Wewnętrzny błąd serwera", + "@response500": {}, + "response501": "Nie zaimplementowano", + "@response501": {}, + "response502": "Zła brama", + "@response502": {}, + "response503": "Usługa niedostępna", + "@response503": {}, + "response504": "Przekroczono limit czasu", + "@response504": {}, + "response505": "Wersja HTTP nie obsługiwana", + "@response505": {}, + "responseData": "Dane odpowiedzi", + "@responseData": {}, + "responseInvalid": "Nieprawidłowy kod odpowiedzi", + "@responseInvalid": {}, + "responseUnknown": "Nieznana odpowiedź", + "@responseUnknown": {}, + "result": "Wynik", + "@result": { + "description": "" + }, + "returned": "Zwrócono", + "@returned": {}, + "salesOrders": "Zlecenia Sprzedaży", + "@salesOrders": {}, + "save": "Zapisz", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skanuj kod kreskowy", + "@scanBarcode": {}, + "scanIntoLocation": "Skanuj do lokacji", + "@scanIntoLocation": {}, + "search": "Szukaj", + "@search": { + "description": "search" + }, + "searchLocation": "Wyszukaj lokalizację", + "@searchLocation": {}, + "searchParts": "Szukaj części", + "@searchParts": {}, + "searchStock": "Szukaj zapasów", + "@searchStock": {}, + "select": "Wybierz", + "@select": {}, + "selectFile": "Wybierz Plik", + "@selectFile": {}, + "selectImage": "Wybierz obraz", + "@selectImage": {}, + "selectLocation": "Wybierz lokację", + "@selectLocation": {}, + "send": "Wyślij", + "@send": {}, + "serialNumber": "Numer seryjny", + "@serialNumber": {}, + "server": "Serwer", + "@server": {}, + "serverAddress": "Adres serwera", + "@serverAddress": {}, + "serverApiRequired": "Wymagana wersja API", + "@serverApiRequired": {}, + "serverApiVersion": "Wersja API serwera", + "@serverApiVersion": {}, + "serverAuthenticationError": "Błąd uwierzytelniania", + "@serverAuthenticationError": {}, + "serverCertificateError": "Błąd certyfikatu", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Certyfikat serwera HTTPS jest nieprawidłowy", + "@serverCertificateInvalid": {}, + "serverConnected": "Połączony z serwerem", + "@serverConnected": {}, + "serverConnecting": "Łączenie z serwerem", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nie można połączyć się z serwerem", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serwer nie może być pusty", + "@serverEmpty": {}, + "serverError": "Błąd serwera", + "@serverError": {}, + "serverDetails": "Szczegóły serwera", + "@serverDetails": {}, + "serverMissingData": "Odpowiedź serwera nie ma wymaganych pól", + "@serverMissingData": {}, + "serverOld": "Stara wersja serwera", + "@serverOld": {}, + "serverSettings": "Ustawienia Serwera", + "@serverSettings": {}, + "serverStart": "Serwer musi zaczynać się od http[s]", + "@serverStart": {}, + "settings": "Ustawienia", + "@settings": {}, + "serverInstance": "Instancja serwera", + "@serverInstance": {}, + "serverNotConnected": "Serwer nie podłączony", + "@serverNotConnected": {}, + "sounds": "Dźwięki", + "@sounds": {}, + "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Kod statusu", + "@statusCode": {}, + "stock": "Stan", + "@stock": { + "description": "stock" + }, + "stockItem": "Element magazynowy", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Elementy magazynowe", + "@stockItems": {}, + "stockItemCreate": "Nowa Pozycja Magazynowa", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Utwórz nową pozycję magazynową w tej lokalizacji", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Usuń przedmiot magazynowy", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Czy jesteś pewien, że chcesz usunąć ten przedmiot magazynowy?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Nie można usunąć przedmiotu magazynowego", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Przedmiot magazynowy usunięty", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historia zapasów", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Wyświetl historyczne informacje o śledzeniu stanów magazynowych", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Element magazynowy przeniesiony", + "@stockItemTransferred": {}, + "stockItemUpdated": "Zaktualizowano element magazynowy", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Brak dostępnych elementów", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notatki przedmiotu magazynowego", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Zaktualizowano element magazynowy", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Nie zaktualizowano elementu magazynowego", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lokacja stanu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lokacje stanów", + "@stockLocations": {}, + "stockTopLevel": "Najwyższy poziom lokalizacji magazynu", + "@stockTopLevel": {}, + "strictHttps": "Ścisły HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Wymuś ścisłe sprawdzanie certyfikatów HTTPS", + "@strictHttpsDetails": {}, + "subcategory": "Podkategoria", + "@subcategory": {}, + "subcategories": "Podkategorie", + "@subcategories": {}, + "sublocation": "Sublokacja", + "@sublocation": {}, + "sublocations": "Subblokacje", + "@sublocations": {}, + "sublocationNone": "Brak subblokacji", + "@sublocationNone": {}, + "sublocationNoneDetail": "Brak dostępnych podlokalizacji", + "@sublocationNoneDetail": {}, + "submitFeedback": "Prześlij opinię", + "@submitFeedback": {}, + "suppliedParts": "Dostarczone Części", + "@suppliedParts": {}, + "supplier": "Dostawca", + "@supplier": {}, + "suppliers": "Dostawcy", + "@suppliers": {}, + "supplierReference": "Identyfikator Dostawcy", + "@supplierReference": {}, + "takePicture": "Zrób zdjęcie", + "@takePicture": {}, + "targetDate": "Data Docelowa", + "@targetDate": {}, + "testName": "Nazwa testu", + "@testName": {}, + "testPassedOrFailed": "Test zaliczony lub nieudany", + "@testPassedOrFailed": {}, + "testsRequired": "Wymagane testy", + "@testsRequired": {}, + "testResults": "Wyniki testu", + "@testResults": { + "description": "" + }, + "testResultAdd": "Dodaj wynik testu", + "@testResultAdd": {}, + "testResultNone": "Brak wyników testu", + "@testResultNone": {}, + "testResultNoneDetail": "Brak dostępnych wyników testu", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Błąd przesyłania wyniku testu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Wynik testu przesłany", + "@testResultUploadPass": {}, + "timeout": "Upłynął limit czasu", + "@timeout": { + "description": "" + }, + "tokenError": "Błąd tokenu", + "@tokenError": {}, + "tokenMissing": "Brakujący token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", + "@tokenMissingFromResponse": {}, + "transfer": "Przenieś", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Przenieś stan", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Przetłumacz", + "@translate": {}, + "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", + "@translateHelp": {}, + "units": "Jednostki", + "@units": {}, + "unknownResponse": "Nieznana odpowiedź", + "@unknownResponse": {}, + "upload": "Wyślij", + "@upload": {}, + "uploadFailed": "Błąd wysyłania pliku", + "@uploadFailed": {}, + "uploadSuccess": "Plik przesłany", + "@uploadSuccess": {}, + "usedIn": "Użyte w", + "@usedIn": {}, + "usedInDetails": "Złożenie, które wymagają tego komponentu", + "@usedInDetails": {}, + "username": "Nazwa użytkownika", + "@username": {}, + "usernameEmpty": "Nazwa użytkownika nie może być pusta", + "@usernameEmpty": {}, + "value": "Wartość", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Wartość nie może być pusta", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wartość jest wymagana", + "@valueRequired": {}, + "version": "Wersja", + "@version": {}, + "viewSupplierPart": "Zobacz Dostawcę Części", + "@viewSupplierPart": {}, + "website": "Strona WWW", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/pt-BR/app_pt.arb b/lib/l10n/pt-BR/app_pt.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/pt-BR/app_pt.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/pt-PT/app_pt.arb b/lib/l10n/pt-PT/app_pt.arb new file mode 100644 index 0000000..4e4e56b --- /dev/null +++ b/lib/l10n/pt-PT/app_pt.arb @@ -0,0 +1,193 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Sobre", + "@about": {}, + "accountDetails": "Detalhes da Conta", + "@accountDetails": {}, + "actions": "Ações", + "@actions": { + "description": "" + }, + "actionsNone": "Nenhuma ação disponível", + "@actionsNone": {}, + "add": "Adicionar", + "@add": { + "description": "add" + }, + "addStock": "Adicionar ao estoque", + "@addStock": { + "description": "add stock" + }, + "address": "Endereço", + "@address": {}, + "appAbout": "Sobre o InvenTree", + "@appAbout": {}, + "appCredits": "Créditos adicionais do aplicativo", + "@appCredits": {}, + "appDetails": "Detalhes do App", + "@appDetails": {}, + "appReleaseNotes": "Exibir notas de versão do aplicativo", + "@appReleaseNotes": {}, + "appSettings": "Configurações do App", + "@appSettings": {}, + "appSettingsDetails": "Configurar os parâmetros do InvenTree", + "@appSettingsDetails": {}, + "attachments": "Anexos", + "@attachments": {}, + "attachImage": "Anexar Imagem", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Não foram encontrados quaisquer anexos", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Selecionar anexo", + "@attachmentSelect": {}, + "attention": "Aviso", + "@attention": {}, + "barcodeAssign": "Atribuir Código de Barras", + "@barcodeAssign": {}, + "barcodeAssigned": "Código de barras atribuído", + "@barcodeAssigned": {}, + "barcodeError": "Erro ao escanear código de barras", + "@barcodeError": {}, + "barcodeInUse": "Código de barras já atribuído", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Não corresponde a nenhum código de barras", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Código de barras não atribuído", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Escaneie para atribuir código de barras", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Escaneie itens de estoque no local", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear Localização", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Escaneado no local", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "Escanear ítem", + "@barcodeScanItem": {}, + "barcodeTones": "Tons do código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Remover código de barras pre-designado", + "@barcodeUnassign": {}, + "barcodeUnknown": "Código de barras não reconhecido", + "@barcodeUnknown": {}, + "batchCode": "Código de lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiais", + "@billOfMaterials": {}, + "bom": "Lista de Materiais", + "@bom": {}, + "build": "Compilar", + "@build": {}, + "building": "Compilando", + "@building": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nova Categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Criar nova categoria de peças", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria de peça atualizada", + "@categoryUpdated": {}, + "company": "Empresa", + "@company": {}, + "companyEdit": "Editar empresa", + "@companyEdit": {}, + "companyNoResults": "Nenhuma empresa corresponde a consulta", + "@companyNoResults": {}, + "companyUpdated": "Dados da empresa atualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "configureServer": "Configurar os parâmetros do servidor de email", + "@configureServer": {}, + "connectionRefused": "Conexão recusada", + "@connectionRefused": {}, + "count": "Contagem", + "@count": { + "description": "Count" + }, + "countStock": "Contagem de Estoque", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "customers": "Clientes", + "@customers": {}, + "damaged": "Danificado", + "@damaged": {}, + "delete": "Excluir", + "@delete": {}, + "deletePart": "Excluir esta parte", + "@deletePart": {}, + "deletePartDetail": "Remover esta peça da base de dados", + "@deletePartDetail": {}, + "description": "Descrição", + "@description": {}, + "destroyed": "Destruído", + "@destroyed": {}, + "details": "Detalhes", + "@details": { + "description": "details" + }, + "documentation": "Documentação", + "@documentation": {}, + "downloading": "Baixando arquivo", + "@downloading": {}, + "downloadError": "Erro de download", + "@downloadError": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editCategory": "Editar categoria", + "@editCategory": {}, + "editLocation": "Editar Localização", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editPart": "Editar a peça", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar Item do Estoque", + "@editItem": {}, + "enterPassword": "Digite a senha", + "@enterPassword": {}, + "enterUsername": "Inserir usuário", + "@enterUsername": {}, + "error": "Erro", + "@error": { + "description": "Error" + }, + "errorCreate": "Erro ao criar entrada de banco de dados", + "@errorCreate": {}, + "errorDelete": "Erro ao excluir entrada no banco de dados", + "@errorDelete": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "lastUpdated": "Ultima atualização", + "@lastUpdated": {}, + "lineItems": "Itens de linha", + "@lineItems": {} +} \ No newline at end of file diff --git a/lib/l10n/ru/app_ru.arb b/lib/l10n/ru/app_ru.arb new file mode 100644 index 0000000..7a7dbef --- /dev/null +++ b/lib/l10n/ru/app_ru.arb @@ -0,0 +1,263 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "ОК", + "@ok": { + "description": "OK" + }, + "about": "О проекте", + "@about": {}, + "accountDetails": "Данные аккаунта", + "@accountDetails": {}, + "actions": "Действия", + "@actions": { + "description": "" + }, + "actionsNone": "Действия недоступны", + "@actionsNone": {}, + "add": "Добавить", + "@add": { + "description": "add" + }, + "addStock": "Добавить запасы", + "@addStock": { + "description": "add stock" + }, + "address": "Адрес", + "@address": {}, + "appAbout": "О InvenTree", + "@appAbout": {}, + "appCredits": "Благодарности за помощь и поддержку", + "@appCredits": {}, + "appDetails": "Информация о приложении", + "@appDetails": {}, + "appReleaseNotes": "Показать заметки о выпуске приложения", + "@appReleaseNotes": {}, + "appSettings": "Настройки приложения", + "@appSettings": {}, + "companyNoResults": "Нет организаций, соответствующих запросу", + "@companyNoResults": {}, + "downloading": "Загрузка файла", + "@downloading": {}, + "downloadError": "Ошибка загрузки", + "@downloadError": {}, + "edit": "Изменить", + "@edit": { + "description": "edit" + }, + "editCategory": "Редактировать категорию", + "@editCategory": {}, + "editLocation": "Редактировать местонахождение", + "@editLocation": {}, + "editNotes": "Редактировать примечания", + "@editNotes": {}, + "editPart": "Ред. эту часть", + "@editPart": { + "description": "edit part" + }, + "editItem": "Отредактированный товар", + "@editItem": {}, + "enterPassword": "Введите пароль", + "@enterPassword": {}, + "enterUsername": "Введите имя пользователя", + "@enterUsername": {}, + "error": "Ошибка", + "@error": { + "description": "Error" + }, + "errorCreate": "Ошибка создания записи базы данных", + "@errorCreate": {}, + "errorDetails": "Подробнее об ошибке", + "@errorDetails": {}, + "errorFetch": "Ошибка при получении данных с сервера", + "@errorFetch": {}, + "feedback": "Обратная Связь", + "@feedback": {}, + "feedbackError": "Ошибка отправки отзыва", + "@feedbackError": {}, + "feedbackSuccess": "Отзыв отправлен", + "@feedbackSuccess": {}, + "formatException": "Формат исключения", + "@formatException": {}, + "formatExceptionJson": "Ошибка формата JSON", + "@formatExceptionJson": {}, + "formError": "Ошибка в форме", + "@formError": {}, + "history": "История", + "@history": { + "description": "history" + }, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Не удалось загрузить изображение", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Изображение загружено", + "@imageUploadSuccess": {}, + "inactive": "Неактивный", + "@inactive": {}, + "inactiveDetail": "Эта часть помечена как неактивная", + "@inactiveDetail": {}, + "includeSubcategories": "Включить подкатегории", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Отображать подкатегории в виде списка", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Добавить доп. местоположения", + "@includeSublocations": {}, + "includeSublocationsDetail": "Отображать доп. местоположения в виде списка", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Неполные данные профиля", + "@incompleteDetails": {}, + "internalPartNumber": "Внутренний номер", + "@internalPartNumber": {}, + "info": "Информация", + "@info": {}, + "invalidHost": "Неверное имя хоста", + "@invalidHost": {}, + "invalidHostDetails": "Недопустимый пароль", + "@invalidHostDetails": {}, + "invalidPart": "Недопустимый элемент", + "@invalidPart": {}, + "invalidPartCategory": "Неверная категория элемента", + "@invalidPartCategory": {}, + "invalidStockLocation": "Неверное расположение склада", + "@invalidStockLocation": {}, + "invalidStockItem": "Недопустимый товарный пункт", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", + "@invalidUsernamePassword": {}, + "issueDate": "Дата проблемы", + "@issueDate": {}, + "itemInLocation": "Элемент уже находится на месте", + "@itemInLocation": {}, + "keywords": "Ключевые слова", + "@keywords": {}, + "lastStocktake": "Последняя инвентаризация", + "@lastStocktake": {}, + "lastUpdated": "Последние обновлённые", + "@lastUpdated": {}, + "lineItem": "Элемент строки", + "@lineItem": {}, + "lineItems": "Элементы строки", + "@lineItems": {}, + "locationCreate": "Новое местоположение", + "@locationCreate": {}, + "locationCreateDetail": "Создать новое расположение склада", + "@locationCreateDetail": {}, + "locationNotSet": "Не указано месторасположение", + "@locationNotSet": {}, + "link": "Ссылка", + "@link": {}, + "lost": "Потерян", + "@lost": {}, + "manufacturers": "Производители", + "@manufacturers": {}, + "missingData": "Отсутствующие данные", + "@missingData": {}, + "name": "Название", + "@name": {}, + "notConnected": "Соединение не установлено", + "@notConnected": {}, + "notes": "Заметки", + "@notes": { + "description": "Notes" + }, + "noResponse": "Нет ответа от сервера", + "@noResponse": {}, + "noResults": "Нет результатов", + "@noResults": {}, + "noSubcategories": "Нет подкатегории", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Нет доступных подкатегорий", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Неправильный номер", + "@numberInvalid": {}, + "onOrder": "Под заказ", + "@onOrder": {}, + "onOrderDetails": "Заказаные элементы", + "@onOrderDetails": {}, + "packaging": "Упаковка", + "@packaging": {}, + "packageName": "Название упаковки", + "@packageName": {}, + "parent": "Родитель", + "@parent": {}, + "parentCategory": "Родительская категория", + "@parentCategory": {}, + "parentLocation": "Родительское местоположение", + "@parentLocation": {}, + "part": "Компонент", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Новый компонент", + "@partCreate": {}, + "partCreateDetail": "Создать компонент в данной категории", + "@partCreateDetail": {}, + "parts": "Номенклатура", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Нет компонентов", + "@partsNone": {}, + "partNoResults": "Нет компонентов, соответствующих запросу", + "@partNoResults": {}, + "response405": "405 Метод не разрешен", + "@response405": {}, + "response429": "Слишком много запросов", + "@response429": {}, + "response500": "Внутренняя ошибка сервера", + "@response500": {}, + "response501": "Не реализовано", + "@response501": {}, + "response502": "Недопустимый шлюз", + "@response502": {}, + "response503": "Сервис недоступен", + "@response503": {}, + "response504": "504: тайм-аут шлюза", + "@response504": {}, + "response505": "505: версия не поддерживается", + "@response505": {}, + "responseData": "Информация об ответе", + "@responseData": {}, + "responseInvalid": "Неверный код ответа", + "@responseInvalid": {}, + "responseUnknown": "Неизвестный ответ", + "@responseUnknown": {}, + "result": "Результат", + "@result": { + "description": "" + }, + "returned": "Возвращено", + "@returned": {}, + "salesOrders": "Заказы на продажу", + "@salesOrders": {}, + "save": "Сохранить", + "@save": { + "description": "Save" + }, + "scanBarcode": "Сканировать штрихкод", + "@scanBarcode": {}, + "scanIntoLocation": "Сканировать в местоположение", + "@scanIntoLocation": {}, + "search": "Поиск", + "@search": { + "description": "search" + }, + "searchLocation": "Искать по месту", + "@searchLocation": {}, + "searchParts": "Найти номенклатуру", + "@searchParts": {}, + "searchStock": "Поиск в наличии", + "@searchStock": {}, + "select": "Выбрать", + "@select": {}, + "selectFile": "Выбрать файл", + "@selectFile": {}, + "selectImage": "Выбрать изображение", + "@selectImage": {}, + "website": "Сайт", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/sv-SE/app_sv.arb b/lib/l10n/sv-SE/app_sv.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/sv-SE/app_sv.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/th/app_th.arb b/lib/l10n/th/app_th.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/th/app_th.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/tr/app_tr.arb b/lib/l10n/tr/app_tr.arb new file mode 100644 index 0000000..e069fbf --- /dev/null +++ b/lib/l10n/tr/app_tr.arb @@ -0,0 +1,735 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "TAMAM", + "@ok": { + "description": "OK" + }, + "about": "Hakkında", + "@about": {}, + "accountDetails": "Hesap Detayları", + "@accountDetails": {}, + "actions": "Eylemler", + "@actions": { + "description": "" + }, + "actionsNone": "Kullanılabilir eylem yok", + "@actionsNone": {}, + "add": "Ekle", + "@add": { + "description": "add" + }, + "addStock": "Stok ekle", + "@addStock": { + "description": "add stock" + }, + "address": "Adres", + "@address": {}, + "appAbout": "InvenTree Hakkında", + "@appAbout": {}, + "appCredits": "Uygulama kredisi ekle", + "@appCredits": {}, + "appDetails": "Uygulama Detayları", + "@appDetails": {}, + "appReleaseNotes": "Uygulama yayınlama notları", + "@appReleaseNotes": {}, + "appSettings": "Uygulama Ayarları", + "@appSettings": {}, + "appSettingsDetails": "Uygulama ayarlarından yapılandır", + "@appSettingsDetails": {}, + "attachments": "Ekler", + "@attachments": {}, + "attachImage": "Resim ekle", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Hiçbir ek bulunamadı", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Ek seçin", + "@attachmentSelect": {}, + "attention": "Dikkat", + "@attention": {}, + "barcodeAssign": "Barkod Ata", + "@barcodeAssign": {}, + "barcodeAssigned": "Barkod atandı", + "@barcodeAssigned": {}, + "barcodeError": "Barkod tarama hatası", + "@barcodeError": {}, + "barcodeInUse": "Barkod zaten kullanımda", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash verisi alınamadı", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Barkod için eşleşme yok", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barkod atanmış değil", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Atanmış barkodu tara", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Bir Iventree barkodu tara", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Stok öğelerini konum içine tara", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Stok konumu tara", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Konuma tarandı", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Madde taranmış değil", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Stok öğesi tara", + "@barcodeScanItem": {}, + "barcodeTones": "Barkod Tonları", + "@barcodeTones": {}, + "barcodeUnassign": "Atanmamış barkod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barkod tanınmadı", + "@barcodeUnknown": {}, + "batchCode": "Grup kodu", + "@batchCode": {}, + "billOfMaterials": "Fatura materyalleri", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Oluştur", + "@build": {}, + "building": "Oluşturma", + "@building": {}, + "cancel": "İptal", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Yeni Kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Yeni parça kategorisi oluştur", + "@categoryCreateDetail": {}, + "categoryUpdated": "Parça Kategorisi güncellendi", + "@categoryUpdated": {}, + "company": "Şirket", + "@company": {}, + "companyEdit": "Şirketi Düzenle", + "@companyEdit": {}, + "companyNoResults": "Sorguyla eşleşen şirket yok", + "@companyNoResults": {}, + "companyUpdated": "Firma bilgileri güncellendi", + "@companyUpdated": {}, + "companies": "Şirketler", + "@companies": {}, + "configureServer": "Sunucu ayarlarınızı yapılandırın", + "@configureServer": {}, + "connectionRefused": "Bağlantı reddedildi", + "@connectionRefused": {}, + "count": "Sayım", + "@count": { + "description": "Count" + }, + "countStock": "Stok sayımı", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Katkıda Bulunanlar", + "@credits": {}, + "customers": "Müşteriler", + "@customers": {}, + "damaged": "Hasarlı", + "@damaged": {}, + "delete": "Sil", + "@delete": {}, + "deletePart": "Parça Sil", + "@deletePart": {}, + "deletePartDetail": "Bu parçayı veritabanından kaldır", + "@deletePartDetail": {}, + "description": "Açıklama", + "@description": {}, + "destroyed": "Yok edildi", + "@destroyed": {}, + "details": "Detaylar", + "@details": { + "description": "details" + }, + "documentation": "Dökümantasyon", + "@documentation": {}, + "downloading": "Dosya indiriliyor", + "@downloading": {}, + "downloadError": "İndirme Hatası", + "@downloadError": {}, + "edit": "Düzenle", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategoriyi düzenle", + "@editCategory": {}, + "editLocation": "Konumu Düzenle", + "@editLocation": {}, + "editNotes": "Notları Düzenle", + "@editNotes": {}, + "editPart": "Parçayı Düzenle", + "@editPart": { + "description": "edit part" + }, + "editItem": "Parçayı Düzenle", + "@editItem": {}, + "enterPassword": "Şifrenizi girin", + "@enterPassword": {}, + "enterUsername": "Kullanıcı adını girin", + "@enterUsername": {}, + "error": "Hata", + "@error": { + "description": "Error" + }, + "errorCreate": "Veritabanı girdi oluşturma hatası", + "@errorCreate": {}, + "errorDelete": "Veritabanı girdisini silerken hata", + "@errorDelete": {}, + "errorDetails": "Hata Ayrıntıları", + "@errorDetails": {}, + "errorFetch": "Sunucudan veri alınırken hata oluştu", + "@errorFetch": {}, + "errorReporting": "Hata Raporlama", + "@errorReporting": {}, + "errorReportUpload": "Hata raporu yükle", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonim olarak hata ve log yükle", + "@errorReportUploadDetails": {}, + "feedback": "Geri Bildirim", + "@feedback": {}, + "feedbackError": "Geribildirim gönderme hatası", + "@feedbackError": {}, + "feedbackSuccess": "Geri bildirim gönderildi", + "@feedbackSuccess": {}, + "formatException": "Biçim İstisnası", + "@formatException": {}, + "formatExceptionJson": "JSON veri format istisnası", + "@formatExceptionJson": {}, + "formError": "Form hatası", + "@formError": {}, + "history": "Geçmiş", + "@history": { + "description": "history" + }, + "homeScreen": "Ana Ekran", + "@homeScreen": {}, + "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", + "@homeScreenSettings": {}, + "homeShowPo": "Satın Alma Siparişlerini Göster", + "@homeShowPo": {}, + "homeShowSubscribed": "Parça bildirimlerine abone ol", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", + "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Tedarikçileri Göster", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Üreticileri Göster", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Müşterileri Göster", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Fotoğraf yükleme başarısız", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Resim yüklendi", + "@imageUploadSuccess": {}, + "inactive": "Pasif", + "@inactive": {}, + "inactiveDetail": "Bu parça pasif olarak işaretlendi", + "@inactiveDetail": {}, + "includeSubcategories": "Alt kategorileri dahil et", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Alt kategori parçalarını liste görünümünde göster", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alt konumları dahil et", + "@includeSublocations": {}, + "includeSublocationsDetail": "Alt konum parçalarını liste görünümünde göster", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Tamamlanmamış profil detayları", + "@incompleteDetails": {}, + "internalPartNumber": "İç Parça Numarası", + "@internalPartNumber": {}, + "info": "Bilgi", + "@info": {}, + "inProduction": "Yapım Aşamasında", + "@inProduction": {}, + "inProductionDetail": "Bu ürün üretim aşamasında", + "@inProductionDetail": {}, + "invalidHost": "Geçersiz alan adı", + "@invalidHost": {}, + "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", + "@invalidHostDetails": {}, + "invalidPart": "Geçersiz Parça", + "@invalidPart": {}, + "invalidPartCategory": "Geçersiz Parça Kategorisi", + "@invalidPartCategory": {}, + "invalidStockLocation": "Geçersiz Stok Konumu", + "@invalidStockLocation": {}, + "invalidStockItem": "Geçersiz Stok Parçası", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", + "@invalidUsernamePassword": {}, + "issueDate": "Sorun Tarihi", + "@issueDate": {}, + "itemInLocation": "Parça zaten konumda", + "@itemInLocation": {}, + "keywords": "Anahtar kelimeler", + "@keywords": {}, + "lastStocktake": "Son stok tutma", + "@lastStocktake": {}, + "lastUpdated": "Son güncelleme", + "@lastUpdated": {}, + "lineItem": "Parça Sırası", + "@lineItem": {}, + "lineItems": "Parçalar Sırası", + "@lineItems": {}, + "locationCreate": "Yeni Konum", + "@locationCreate": {}, + "locationCreateDetail": "Yeni stok konumu oluştur", + "@locationCreateDetail": {}, + "locationNotSet": "Belirtilmiş konum yok", + "@locationNotSet": {}, + "locationUpdated": "Stok lokasyonu güncellendi", + "@locationUpdated": {}, + "link": "Bağlantı", + "@link": {}, + "lost": "Kayıp", + "@lost": {}, + "manufacturers": "Üreticiler", + "@manufacturers": {}, + "missingData": "Eksik Veri", + "@missingData": {}, + "name": "Adı", + "@name": {}, + "notConnected": "Bağlı değil", + "@notConnected": {}, + "notes": "Notlar", + "@notes": { + "description": "Notes" + }, + "noResponse": "Sunucudan yanıt yok", + "@noResponse": {}, + "noResults": "Sonuç Yok", + "@noResults": {}, + "noSubcategories": "Alt kategori yok", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Uygun alt kategori yok", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Geçersiz numara", + "@numberInvalid": {}, + "onOrder": "Siparişte", + "@onOrder": {}, + "onOrderDetails": "Parça şuan siparişte", + "@onOrderDetails": {}, + "packaging": "Paketleme", + "@packaging": {}, + "packageName": "Paket İsmi", + "@packageName": {}, + "parent": "Üst", + "@parent": {}, + "parentCategory": "Üst Kategori", + "@parentCategory": {}, + "parentLocation": "Bağlı lokasyon", + "@parentLocation": {}, + "part": "Parça", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Yeni Parça", + "@partCreate": {}, + "partCreateDetail": "Yeni parça kategorisi oluştur", + "@partCreateDetail": {}, + "partEdited": "Parça Güncellendi", + "@partEdited": {}, + "parts": "Parçalar", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Parça Yok", + "@partsNone": {}, + "partNoResults": "Sorguyla eşleşen parça yok", + "@partNoResults": {}, + "partsStarred": "Sürekli Gelen parçalar", + "@partsStarred": {}, + "partsStarredNone": "Yıldızlı parça yok", + "@partsStarredNone": {}, + "partSuppliers": "Parça Tedarikçileri", + "@partSuppliers": {}, + "partCategory": "Parça Kategorileri", + "@partCategory": {}, + "partCategoryTopLevel": "Üst seviye parça kategorisi", + "@partCategoryTopLevel": {}, + "partCategories": "Parça Kategorileri", + "@partCategories": {}, + "partDetails": "Parça detayları", + "@partDetails": {}, + "partNotes": "Parça notları", + "@partNotes": {}, + "partStock": "Parça stok", + "@partStock": { + "description": "part stock" + }, + "password": "Parola", + "@password": {}, + "passwordEmpty": "Parola boş bırakılamaz", + "@passwordEmpty": {}, + "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", + "@permissionAccountDenied": {}, + "permissionRequired": "İzin Gerekli", + "@permissionRequired": {}, + "printLabel": "Etiket Yazdır", + "@printLabel": {}, + "printLabelFailure": "Etiket yazdırılamadı", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiket yazıcıya gönderildi", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Yeni Sunucu Profili Ekle", + "@profileAdd": {}, + "profileConnect": "Sunucuya bağlan", + "@profileConnect": {}, + "profileEdit": "Sunucu Profilini düzenle", + "@profileEdit": {}, + "profileDelete": "Sunucu profilini sil", + "@profileDelete": {}, + "profileName": "Profil Adı", + "@profileName": {}, + "profileNone": "Kullanılabiir profil yok", + "@profileNone": {}, + "profileNotSelected": "Profil seçilmedi", + "@profileNotSelected": {}, + "profileSelect": "InvenTree sunucusu seç", + "@profileSelect": {}, + "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", + "@profileTapToCreate": {}, + "purchaseOrder": "Satınalma Siparişi", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Satın Alma siparişini düzenle", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Satınalma Siparişleri", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Alış Fiyatı", + "@purchasePrice": {}, + "quantity": "Adet", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Adet boş", + "@quantityEmpty": {}, + "quantityInvalid": "Adet geçersiz", + "@quantityInvalid": {}, + "quantityPositive": "Adet pozitif bir sayı olmalı", + "@quantityPositive": {}, + "queryNoResults": "Sorgu için sonuç yok", + "@queryNoResults": {}, + "received": "Alınan", + "@received": {}, + "receiveItem": "Alınan Öğeler", + "@receiveItem": {}, + "receivedItem": "Alınan stok parçaları", + "@receivedItem": {}, + "refresh": "Yenile", + "@refresh": {}, + "refreshing": "Yenileniyor", + "@refreshing": {}, + "rejected": "Reddedildi", + "@rejected": {}, + "releaseNotes": "Sürüm notları", + "@releaseNotes": {}, + "remove": "Kaldır", + "@remove": { + "description": "remove" + }, + "removeStock": "Stok Kaldır", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hata Bildir", + "@reportBug": {}, + "reportBugDescription": "Hata raporla ( github hesabı gerektirir)", + "@reportBugDescription": {}, + "results": "Sonuçlar", + "@results": {}, + "request": "Talep", + "@request": {}, + "requestingData": "Veri Talep Ediliyor", + "@requestingData": {}, + "required": "Gerekli", + "@required": { + "description": "This field is required" + }, + "response400": "Hatalı İstek", + "@response400": {}, + "response401": "Yetkisiz", + "@response401": {}, + "response403": "İzin Engellendi", + "@response403": {}, + "response404": "Kaynak bulunamadı", + "@response404": {}, + "response405": "İzin Verilmeyen Yöntem", + "@response405": {}, + "response429": "Çok Fazla İstek", + "@response429": {}, + "response500": "İç Sunucu Hatası", + "@response500": {}, + "response501": "Uygulanamadı", + "@response501": {}, + "response502": "Hatalı Ağ Geçidi", + "@response502": {}, + "response503": "Hizmet Kullanılamıyor", + "@response503": {}, + "response504": "Ağ Geçidi Zaman Aşımı", + "@response504": {}, + "response505": "HTTP Sürümü Desteklenmiyor", + "@response505": {}, + "responseData": "Yanıt verileri", + "@responseData": {}, + "responseInvalid": "Geçersiz yanıt kodu.", + "@responseInvalid": {}, + "responseUnknown": "Bilinmeyen yanıt", + "@responseUnknown": {}, + "result": "Sonuç", + "@result": { + "description": "" + }, + "returned": "Geri Dönen", + "@returned": {}, + "salesOrders": "Satış Siparişleri", + "@salesOrders": {}, + "save": "Kaydet", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barkod Tara", + "@scanBarcode": {}, + "scanIntoLocation": "Konuma Tara", + "@scanIntoLocation": {}, + "search": "Ara", + "@search": { + "description": "search" + }, + "searchLocation": "Konum için Ara", + "@searchLocation": {}, + "searchParts": "Parçaları Ara", + "@searchParts": {}, + "searchStock": "Stok Ara", + "@searchStock": {}, + "select": "Seç", + "@select": {}, + "selectFile": "Dosya Seç", + "@selectFile": {}, + "selectImage": "Resim Seç", + "@selectImage": {}, + "selectLocation": "Bir yer seçin", + "@selectLocation": {}, + "send": "Gönder", + "@send": {}, + "serialNumber": "Seri Numara", + "@serialNumber": {}, + "server": "Sunucu", + "@server": {}, + "serverAddress": "Sunucu Adresi", + "@serverAddress": {}, + "serverApiRequired": "Gerekli API Sürümü", + "@serverApiRequired": {}, + "serverApiVersion": "Sunucu API Sürümü", + "@serverApiVersion": {}, + "serverAuthenticationError": "Doğrulama Hatası", + "@serverAuthenticationError": {}, + "serverCertificateError": "Sertifika Hatası", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Sunucunun sertifikası geçersiz", + "@serverCertificateInvalid": {}, + "serverConnected": "Sunucuya bağlanıldı", + "@serverConnected": {}, + "serverConnecting": "Sunucuya bağlanıyor", + "@serverConnecting": {}, + "serverCouldNotConnect": "Sunucuya bağlanılamadı", + "@serverCouldNotConnect": {}, + "serverEmpty": "Sunucu boş olamaz", + "@serverEmpty": {}, + "serverError": "Sunucu Hatası", + "@serverError": {}, + "serverDetails": "Sunucu Detayları", + "@serverDetails": {}, + "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", + "@serverMissingData": {}, + "serverOld": "Eski Sunucu Sürümü", + "@serverOld": {}, + "serverSettings": "Sunucu Ayarları", + "@serverSettings": {}, + "serverStart": "Sunucu http(s) ile başlamalı", + "@serverStart": {}, + "settings": "Ayarlar", + "@settings": {}, + "serverInstance": "Sunucu örneği", + "@serverInstance": {}, + "serverNotConnected": "Sunucu bağlı değil", + "@serverNotConnected": {}, + "sounds": "Sesler", + "@sounds": {}, + "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Sunucu hatasında sesli ton çal", + "@soundOnServerError": {}, + "status": "Durum", + "@status": {}, + "statusCode": "Durum Kodu", + "@statusCode": {}, + "stock": "Stok", + "@stock": { + "description": "stock" + }, + "stockItem": "Stok Kalemi", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stok Kalemleri", + "@stockItems": {}, + "stockItemCreate": "Yeni Stok Kalemi", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Stok parçasını sil", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Stok parçası silinemedi", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stok parçası silindi", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stok Geçmişi", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Stok takip bilgisini göster", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stok kalemi transfer edildi", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stok kalemi güncellendi", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Uygun stok kalemi yok", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stok Kalemi Notları", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stok kalemi güncellendi", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stok kalemi güncelleme hatası", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stok Konumu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stok Konumları", + "@stockLocations": {}, + "stockTopLevel": "Üst seviye stok konumu", + "@stockTopLevel": {}, + "subcategory": "Alt kategori", + "@subcategory": {}, + "subcategories": "Alt kategoriler", + "@subcategories": {}, + "sublocation": "Alt konumlar", + "@sublocation": {}, + "sublocations": "Alt konumlar", + "@sublocations": {}, + "sublocationNone": "Alt konum yok", + "@sublocationNone": {}, + "sublocationNoneDetail": "Uygun alt kategori yok", + "@sublocationNoneDetail": {}, + "submitFeedback": "Geri Bildirim Gönder", + "@submitFeedback": {}, + "suppliedParts": "Sağlanan Parçalar", + "@suppliedParts": {}, + "supplier": "Tedarikçi", + "@supplier": {}, + "suppliers": "Tedarikçiler", + "@suppliers": {}, + "supplierReference": "Tedarikçi Referansı", + "@supplierReference": {}, + "takePicture": "Resim Çek", + "@takePicture": {}, + "targetDate": "Hedeflenen Tarih", + "@targetDate": {}, + "testName": "Test Adı", + "@testName": {}, + "testPassedOrFailed": "Test başarılı veya hatalı", + "@testPassedOrFailed": {}, + "testsRequired": "Gerekli Testler", + "@testsRequired": {}, + "testResults": "Test Sonuçları", + "@testResults": { + "description": "" + }, + "testResultAdd": "Test Sonucu Ekle", + "@testResultAdd": {}, + "testResultNone": "Test Sonucu Yok", + "@testResultNone": {}, + "testResultNoneDetail": "Uygun test sonucu yok", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hatalı yüklenen test sonucu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test sonucu yüklendi", + "@testResultUploadPass": {}, + "timeout": "Zaman Aşımı", + "@timeout": { + "description": "" + }, + "tokenError": "Token Hatası", + "@tokenError": {}, + "tokenMissing": "Eksik Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", + "@tokenMissingFromResponse": {}, + "transfer": "Aktarım", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Stok Aktar", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Çeviri", + "@translate": {}, + "translateHelp": "Çeviriye yardım et", + "@translateHelp": {}, + "units": "Birim", + "@units": {}, + "unknownResponse": "Bilinmeyen Yanıt", + "@unknownResponse": {}, + "upload": "Yükle", + "@upload": {}, + "uploadFailed": "Dosya yüklenemedi", + "@uploadFailed": {}, + "uploadSuccess": "Dosya yüklendi", + "@uploadSuccess": {}, + "usedIn": "Burada Kullanıldı", + "@usedIn": {}, + "usedInDetails": "Bu parçayı gerektiren montajlar", + "@usedInDetails": {}, + "username": "Kullanıcı Adı", + "@username": {}, + "usernameEmpty": "Kullanıcı adı boş bırakılamaz", + "@usernameEmpty": {}, + "value": "Değer", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Değer boş olamaz", + "@valueCannotBeEmpty": {}, + "valueRequired": "Değer gereklidir", + "@valueRequired": {}, + "version": "Sürüm", + "@version": {}, + "viewSupplierPart": "Tedarikçi Parçası Görüntüle", + "@viewSupplierPart": {}, + "website": "Web sitesi", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/vi/app_vi.arb b/lib/l10n/vi/app_vi.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/vi/app_vi.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/zh-CN/app_zh.arb b/lib/l10n/zh-CN/app_zh.arb new file mode 100644 index 0000000..6a6c70d --- /dev/null +++ b/lib/l10n/zh-CN/app_zh.arb @@ -0,0 +1,341 @@ +{ + "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "好", + "@ok": { + "description": "OK" + }, + "about": "关于", + "@about": {}, + "accountDetails": "账户详情", + "@accountDetails": {}, + "actions": "操作", + "@actions": { + "description": "" + }, + "add": "添加", + "@add": { + "description": "add" + }, + "addStock": "添加库存", + "@addStock": { + "description": "add stock" + }, + "address": "地址", + "@address": {}, + "appAbout": "关于 InventTree", + "@appAbout": {}, + "appDetails": "应用详情", + "@appDetails": {}, + "appSettings": "应用设置", + "@appSettings": {}, + "attention": "注意", + "@attention": {}, + "barcodeAssign": "分配条码", + "@barcodeAssign": {}, + "barcodeAssigned": "条码已分配", + "@barcodeAssigned": {}, + "barcodeError": "条形码扫描出错", + "@barcodeError": {}, + "barcodeInUse": "条码已经被分配", + "@barcodeInUse": {}, + "barcodeNoMatch": "无匹配条码", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "未分配条码", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "扫描以分配条码", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "扫描 InvenTree 条码", + "@barcodeScanGeneral": {}, + "barcodeScanLocation": "扫描库存地点", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "已扫描至位置", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "扫描库存项", + "@barcodeScanItem": {}, + "barcodeUnassign": "取消分配条码", + "@barcodeUnassign": {}, + "barcodeUnknown": "无法识别条码", + "@barcodeUnknown": {}, + "build": "生产", + "@build": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "category": "分类", + "@category": {}, + "categoryCreate": "新建分类", + "@categoryCreate": {}, + "categoryCreateDetail": "新建商品类别", + "@categoryCreateDetail": {}, + "company": "公司", + "@company": {}, + "companyEdit": "编辑公司信息", + "@companyEdit": {}, + "companies": "公司", + "@companies": {}, + "connectionRefused": "连接被拒绝", + "@connectionRefused": {}, + "count": "数量", + "@count": { + "description": "Count" + }, + "countStock": "库存数量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "致谢", + "@credits": {}, + "damaged": "破损", + "@damaged": {}, + "delete": "删除", + "@delete": {}, + "description": "描述", + "@description": {}, + "destroyed": "销毁", + "@destroyed": {}, + "details": "详细信息", + "@details": { + "description": "details" + }, + "documentation": "文档", + "@documentation": {}, + "edit": "编辑", + "@edit": { + "description": "edit" + }, + "editCategory": "编辑分类", + "@editCategory": {}, + "editLocation": "编辑位置", + "@editLocation": {}, + "editPart": "编辑部件", + "@editPart": { + "description": "edit part" + }, + "error": "错误", + "@error": { + "description": "Error" + }, + "errorDetails": "c w错误详情", + "@errorDetails": {}, + "history": "历史", + "@history": { + "description": "history" + }, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "internalPartNumber": "内部部件号", + "@internalPartNumber": {}, + "info": "信息", + "@info": {}, + "invalidPart": "无效部件", + "@invalidPart": {}, + "invalidPartCategory": "无效部件分类", + "@invalidPartCategory": {}, + "invalidStockLocation": "无效库存位置", + "@invalidStockLocation": {}, + "invalidStockItem": "无效库存项", + "@invalidStockItem": {}, + "keywords": "关键词", + "@keywords": {}, + "link": "链接", + "@link": {}, + "lost": "丢失", + "@lost": {}, + "name": "名称", + "@name": {}, + "notConnected": "未连接", + "@notConnected": {}, + "notes": "注释", + "@notes": { + "description": "Notes" + }, + "noResponse": "服务器未响应", + "@noResponse": {}, + "parent": "父级", + "@parent": {}, + "parentCategory": "父类别", + "@parentCategory": {}, + "part": "部件", + "@part": { + "description": "Part (single)" + }, + "parts": "部件", + "@parts": { + "description": "Part (multiple)" + }, + "partCategory": "部件分类", + "@partCategory": {}, + "partCategories": "部件分类", + "@partCategories": {}, + "partDetails": "部件详情", + "@partDetails": {}, + "partNotes": "部件注释", + "@partNotes": {}, + "partStock": "部件库存", + "@partStock": { + "description": "part stock" + }, + "password": "密码", + "@password": {}, + "profile": "档案", + "@profile": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "容量为空", + "@quantityEmpty": {}, + "quantityInvalid": "数量无效", + "@quantityInvalid": {}, + "quantityPositive": "数量必须大于0", + "@quantityPositive": {}, + "refresh": "刷新", + "@refresh": {}, + "refreshing": "正在刷新", + "@refreshing": {}, + "rejected": "已拒绝", + "@rejected": {}, + "releaseNotes": "更新日志", + "@releaseNotes": {}, + "remove": "移除", + "@remove": { + "description": "remove" + }, + "removeStock": "移除库存", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "反馈问题", + "@reportBug": {}, + "request": "请求", + "@request": {}, + "requestingData": "正在请求数据", + "@requestingData": {}, + "required": "必填", + "@required": { + "description": "This field is required" + }, + "responseInvalid": "无效响应码", + "@responseInvalid": {}, + "responseUnknown": "未知响应", + "@responseUnknown": {}, + "result": "结果", + "@result": { + "description": "" + }, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "扫描条码", + "@scanBarcode": {}, + "scanIntoLocation": "已扫描至位置", + "@scanIntoLocation": {}, + "search": "搜索", + "@search": { + "description": "search" + }, + "searchParts": "搜索部件", + "@searchParts": {}, + "searchStock": "搜索库存", + "@searchStock": {}, + "select": "选择", + "@select": {}, + "send": "发送", + "@send": {}, + "serialNumber": "序列号", + "@serialNumber": {}, + "server": "服务器", + "@server": {}, + "serverAddress": "服务器地址", + "@serverAddress": {}, + "serverConnected": "已连接至服务器", + "@serverConnected": {}, + "serverError": "服务器错误", + "@serverError": {}, + "serverDetails": "服务器详情", + "@serverDetails": {}, + "serverOld": "过时的服务器版本", + "@serverOld": {}, + "serverSettings": "服务器设置", + "@serverSettings": {}, + "settings": "设置", + "@settings": {}, + "serverInstance": "服务器实例", + "@serverInstance": {}, + "serverNotConnected": "未连接至服务器", + "@serverNotConnected": {}, + "status": "状态", + "@status": {}, + "statusCode": "状态码", + "@statusCode": {}, + "stock": "库存", + "@stock": { + "description": "stock" + }, + "stockItem": "库存项", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "库存项", + "@stockItems": {}, + "stockItemNotes": "库存项注释", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "库存项已更新", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "库存项更新失败", + "@stockItemUpdateFailure": {}, + "stockLocation": "库存位置", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "库存位置", + "@stockLocations": {}, + "subcategory": "子类别", + "@subcategory": {}, + "subcategories": "子类别", + "@subcategories": {}, + "sublocation": "次级位置", + "@sublocation": {}, + "sublocations": "次级位置", + "@sublocations": {}, + "testResults": "测试结果", + "@testResults": { + "description": "" + }, + "timeout": "超时", + "@timeout": { + "description": "" + }, + "tokenError": "令牌错误", + "@tokenError": {}, + "tokenMissing": "缺少令牌", + "@tokenMissing": {}, + "transfer": "转移", + "@transfer": { + "description": "transfer" + }, + "transferStock": "转移库存", + "@transferStock": { + "description": "transfer stock" + }, + "unknownResponse": "未知响应", + "@unknownResponse": {}, + "upload": "上传", + "@upload": {}, + "username": "用户名", + "@username": {}, + "value": "值", + "@value": { + "description": "value" + }, + "version": "版本", + "@version": {}, + "website": "网站", + "@website": {} +} \ No newline at end of file From 77b24ad9e40cac8787d581995cf1af36b3ad00e3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 09:59:08 +1000 Subject: [PATCH 003/746] Change path to translations --- l10n.yaml | 2 +- lib/widget/location_display.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/l10n.yaml b/l10n.yaml index a5b40b9..7b9da73 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,4 +1,4 @@ -arb-dir: lib/l10n +arb-dir: lib/l10n/collected 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/widget/location_display.dart b/lib/widget/location_display.dart index 75554e1..00ba955 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -117,7 +117,7 @@ class _LocationDisplayState extends RefreshableState { // Reload location information if (location != null) { - final bool result = await location?.reload() ?? false; + final bool result = await location!.reload() ?? false; if (!result) { Navigator.of(context).pop(); From 56b11b99563e4a8fd5194ae420adfaa076ca788b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 10:03:37 +1000 Subject: [PATCH 004/746] Add readme file --- lib/l10n/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 lib/l10n/README.md diff --git a/lib/l10n/README.md b/lib/l10n/README.md new file mode 100644 index 0000000..aae698e --- /dev/null +++ b/lib/l10n/README.md @@ -0,0 +1,23 @@ +## InvenTree Translation Files + +This directory contains translation files for the InvenTree mobile app. + +### File Structure + +**Translation Source File** - app_en.arb + +This file contains the source strings for translating. If you want to add a new translatable string to the app, is must be added to this file! + +**Translated Files** - /app_arb + +Each directory contains a single translation output file, generated by the [crowdin translation service](https://crowdin.com/project/inventree). *Do not edit these files* + +**collected** - Collected files + +Before building the app, the translation files are collected from the various directories into a single directory, so they can be accessed by the app. + +### Translating + +DO NOT EDIT THE TRANSLATION FILES DIRECTLY! + +Translation files are crowd sourced using the [crowdin service](https://crowdin.com/project/inventree). Contributions are welcomed (and encouraged!) From 245f18be6e6847339d5e6a8236b5560bcd4b4fb4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 10:04:30 +1000 Subject: [PATCH 005/746] Update build instructions --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 7f16021..beb4116 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -18,7 +18,7 @@ Ensure that the translation files have been updated, and copied into the correct ``` cd lib/l10n -python update_translations.py +python collect_translations.py ``` ### Build Appbundle From a5a78f21cd72c97c7c6bd23c77fe393ddedf41f4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 10:16:34 +1000 Subject: [PATCH 006/746] Collect translation files as part of CI --- .github/workflows/android.yaml | 4 ++++ .github/workflows/ios.yaml | 4 ++++ .github/workflows/lint.yaml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 32aed76..d88e094 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -32,6 +32,10 @@ jobs: uses: gradle/gradle-build-action@v2 with: gradle-version: 6.1.1 + - name: Collect Translations + run: | + cd lib/l10n + python3 collect_translations.py - name: Build for Android run: | flutter pub get diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 202c684..8f428ca 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -28,6 +28,10 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' + - name: Collect Translations + run: | + cd lib/l10n + python3 collect_translations.py - name: Build for iOS run: | flutter pub get diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index a9d3fe7..b199b27 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -31,6 +31,10 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' + - name: Collect Translations + run: | + cd lib/l10n + python3 collect_translations.py - run: flutter pub get - run: cp lib/dummy_dsn.dart lib/dsn.dart - run: flutter analyze From ef422b4f00aaa8c4d5b13f56081d579d59e428b9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 10:29:53 +1000 Subject: [PATCH 007/746] Ensure output directory has been created --- lib/l10n/collect_translations.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index 56e3dbe..f1987e3 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -74,6 +74,10 @@ if __name__ == '__main__': here = os.path.abspath(os.path.dirname(__file__)) + # Ensure the 'collected' output directory exists + output_dir = os.path.join(here, 'collected') + os.makedirs(output_dir, exist_ok=True) + for item in os.listdir(here): # Ignore the output directory From 2cdf927d98edff71ae95fc9e755e53bf3246d867 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 10:36:03 +1000 Subject: [PATCH 008/746] linting fix --- lib/widget/location_display.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 00ba955..cdf1856 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -117,7 +117,7 @@ class _LocationDisplayState extends RefreshableState { // Reload location information if (location != null) { - final bool result = await location!.reload() ?? false; + final bool result = await location!.reload(); if (!result) { Navigator.of(context).pop(); From 4db641889876f76818b4ef83262d04c11102dfc6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 10:57:47 +1000 Subject: [PATCH 009/746] Update Crowdin configuration file --- crowdin.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 crowdin.yml diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..204cc87 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: /lib/l10n/app_en.arb + translation: /lib/l10n/app_%two_letters_code%.arb From e28beb6a5e9281957fe80f0f17e49f12f82a32e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:00:29 +1000 Subject: [PATCH 010/746] New Crowdin updates (#107) * New translations app_en.arb (French) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Persian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Turkish) * New translations app_en.arb (Swedish) * New translations app_en.arb (Russian) * New translations app_en.arb (Polish) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Korean) * New translations app_en.arb (Japanese) * New translations app_en.arb (Italian) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Greek) * New translations app_en.arb (German) * New translations app_en.arb (Czech) * New translations app_en.arb (Thai) --- lib/l10n/app_cs.arb | 5 +++++ lib/l10n/app_de.arb | 5 +++++ lib/l10n/app_el.arb | 5 +++++ lib/l10n/app_es.arb | 5 +++++ lib/l10n/app_fa.arb | 5 +++++ lib/l10n/app_fr.arb | 5 +++++ lib/l10n/app_he.arb | 5 +++++ lib/l10n/app_hu.arb | 5 +++++ lib/l10n/app_id.arb | 5 +++++ lib/l10n/app_it.arb | 5 +++++ lib/l10n/app_ja.arb | 5 +++++ lib/l10n/app_ko.arb | 5 +++++ lib/l10n/app_nl.arb | 5 +++++ lib/l10n/app_no.arb | 5 +++++ lib/l10n/app_pl.arb | 5 +++++ lib/l10n/app_pt.arb | 5 +++++ lib/l10n/app_ru.arb | 5 +++++ lib/l10n/app_sv.arb | 5 +++++ lib/l10n/app_th.arb | 5 +++++ lib/l10n/app_tr.arb | 5 +++++ lib/l10n/app_vi.arb | 5 +++++ lib/l10n/app_zh.arb | 5 +++++ 22 files changed, 110 insertions(+) create mode 100644 lib/l10n/app_cs.arb create mode 100644 lib/l10n/app_de.arb create mode 100644 lib/l10n/app_el.arb create mode 100644 lib/l10n/app_es.arb create mode 100644 lib/l10n/app_fa.arb create mode 100644 lib/l10n/app_fr.arb create mode 100644 lib/l10n/app_he.arb create mode 100644 lib/l10n/app_hu.arb create mode 100644 lib/l10n/app_id.arb create mode 100644 lib/l10n/app_it.arb create mode 100644 lib/l10n/app_ja.arb create mode 100644 lib/l10n/app_ko.arb create mode 100644 lib/l10n/app_nl.arb create mode 100644 lib/l10n/app_no.arb create mode 100644 lib/l10n/app_pl.arb create mode 100644 lib/l10n/app_pt.arb create mode 100644 lib/l10n/app_ru.arb create mode 100644 lib/l10n/app_sv.arb create mode 100644 lib/l10n/app_th.arb create mode 100644 lib/l10n/app_tr.arb create mode 100644 lib/l10n/app_vi.arb create mode 100644 lib/l10n/app_zh.arb diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_cs.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_de.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_el.arb b/lib/l10n/app_el.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_el.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_es.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_fa.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_fr.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_he.arb b/lib/l10n/app_he.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_he.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_hu.arb b/lib/l10n/app_hu.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_hu.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_id.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_it.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_ja.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_ko.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_nl.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_no.arb b/lib/l10n/app_no.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_no.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_pl.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_pt.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_ru.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_sv.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_th.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_tr.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_vi.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/app_zh.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 5b095be5f87440073be5660f237640e8a5e4bccc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 11:06:50 +1000 Subject: [PATCH 011/746] Simplify translation scheme Recover old translation data --- .github/workflows/android.yaml | 4 - .github/workflows/ios.yaml | 4 - .github/workflows/lint.yaml | 4 - l10n.yaml | 2 +- lib/l10n/.gitignore | 2 - lib/l10n/app_cs.arb | 2 +- lib/l10n/app_de.arb | 744 +++++++++++++++++++++++++++++- lib/l10n/app_el.arb | 2 +- lib/l10n/app_es.arb | 16 +- lib/l10n/app_fa.arb | 2 +- lib/l10n/app_fr.arb | 742 +++++++++++++++++++++++++++++- lib/l10n/app_he.arb | 2 +- lib/l10n/app_hu.arb | 744 +++++++++++++++++++++++++++++- lib/l10n/app_id.arb | 2 +- lib/l10n/app_it.arb | 504 ++++++++++++++++++++- lib/l10n/app_ja.arb | 681 +++++++++++++++++++++++++++- lib/l10n/app_ko.arb | 104 ++++- lib/l10n/app_nl.arb | 2 +- lib/l10n/app_no.arb | 2 +- lib/l10n/app_pl.arb | 738 +++++++++++++++++++++++++++++- lib/l10n/app_pt.arb | 192 +++++++- lib/l10n/app_ru.arb | 262 ++++++++++- lib/l10n/app_sv.arb | 2 +- lib/l10n/app_th.arb | 2 +- lib/l10n/app_tr.arb | 734 +++++++++++++++++++++++++++++- lib/l10n/app_vi.arb | 2 +- lib/l10n/app_zh.arb | 340 +++++++++++++- lib/l10n/collect_translations.py | 97 ---- lib/l10n/crowdin.yml | 3 - lib/l10n/cs/app_cs.arb | 5 - lib/l10n/de/app_de.arb | 745 ------------------------------- lib/l10n/el/app_el.arb | 5 - lib/l10n/es-419/app_es.arb | 3 - lib/l10n/es-ES/app_es.arb | 635 -------------------------- lib/l10n/es-MX/app_es.arb | 17 - lib/l10n/fa/app_fa.arb | 5 - lib/l10n/fr/app_fr.arb | 743 ------------------------------ lib/l10n/he/app_he.arb | 5 - lib/l10n/hu/app_hu.arb | 745 ------------------------------- lib/l10n/id/app_id.arb | 5 - lib/l10n/it/app_it.arb | 505 --------------------- lib/l10n/ja/app_ja.arb | 682 ---------------------------- lib/l10n/ko/app_ko.arb | 105 ----- lib/l10n/nl/app_nl.arb | 5 - lib/l10n/no/app_no.arb | 5 - lib/l10n/pl/app_pl.arb | 739 ------------------------------ lib/l10n/pt-BR/app_pt.arb | 5 - lib/l10n/pt-PT/app_pt.arb | 193 -------- lib/l10n/ru/app_ru.arb | 263 ----------- lib/l10n/sv-SE/app_sv.arb | 5 - lib/l10n/th/app_th.arb | 5 - lib/l10n/tr/app_tr.arb | 735 ------------------------------ lib/l10n/vi/app_vi.arb | 5 - lib/l10n/zh-CN/app_zh.arb | 341 -------------- 54 files changed, 5788 insertions(+), 6655 deletions(-) delete mode 100644 lib/l10n/.gitignore delete mode 100644 lib/l10n/collect_translations.py delete mode 100644 lib/l10n/crowdin.yml delete mode 100644 lib/l10n/cs/app_cs.arb delete mode 100644 lib/l10n/de/app_de.arb delete mode 100644 lib/l10n/el/app_el.arb delete mode 100644 lib/l10n/es-419/app_es.arb delete mode 100644 lib/l10n/es-ES/app_es.arb delete mode 100644 lib/l10n/es-MX/app_es.arb delete mode 100644 lib/l10n/fa/app_fa.arb delete mode 100644 lib/l10n/fr/app_fr.arb delete mode 100644 lib/l10n/he/app_he.arb delete mode 100644 lib/l10n/hu/app_hu.arb delete mode 100644 lib/l10n/id/app_id.arb delete mode 100644 lib/l10n/it/app_it.arb delete mode 100644 lib/l10n/ja/app_ja.arb delete mode 100644 lib/l10n/ko/app_ko.arb delete mode 100644 lib/l10n/nl/app_nl.arb delete mode 100644 lib/l10n/no/app_no.arb delete mode 100644 lib/l10n/pl/app_pl.arb delete mode 100644 lib/l10n/pt-BR/app_pt.arb delete mode 100644 lib/l10n/pt-PT/app_pt.arb delete mode 100644 lib/l10n/ru/app_ru.arb delete mode 100644 lib/l10n/sv-SE/app_sv.arb delete mode 100644 lib/l10n/th/app_th.arb delete mode 100644 lib/l10n/tr/app_tr.arb delete mode 100644 lib/l10n/vi/app_vi.arb delete mode 100644 lib/l10n/zh-CN/app_zh.arb diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index d88e094..32aed76 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -32,10 +32,6 @@ jobs: uses: gradle/gradle-build-action@v2 with: gradle-version: 6.1.1 - - name: Collect Translations - run: | - cd lib/l10n - python3 collect_translations.py - name: Build for Android run: | flutter pub get diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 8f428ca..202c684 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -28,10 +28,6 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' - - name: Collect Translations - run: | - cd lib/l10n - python3 collect_translations.py - name: Build for iOS run: | flutter pub get diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index b199b27..a9d3fe7 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -31,10 +31,6 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' - - name: Collect Translations - run: | - cd lib/l10n - python3 collect_translations.py - run: flutter pub get - run: cp lib/dummy_dsn.dart lib/dsn.dart - run: flutter analyze diff --git a/l10n.yaml b/l10n.yaml index 7b9da73..a5b40b9 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,4 +1,4 @@ -arb-dir: lib/l10n/collected +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/.gitignore b/lib/l10n/.gitignore deleted file mode 100644 index 585ff49..0000000 --- a/lib/l10n/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore collected files -collected/ diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index 36d80aa..1aeae1d 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "cs", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 36d80aa..ec3b2b6 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1,5 +1,745 @@ { - "@@locale": "en", + "@@locale": "de", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Über", + "@about": {}, + "accountDetails": "Konto Details", + "@accountDetails": {}, + "actions": "Aktionen", + "@actions": { + "description": "" + }, + "actionsNone": "Keine Aktionen verfügbar", + "@actionsNone": {}, + "add": "Hinzufügen", + "@add": { + "description": "add" + }, + "addStock": "Bestand hinzufügen", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "Über InvenTree", + "@appAbout": {}, + "appCredits": "Weitere App-Danksagungen", + "@appCredits": {}, + "appDetails": "App-Informationen", + "@appDetails": {}, + "appReleaseNotes": "App-Versionshinweise anzeigen", + "@appReleaseNotes": {}, + "appSettings": "App-Einstellungen", + "@appSettings": {}, + "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", + "@appSettingsDetails": {}, + "attachments": "Anhänge", + "@attachments": {}, + "attachImage": "Bild hinzufügen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Keine Anhänge gefunden", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Anhang auswählen", + "@attachmentSelect": {}, + "attention": "Achtung", + "@attention": {}, + "availableStock": "Verfügbarer Lagerbestand", + "@availableStock": {}, + "barcodeAssign": "Barcode zuweisen", + "@barcodeAssign": {}, + "barcodeAssigned": "Barcode zugewiesen", + "@barcodeAssigned": {}, + "barcodeError": "Fehler beim Scannen des Barcodes", + "@barcodeError": {}, + "barcodeInUse": "Barcode wurde bereits zugewiesen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Prüfsumme fehlt in Antwort", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Keine Übereinstimmung für den Barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode nicht zugewiesen", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scannen um Barcode zuzuweisen", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Einen InvenTree Barcode scannen", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Artikel per Barcode-Scan zu Lagerort hinzufügen", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Lagerort scannen", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Artikel scannen", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode-Ton", + "@barcodeTones": {}, + "barcodeUnassign": "Barcode entfernen", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode wurde nicht erkannt", + "@barcodeUnknown": {}, + "batchCode": "Losnummer", + "@batchCode": {}, + "billOfMaterials": "Stückliste", + "@billOfMaterials": {}, + "bom": "Stückliste", + "@bom": {}, + "build": "Bauauftrag", + "@build": {}, + "building": "Gebäude", + "@building": {}, + "cancel": "Abbrechen", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategorie", + "@category": {}, + "categoryCreate": "Neue Kategorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Teile-Kategorie anlegen", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategorie aktualisiert", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Firma bearbeiten", + "@companyEdit": {}, + "companyNoResults": "Keine Firmen entsprechen der Anfrage", + "@companyNoResults": {}, + "companyUpdated": "Firmendetails aktualisiert", + "@companyUpdated": {}, + "companies": "Firmen", + "@companies": {}, + "configureServer": "Server-Einstellungen konfigurieren", + "@configureServer": {}, + "connectionRefused": "Verbindung verweigert", + "@connectionRefused": {}, + "count": "Zählen", + "@count": { + "description": "Count" + }, + "countStock": "Bestand zählen", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Danksagungen", + "@credits": {}, + "customers": "Kunden", + "@customers": {}, + "damaged": "Beschädigt", + "@damaged": {}, + "delete": "Löschen", + "@delete": {}, + "deletePart": "Teil löschen", + "@deletePart": {}, + "deletePartDetail": "Dieses Teil aus der Datenbank löschen", + "@deletePartDetail": {}, + "description": "Beschreibung", + "@description": {}, + "destroyed": "Vernichtet", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloading": "Datei wird heruntergeladen", + "@downloading": {}, + "downloadError": "Fehler beim Herunterladen", + "@downloadError": {}, + "edit": "Bearbeiten", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategorie bearbeiten", + "@editCategory": {}, + "editLocation": "Ort bearbeiten", + "@editLocation": {}, + "editNotes": "Notizen bearbeiten", + "@editNotes": {}, + "editPart": "Teil bearbeiten", + "@editPart": { + "description": "edit part" + }, + "editItem": "Artikel bearbeiten", + "@editItem": {}, + "enterPassword": "Passwort eingeben", + "@enterPassword": {}, + "enterUsername": "Benutzername eingeben", + "@enterUsername": {}, + "error": "Fehler", + "@error": { + "description": "Error" + }, + "errorCreate": "Fehler beim Erstellen des Datenbankeintrages", + "@errorCreate": {}, + "errorDelete": "Fehler beim Löschen von Datenbankeintrag", + "@errorDelete": {}, + "errorDetails": "Fehlerdetails", + "@errorDetails": {}, + "errorFetch": "Fehler beim Abrufen der Daten vom Server", + "@errorFetch": {}, + "errorReporting": "Fehlerberichterstattung", + "@errorReporting": {}, + "errorReportUpload": "Fehlerberichte hochladen", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fehler beim Senden des Feedbacks", + "@feedbackError": {}, + "feedbackSuccess": "Feedback gesendet", + "@feedbackSuccess": {}, + "formatException": "Formatfehler", + "@formatException": {}, + "formatExceptionJson": "Format-Fehler im JSON", + "@formatExceptionJson": {}, + "formError": "Formular-Fehler", + "@formError": {}, + "history": "Verlauf", + "@history": { + "description": "history" + }, + "homeScreen": "Startseite", + "@homeScreen": {}, + "homeScreenSettings": "Einstellungen für Startseite konfigurieren", + "@homeScreenSettings": {}, + "homeShowPo": "Bestellungen anzeigen", + "@homeShowPo": {}, + "homeShowSubscribed": "Abonnierte Teile", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Lieferanten anzeigen", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Hersteller anzeigen", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Hersteller auf Startseite anzeigen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Kunden anzeigen", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Kunden auf Startseite anzeigen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Das Bild konnte nicht hochgeladen werden", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Bild hochgeladen", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveDetail": "Teil als inaktiv gekennzeichnet", + "@inactiveDetail": {}, + "includeSubcategories": "Unter-Kategorien einschließen", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Teile aus Unter-Kategorien anzeigen", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Unter-Lagerorte einschließen", + "@includeSublocations": {}, + "includeSublocationsDetail": "Liste der Unter-Lagerorte anzeigen", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil unvollständig", + "@incompleteDetails": {}, + "internalPartNumber": "Interne Teilenummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Produktion", + "@inProduction": {}, + "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", + "@inProductionDetail": {}, + "invalidHost": "Ungültiger Hostname", + "@invalidHost": {}, + "invalidHostDetails": "Der angegebener Hostname ist ungültig", + "@invalidHostDetails": {}, + "invalidPart": "Ungültiges Teil", + "@invalidPart": {}, + "invalidPartCategory": "Ungültige Teil-Kategorie", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ungültiger Lagerort", + "@invalidStockLocation": {}, + "invalidStockItem": "Ungültiger Artikel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", + "@invalidUsernamePassword": {}, + "issueDate": "Ausstellungsdatum", + "@issueDate": {}, + "itemInLocation": "Artikel ist bereits in diesem Lagerort", + "@itemInLocation": {}, + "keywords": "Schlüsselwörter", + "@keywords": {}, + "lastStocktake": "Letzte Inventur", + "@lastStocktake": {}, + "lastUpdated": "Letzte Änderung", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Positionen", + "@lineItems": {}, + "locationCreate": "Neuer Lagerort", + "@locationCreate": {}, + "locationCreateDetail": "Neuen Lagerort erstellen", + "@locationCreateDetail": {}, + "locationNotSet": "Lagerort nicht angegeben", + "@locationNotSet": {}, + "locationUpdated": "Lagerort aktualisiert", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "manufacturers": "Hersteller", + "@manufacturers": {}, + "missingData": "Fehlende Daten", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Nicht verbunden", + "@notConnected": {}, + "notes": "Notizen", + "@notes": { + "description": "Notes" + }, + "noResponse": "Keine Antwort vom Server", + "@noResponse": {}, + "noResults": "Keine Ergebnisse", + "@noResults": {}, + "noSubcategories": "Keine Unter-Kategorien", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Keine gültige Zahl", + "@numberInvalid": {}, + "onOrder": "Bestellt", + "@onOrder": {}, + "onOrderDetails": "Artikel wurde bestellt", + "@onOrderDetails": {}, + "packaging": "Paket", + "@packaging": {}, + "packageName": "Paket-Name", + "@packageName": {}, + "parent": "Übergeordnetes", + "@parent": {}, + "parentCategory": "Übergeordnete Kategorie", + "@parentCategory": {}, + "parentLocation": "Übergeordneter Lagerort", + "@parentLocation": {}, + "part": "Teil", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Teil anlegen", + "@partCreate": {}, + "partCreateDetail": "Teil in dieser Kategorie anlegen", + "@partCreateDetail": {}, + "partEdited": "Teil aktualisiert", + "@partEdited": {}, + "parts": "Teile", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Keine Teile", + "@partsNone": {}, + "partNoResults": "Keine Teile entsprechen der Anfrage", + "@partNoResults": {}, + "partsStarred": "Abonnierte Teile", + "@partsStarred": {}, + "partsStarredNone": "Keine Teile abonniert", + "@partsStarredNone": {}, + "partSuppliers": "Teile-Lieferanten", + "@partSuppliers": {}, + "partCategory": "Teil-Kategorie", + "@partCategory": {}, + "partCategoryTopLevel": "Oberste Teile-Kategorie", + "@partCategoryTopLevel": {}, + "partCategories": "Teil-Kategorien", + "@partCategories": {}, + "partDetails": "Teil-Details", + "@partDetails": {}, + "partNotes": "Teil-Bemerkungen", + "@partNotes": {}, + "partStock": "Teilbestand", + "@partStock": { + "description": "part stock" + }, + "password": "Passwort", + "@password": {}, + "passwordEmpty": "Passwort darf nicht leer sein", + "@passwordEmpty": {}, + "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", + "@permissionAccountDenied": {}, + "permissionRequired": "Berechtigung erforderlich", + "@permissionRequired": {}, + "printLabel": "Label drucken", + "@printLabel": {}, + "printLabelFailure": "Labeldruck fehlgeschlagen", + "@printLabelFailure": {}, + "printLabelSuccess": "Label an den Drucker gesendet", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Server-Profil anlegen", + "@profileAdd": {}, + "profileConnect": "Mit Server verbinden", + "@profileConnect": {}, + "profileEdit": "Server-Profil bearbeiten", + "@profileEdit": {}, + "profileDelete": "Server-Profil löschen", + "@profileDelete": {}, + "profileName": "Profil-Name", + "@profileName": {}, + "profileNone": "Keine Profile angelegt", + "@profileNone": {}, + "profileNotSelected": "Kein Profil ausgewählt", + "@profileNotSelected": {}, + "profileSelect": "InvenTree-Server auswählen", + "@profileSelect": {}, + "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", + "@profileTapToCreate": {}, + "purchaseOrder": "Bestellung", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Bestellung bearbeiten", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Bestellungen", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bestellung aktualisiert", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Einkaufspreis", + "@purchasePrice": {}, + "quantity": "Anzahl", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Menge ist leer", + "@quantityEmpty": {}, + "quantityInvalid": "Menge ist ungültig", + "@quantityInvalid": {}, + "quantityPositive": "Menge muss positiv sein", + "@quantityPositive": {}, + "queryNoResults": "Keine Ergebnisse für die Anfrage", + "@queryNoResults": {}, + "received": "Empfangen", + "@received": {}, + "receiveItem": "Artikel erhalten", + "@receiveItem": {}, + "receivedItem": "Artikel wurde erhalten", + "@receivedItem": {}, + "refresh": "Neu laden", + "@refresh": {}, + "refreshing": "Aktualisiere", + "@refreshing": {}, + "rejected": "Zurückgewiesen", + "@rejected": {}, + "releaseNotes": "Versionshinweise", + "@releaseNotes": {}, + "remove": "Entfernen", + "@remove": { + "description": "remove" + }, + "removeStock": "Bestand entfernen", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Fehler melden", + "@reportBug": {}, + "reportBugDescription": "Fehlerbericht senden (erfordert GitHub Konto)", + "@reportBugDescription": {}, + "results": "Ergebnisse", + "@results": {}, + "request": "Anfrage", + "@request": {}, + "requestingData": "Daten werden angefordert", + "@requestingData": {}, + "required": "Erforderlich", + "@required": { + "description": "This field is required" + }, + "response400": "Ungültige Anfrage", + "@response400": {}, + "response401": "Nicht autorisiert", + "@response401": {}, + "response403": "Zugriff verweigert", + "@response403": {}, + "response404": "Ressource nicht gefunden", + "@response404": {}, + "response405": "Methode nicht erlaubt", + "@response405": {}, + "response429": "Zu viele Anfragen", + "@response429": {}, + "response500": "Interner Serverfehler", + "@response500": {}, + "response501": "Nicht Implementiert", + "@response501": {}, + "response502": "Fehlerhaftes Gateway", + "@response502": {}, + "response503": "Dienst nicht verfügbar", + "@response503": {}, + "response504": "Gateway-Zeitüberschreitung", + "@response504": {}, + "response505": "HTTP-Version wird nicht unterstützt", + "@response505": {}, + "responseData": "Antwort-Daten", + "@responseData": {}, + "responseInvalid": "Ungültiger Antwort-Code", + "@responseInvalid": {}, + "responseUnknown": "Unbekannte Antwort", + "@responseUnknown": {}, + "result": "Ergebnis", + "@result": { + "description": "" + }, + "returned": "Retourniert", + "@returned": {}, + "salesOrders": "Kundenauftrag", + "@salesOrders": {}, + "save": "Speichern", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barcode scannen", + "@scanBarcode": {}, + "scanIntoLocation": "In Lagerorten buchen", + "@scanIntoLocation": {}, + "search": "Suchen", + "@search": { + "description": "search" + }, + "searchLocation": "Lagerort suchen", + "@searchLocation": {}, + "searchParts": "Teile suchen", + "@searchParts": {}, + "searchStock": "Bestand durchsuchen", + "@searchStock": {}, + "select": "Auswählen", + "@select": {}, + "selectFile": "Datei auswählen", + "@selectFile": {}, + "selectImage": "Bild auswählen", + "@selectImage": {}, + "selectLocation": "Wähle einen Lagerort", + "@selectLocation": {}, + "send": "Senden", + "@send": {}, + "serialNumber": "Seriennummer", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradresse", + "@serverAddress": {}, + "serverApiRequired": "Erforderliche API-Version", + "@serverApiRequired": {}, + "serverApiVersion": "API-Version des Servers", + "@serverApiVersion": {}, + "serverAuthenticationError": "Anmeldung fehlgeschlagen", + "@serverAuthenticationError": {}, + "serverCertificateError": "Zertifikatsfehler", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Zertifikat des Servers ist ungültig", + "@serverCertificateInvalid": {}, + "serverConnected": "Verbunden mit Server", + "@serverConnected": {}, + "serverConnecting": "Verbindung zum Server wird aufgebaut", + "@serverConnecting": {}, + "serverCouldNotConnect": "Verbindung zum Server nicht möglich", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server darf nicht leer sein", + "@serverEmpty": {}, + "serverError": "Serverfehler", + "@serverError": {}, + "serverDetails": "Serverdetails", + "@serverDetails": {}, + "serverMissingData": "In der Server-Antwort fehlen erforderliche Felder", + "@serverMissingData": {}, + "serverOld": "Alte Server Version", + "@serverOld": {}, + "serverSettings": "Server Einstellungen", + "@serverSettings": {}, + "serverStart": "Server muss mit http[s] beginnen", + "@serverStart": {}, + "settings": "Einstellungen", + "@settings": {}, + "serverInstance": "Server Instanz", + "@serverInstance": {}, + "serverNotConnected": "Server nicht verbunden", + "@serverNotConnected": {}, + "sounds": "Töne", + "@sounds": {}, + "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Ton bei Serverfehler abspielen", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuscode", + "@statusCode": {}, + "stock": "Bestand", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktuell verfügbare Lagermenge", + "@stockDetails": {}, + "stockItem": "Artikel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Artikel", + "@stockItems": {}, + "stockItemCreate": "Neuen Artikel anlegen", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Neuen Artikel an diesem Lagerort erstellen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Lagerartikel löschen", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Sind Sie sicher, dass Sie diesen Lagerartikel löschen wollen?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Lagerbestand konnte nicht gelöscht werden", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagerbestand gelöscht", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historie des Artikels", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Zeige historische Bestandsverfolgungsdaten", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Artikel umgezogen", + "@stockItemTransferred": {}, + "stockItemUpdated": "Artikel aktualisiert", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Keine Artikel verfügbar", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notizen zum Artikel", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Artikel aktualisiert", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Fehler bei Artikel-Aktualisierung", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerort", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerorte", + "@stockLocations": {}, + "stockTopLevel": "Oberster Lagerort", + "@stockTopLevel": {}, + "strictHttps": "Striktes HTTPS verwenden", + "@strictHttps": {}, + "strictHttpsDetails": "Erzwinge strenge Überprüfung von HTTPs-Zertifikaten", + "@strictHttpsDetails": {}, + "subcategory": "Unterkategorie", + "@subcategory": {}, + "subcategories": "Unterkategorien", + "@subcategories": {}, + "sublocation": "Unter-Lagerort", + "@sublocation": {}, + "sublocations": "Unter-Lagerorte", + "@sublocations": {}, + "sublocationNone": "Keine Unter-Lagerorte", + "@sublocationNone": {}, + "sublocationNoneDetail": "Keine Unter-Lagerorte verfügbar", + "@sublocationNoneDetail": {}, + "submitFeedback": "Feedback geben", + "@submitFeedback": {}, + "suppliedParts": "Gelieferte Teile", + "@suppliedParts": {}, + "supplier": "Lieferant", + "@supplier": {}, + "suppliers": "Lieferanten", + "@suppliers": {}, + "supplierReference": "Lieferanten-Referenz", + "@supplierReference": {}, + "takePicture": "Foto aufnehmen", + "@takePicture": {}, + "targetDate": "Zieldatum", + "@targetDate": {}, + "templatePart": "Übergeordnetes Vorlagenteil", + "@templatePart": {}, + "testName": "Test-Name", + "@testName": {}, + "testPassedOrFailed": "Test erfolgreich oder fehlgeschlagen", + "@testPassedOrFailed": {}, + "testsRequired": "Erforderliche Tests", + "@testsRequired": {}, + "testResults": "Testergebnisse", + "@testResults": { + "description": "" + }, + "testResultAdd": "Testergebnis hinzufügen", + "@testResultAdd": {}, + "testResultNone": "Keine Testergebnisse", + "@testResultNone": {}, + "testResultNoneDetail": "Keine Testergebnisse vorhanden", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fehler beim Hochladen des Testergebnisses", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testergebnis hochgeladen", + "@testResultUploadPass": {}, + "timeout": "Zeitüberschreitung", + "@timeout": { + "description": "" + }, + "tokenError": "Token-Fehler", + "@tokenError": {}, + "tokenMissing": "Token fehlt", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", + "@tokenMissingFromResponse": {}, + "transfer": "Verschieben", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Bestand verschieben", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Übersetzen", + "@translate": {}, + "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", + "@translateHelp": {}, + "units": "Einheiten", + "@units": {}, + "unknownResponse": "Unbekannte Antwort", + "@unknownResponse": {}, + "upload": "Hochladen", + "@upload": {}, + "uploadFailed": "Datei hochladen fehlgeschlagen", + "@uploadFailed": {}, + "uploadSuccess": "Datei hochgeladen", + "@uploadSuccess": {}, + "usedIn": "Verwendet in", + "@usedIn": {}, + "usedInDetails": "Baugruppen, die dieses Teil benötigen", + "@usedInDetails": {}, + "username": "Benutzername", + "@username": {}, + "usernameEmpty": "Der Benutzername darf nicht leer sein", + "@usernameEmpty": {}, + "value": "Wert", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Dieser Wert darf nicht leer sein", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wert erforderlich", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Zulieferer-Teil anzeigen", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_el.arb b/lib/l10n/app_el.arb index 36d80aa..2ae9e43 100644 --- a/lib/l10n/app_el.arb +++ b/lib/l10n/app_el.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "el", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 36d80aa..17a7a62 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,5 +1,17 @@ { - "@@locale": "en", + "@@locale": "es", + "barcodeScanInItems": "Escanear artículos de stock en su ubicación", + "@barcodeScanInItems": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", + "@includeSublocationsDetail": {}, + "lineItems": "Ítems de línea", + "@lineItems": {}, + "onOrderDetails": "Artículos actualmente en pedido", + "@onOrderDetails": {}, + "stockItems": "Elementos de stock", + "@stockItems": {}, + "stockItemsNotAvailable": "No hay artículos de stock disponibles", + "@stockItemsNotAvailable": {} } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 36d80aa..f17cd61 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "fa", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 36d80aa..b4ded9e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1,5 +1,743 @@ { - "@@locale": "en", + "@@locale": "fr", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "À propos", + "@about": {}, + "accountDetails": "Détails du compte", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "Aucune action disponible", + "@actionsNone": {}, + "add": "Ajouter", + "@add": { + "description": "add" + }, + "addStock": "Ajouter un stock", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "À propos d'InvenTree", + "@appAbout": {}, + "appCredits": "Crédits d'application supplémentaires", + "@appCredits": {}, + "appDetails": "Détails de l'application", + "@appDetails": {}, + "appReleaseNotes": "Afficher les notes de version de l'application", + "@appReleaseNotes": {}, + "appSettings": "Réglages de l'application", + "@appSettings": {}, + "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", + "@appSettingsDetails": {}, + "attachments": "Pieces jointes", + "@attachments": {}, + "attachImage": "Ajouter une image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Aucune pièce jointe trouvée", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Sélectionner une pièce jointe", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "availableStock": "Stock disponible", + "@availableStock": {}, + "barcodeAssign": "Affecter un code-barres", + "@barcodeAssign": {}, + "barcodeAssigned": "Code-barres affecté", + "@barcodeAssigned": {}, + "barcodeError": "Erreur lors du scan du code-barres", + "@barcodeError": {}, + "barcodeInUse": "Le code-barres est déjà en cours d’utilisation", + "@barcodeInUse": {}, + "barcodeMissingHash": "Les données de hachage du code-barres sont manquantes dans la réponse", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Pas de correspondance pour ce code-barres", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Code-barres non assigné", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scanner pour attribuer un code-barres", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scanner un code-barres InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scannez les items de stock à l'emplacement", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scanner la localisation du stock", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item non scanné dans", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scanner l'article en stock", + "@barcodeScanItem": {}, + "barcodeTones": "Types de code-barre", + "@barcodeTones": {}, + "barcodeUnassign": "Désaffecter le code-barres", + "@barcodeUnassign": {}, + "barcodeUnknown": "Code-barres non reconnu", + "@barcodeUnknown": {}, + "batchCode": "Code de lot", + "@batchCode": {}, + "billOfMaterials": "Liste des matériaux", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Assemblage", + "@build": {}, + "building": "Assemblage en cours", + "@building": {}, + "cancel": "Annuler", + "@cancel": { + "description": "Cancel" + }, + "category": "Catégorie", + "@category": {}, + "categoryCreate": "Nouvelle catégorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Créer une nouvelle catégorie de pièce", + "@categoryCreateDetail": {}, + "categoryUpdated": "Catégorie de pièce mise à jour", + "@categoryUpdated": {}, + "company": "Société", + "@company": {}, + "companyEdit": "Modifier la société", + "@companyEdit": {}, + "companyNoResults": "Aucune société ne correspond à la requête", + "@companyNoResults": {}, + "companyUpdated": "Détails de la société mis à jour", + "@companyUpdated": {}, + "companies": "Sociétés", + "@companies": {}, + "configureServer": "Configurer les paramètres serveur", + "@configureServer": {}, + "connectionRefused": "Connexion refusée", + "@connectionRefused": {}, + "count": "Nombre", + "@count": { + "description": "Count" + }, + "countStock": "Nombre de stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Crédits", + "@credits": {}, + "customers": "Clients", + "@customers": {}, + "damaged": "Endommagé", + "@damaged": {}, + "delete": "Supprimer", + "@delete": {}, + "deletePart": "Supprimer la pièce", + "@deletePart": {}, + "deletePartDetail": "Supprimer cette pièce de la base de données", + "@deletePartDetail": {}, + "description": "Description", + "@description": {}, + "destroyed": "Détruit", + "@destroyed": {}, + "details": "Détails", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Téléchargement du fichier", + "@downloading": {}, + "downloadError": "Erreur lors du téléchargement", + "@downloadError": {}, + "edit": "Modifier", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifier la catégorie", + "@editCategory": {}, + "editLocation": "Modifier l’emplacement", + "@editLocation": {}, + "editNotes": "Modifier les notes", + "@editNotes": {}, + "editPart": "Modifier la pièce", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editer l'article en stock", + "@editItem": {}, + "enterPassword": "Saisissez le mot de passe", + "@enterPassword": {}, + "enterUsername": "Saisissez le nom d'utilisateur", + "@enterUsername": {}, + "error": "Erreur", + "@error": { + "description": "Error" + }, + "errorCreate": "Erreur lors de la création de l'entrée de la base de données", + "@errorCreate": {}, + "errorDelete": "Erreur lors de la suppression de l'entrée de la base de données", + "@errorDelete": {}, + "errorDetails": "Détails de l'erreur", + "@errorDetails": {}, + "errorFetch": "Erreur de récupération des données du serveur", + "@errorFetch": {}, + "errorReporting": "Rapport d'erreur", + "@errorReporting": {}, + "errorReportUpload": "Envoyer le rapport d 'erreur", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", + "@errorReportUploadDetails": {}, + "feedback": "Donner votre avis", + "@feedback": {}, + "feedbackError": "Erreur lors de l'envoi du commentaire", + "@feedbackError": {}, + "feedbackSuccess": "Commentaire envoyé", + "@feedbackSuccess": {}, + "formatException": "Exception de format", + "@formatException": {}, + "formatExceptionJson": "Exception de format de données JSON", + "@formatExceptionJson": {}, + "formError": "Erreur de formulaire", + "@formError": {}, + "history": "Historique", + "@history": { + "description": "history" + }, + "homeScreen": "Ecran d'accueil", + "@homeScreen": {}, + "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", + "@homeScreenSettings": {}, + "homeShowPo": "Afficher les commandes d'achat", + "@homeShowPo": {}, + "homeShowSubscribed": "Pièces suivies", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Afficher les fournisseurs", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Afficher les fabriquants", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Afficher le bouton fabriquant sur l'écran d'accueil", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Afficher les clients", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Afficher le bouton clients sur l'écran d'accueil", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Échec de l'envoi de l'image", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image transférée", + "@imageUploadSuccess": {}, + "inactive": "Inactif", + "@inactive": {}, + "inactiveDetail": "Cette pièce est marquée comme inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Inclure les sous-catégories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Afficher les sous-catégories dans la vue liste", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclure les sous-emplacements", + "@includeSublocations": {}, + "includeSublocationsDetail": "Afficher les sous-emplacements des articles dans la vue liste", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil incomplet", + "@incompleteDetails": {}, + "internalPartNumber": "Numéro de pièce interne", + "@internalPartNumber": {}, + "info": "Information", + "@info": {}, + "inProduction": "En production", + "@inProduction": {}, + "inProductionDetail": "Cet article de stock est en production", + "@inProductionDetail": {}, + "invalidHost": "Nom d’hôte invalide", + "@invalidHost": {}, + "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", + "@invalidHostDetails": {}, + "invalidPart": "Article non valide", + "@invalidPart": {}, + "invalidPartCategory": "Catégorie d'article invalide", + "@invalidPartCategory": {}, + "invalidStockLocation": "Emplacement invalide", + "@invalidStockLocation": {}, + "invalidStockItem": "Article en stock non valide", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", + "@invalidUsernamePassword": {}, + "issueDate": "Date d'émission", + "@issueDate": {}, + "itemInLocation": "Article déjà dans l'emplacement", + "@itemInLocation": {}, + "keywords": "Mots clés", + "@keywords": {}, + "lastStocktake": "Dernier inventaire", + "@lastStocktake": {}, + "lastUpdated": "Dernière mise à jour", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Position", + "@lineItems": {}, + "locationCreate": "Nouvel emplacement", + "@locationCreate": {}, + "locationCreateDetail": "Créer un nouvel emplacement de stock", + "@locationCreateDetail": {}, + "locationNotSet": "Aucun emplacement spécifié", + "@locationNotSet": {}, + "locationUpdated": "Emplacement du stock mis à jour", + "@locationUpdated": {}, + "link": "Lien", + "@link": {}, + "lost": "Perdu", + "@lost": {}, + "manufacturers": "Fabricants", + "@manufacturers": {}, + "missingData": "Données manquantes", + "@missingData": {}, + "name": "Nom", + "@name": {}, + "notConnected": "Non connecté", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "noResponse": "Aucune réponse du serveur", + "@noResponse": {}, + "noResults": "Aucun résultat", + "@noResults": {}, + "noSubcategories": "Pas de sous-catégorie", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nombre invalide", + "@numberInvalid": {}, + "onOrder": "Sur Commande", + "@onOrder": {}, + "onOrderDetails": "Articles en cours de commande", + "@onOrderDetails": {}, + "packaging": "Emballage", + "@packaging": {}, + "packageName": "Nom du package", + "@packageName": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Catégorie parent", + "@parentCategory": {}, + "parentLocation": "Emplacement parent", + "@parentLocation": {}, + "part": "Pièce", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nouvelle pièce", + "@partCreate": {}, + "partCreateDetail": "Créer une nouvelle pièce dans cette catégorie", + "@partCreateDetail": {}, + "partEdited": "Pièce mise à jour", + "@partEdited": {}, + "parts": "Pièces", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Aucune pièces", + "@partsNone": {}, + "partNoResults": "Pas de pièces correspondant à la requête", + "@partNoResults": {}, + "partsStarred": "Pièces suivies", + "@partsStarred": {}, + "partsStarredNone": "Aucune pièce favorite disponible", + "@partsStarredNone": {}, + "partSuppliers": "Fournisseurs de pièces", + "@partSuppliers": {}, + "partCategory": "Catégorie de la pièce", + "@partCategory": {}, + "partCategoryTopLevel": "Catégorie de pièce parente", + "@partCategoryTopLevel": {}, + "partCategories": "Catégories de pièce", + "@partCategories": {}, + "partDetails": "Détails de la pièce", + "@partDetails": {}, + "partNotes": "Notes de la pièce", + "@partNotes": {}, + "partStock": "Stock de la pièce", + "@partStock": { + "description": "part stock" + }, + "password": "Mot de passe", + "@password": {}, + "passwordEmpty": "Le mot de passe peut pas être vide", + "@passwordEmpty": {}, + "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorisation requise", + "@permissionRequired": {}, + "printLabel": "Imprimer l'étiquette", + "@printLabel": {}, + "printLabelFailure": "Echec de l'impression", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiquette envoyée à l'imprimante", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Ajouter un profil serveur", + "@profileAdd": {}, + "profileConnect": "Se connecter au serveur", + "@profileConnect": {}, + "profileEdit": "Editer le profil du serveur", + "@profileEdit": {}, + "profileDelete": "Supprimer le profil du serveur", + "@profileDelete": {}, + "profileName": "Nom du profil", + "@profileName": {}, + "profileNone": "Aucun profil disponible", + "@profileNone": {}, + "profileNotSelected": "Aucun profil sélectionné", + "@profileNotSelected": {}, + "profileSelect": "Sélectionner le serveur InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Commande d’achat", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifier la commande d'achat", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Commandes d'achat", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bon de commande mis à jour", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Prix d'achat", + "@purchasePrice": {}, + "quantity": "Quantité", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "La quantité est vide", + "@quantityEmpty": {}, + "quantityInvalid": "La quantité n'est pas valide", + "@quantityInvalid": {}, + "quantityPositive": "La quantité doit être positive", + "@quantityPositive": {}, + "queryNoResults": "Pas de résultat pour votre requête", + "@queryNoResults": {}, + "received": "Reçu", + "@received": {}, + "receiveItem": "Articles reçus", + "@receiveItem": {}, + "receivedItem": "Article de stock reçu", + "@receivedItem": {}, + "refresh": "Actualiser", + "@refresh": {}, + "refreshing": "Actualisation en cours", + "@refreshing": {}, + "rejected": "Rejeté", + "@rejected": {}, + "releaseNotes": "Notes de Version", + "@releaseNotes": {}, + "remove": "Supprimer", + "@remove": { + "description": "remove" + }, + "removeStock": "Supprimer le stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Signaler un bug", + "@reportBug": {}, + "reportBugDescription": "Envoyer un rapport de bug (nécessite un compte GitHub)", + "@reportBugDescription": {}, + "results": "Résultats", + "@results": {}, + "request": "Requête", + "@request": {}, + "requestingData": "Demande de données", + "@requestingData": {}, + "required": "Requis", + "@required": { + "description": "This field is required" + }, + "response400": "Mauvaise requête", + "@response400": {}, + "response401": "Non autorisé", + "@response401": {}, + "response403": "Autorisation refusée", + "@response403": {}, + "response404": "Ressource non trouvée", + "@response404": {}, + "response405": "Méthode non autorisé", + "@response405": {}, + "response429": "Trop de requêtes", + "@response429": {}, + "response500": "Erreur interne du serveur", + "@response500": {}, + "response501": "Non implémenté", + "@response501": {}, + "response502": "Mauvaise passerelle", + "@response502": {}, + "response503": "Service indisponible", + "@response503": {}, + "response504": "Délai d'attente de la passerelle expiré", + "@response504": {}, + "response505": "Version HTTP non prise en charge", + "@response505": {}, + "responseData": "Données de la réponse", + "@responseData": {}, + "responseInvalid": "Code de réponse invalide", + "@responseInvalid": {}, + "responseUnknown": "Réponse inconnue", + "@responseUnknown": {}, + "result": "Résultat ", + "@result": { + "description": "" + }, + "returned": "Retourné", + "@returned": {}, + "salesOrders": "Ventes", + "@salesOrders": {}, + "save": "Enregistrer", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanner un code-barres", + "@scanBarcode": {}, + "scanIntoLocation": "Scanner vers l'emplacement", + "@scanIntoLocation": {}, + "search": "Rechercher", + "@search": { + "description": "search" + }, + "searchLocation": "Rechercher un emplacement", + "@searchLocation": {}, + "searchParts": "Rechercher de pièces", + "@searchParts": {}, + "searchStock": "Rechercher un stock", + "@searchStock": {}, + "select": "Sélectionner", + "@select": {}, + "selectFile": "Sélectionner un fichier", + "@selectFile": {}, + "selectImage": "Sélectionner une image", + "@selectImage": {}, + "selectLocation": "Sélectionnez un emplacement", + "@selectLocation": {}, + "send": "Envoyer", + "@send": {}, + "serialNumber": "Numéro de série", + "@serialNumber": {}, + "server": "Serveur", + "@server": {}, + "serverAddress": "Adresse du serveur", + "@serverAddress": {}, + "serverApiRequired": "Version de l'API requise", + "@serverApiRequired": {}, + "serverApiVersion": "Version de l'API du serveur", + "@serverApiVersion": {}, + "serverAuthenticationError": "Erreur lors de l'authentification", + "@serverAuthenticationError": {}, + "serverCertificateError": "Erreur de certificat", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Le certificat HTTPS du serveur n'est pas valide", + "@serverCertificateInvalid": {}, + "serverConnected": "Connecté au serveur", + "@serverConnected": {}, + "serverConnecting": "Connexion au serveur", + "@serverConnecting": {}, + "serverCouldNotConnect": "Connexion au serveur impossible", + "@serverCouldNotConnect": {}, + "serverEmpty": "Le serveur ne peut pas être vide", + "@serverEmpty": {}, + "serverError": "Erreur serveur", + "@serverError": {}, + "serverDetails": "Détails du serveur", + "@serverDetails": {}, + "serverMissingData": "La réponse du serveur ne possède pas les champs obligatoires", + "@serverMissingData": {}, + "serverOld": "Ancienne version du serveur", + "@serverOld": {}, + "serverSettings": "Paramètres du serveur", + "@serverSettings": {}, + "serverStart": "Le serveur doit débuter par http[s]", + "@serverStart": {}, + "settings": "Réglages", + "@settings": {}, + "serverInstance": "Instance du serveur", + "@serverInstance": {}, + "serverNotConnected": "Le serveur n'est pas connecté", + "@serverNotConnected": {}, + "sounds": "Sons", + "@sounds": {}, + "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Jouer une tonalité sonore en cas d'erreur du serveur", + "@soundOnServerError": {}, + "status": "État", + "@status": {}, + "statusCode": "Code d'état", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Quantité actuelle de stock disponible", + "@stockDetails": {}, + "stockItem": "Article en stock", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Articles en stock", + "@stockItems": {}, + "stockItemCreate": "Nouvel article en stock", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Créer un nouvel article en stock dans cet emplacement", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Supprimer l'article du stock", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Êtes-vous certain de vouloir supprimer cet article ?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Impossible de supprmer cet article", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Article supprimé", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historique du stock", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Afficher les informations de suivi de stock", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Article en stock transféré", + "@stockItemTransferred": {}, + "stockItemUpdated": "Article en stock mis à jour", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Aucun article en stock", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notes de l'article en stock", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Article en stock mis à jour", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Echec de la mise à jour de l'article en stock", + "@stockItemUpdateFailure": {}, + "stockLocation": "Emplacement du stock", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Emplacements du stock", + "@stockLocations": {}, + "stockTopLevel": "Emplacement de stock de premier niveau", + "@stockTopLevel": {}, + "strictHttps": "Utiliser HTTPS strict", + "@strictHttps": {}, + "strictHttpsDetails": "Obliger une vérification stricte des certificats HTTP", + "@strictHttpsDetails": {}, + "subcategory": "Sous-catégorie", + "@subcategory": {}, + "subcategories": "Sous-catégories", + "@subcategories": {}, + "sublocation": "Sous-emplacement", + "@sublocation": {}, + "sublocations": "Sous-emplacements", + "@sublocations": {}, + "sublocationNone": "Aucun sous-emplacement", + "@sublocationNone": {}, + "sublocationNoneDetail": "Aucun sous-emplacement disponible", + "@sublocationNoneDetail": {}, + "submitFeedback": "Soumettre le commentaire", + "@submitFeedback": {}, + "suppliedParts": "Composants fournis", + "@suppliedParts": {}, + "supplier": "Fournisseur", + "@supplier": {}, + "suppliers": "Fournisseurs", + "@suppliers": {}, + "supplierReference": "Référence du fournisseur", + "@supplierReference": {}, + "takePicture": "Prendre une photo", + "@takePicture": {}, + "targetDate": "Date Cible", + "@targetDate": {}, + "testName": "Nom de test", + "@testName": {}, + "testPassedOrFailed": "Test réussi ou échoué", + "@testPassedOrFailed": {}, + "testsRequired": "Tests requis", + "@testsRequired": {}, + "testResults": "Résultats du test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Ajouter un résultat de test", + "@testResultAdd": {}, + "testResultNone": "Aucun résultat de test", + "@testResultNone": {}, + "testResultNoneDetail": "Aucun résultat de test disponible", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Erreur lors de l'envoi du résultat du test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Résultats du test chargés", + "@testResultUploadPass": {}, + "timeout": "Délai dépassé", + "@timeout": { + "description": "" + }, + "tokenError": "Erreur du jeton", + "@tokenError": {}, + "tokenMissing": "Jeton manquant", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", + "@tokenMissingFromResponse": {}, + "transfer": "Transfert", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transférer le stock", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Traduire", + "@translate": {}, + "translateHelp": "Aidez à traduire l'application InvenTree", + "@translateHelp": {}, + "units": "Unités", + "@units": {}, + "unknownResponse": "Réponse inconnue", + "@unknownResponse": {}, + "upload": "Importer le fichier", + "@upload": {}, + "uploadFailed": "Échec du chargement du fichier", + "@uploadFailed": {}, + "uploadSuccess": "Fichier transféré", + "@uploadSuccess": {}, + "usedIn": "Utilisé dans", + "@usedIn": {}, + "usedInDetails": "Assemblages qui requièrent ce composant", + "@usedInDetails": {}, + "username": "Nom d'utilisateur", + "@username": {}, + "usernameEmpty": "Le nom d'utilisateur peut pas être vide", + "@usernameEmpty": {}, + "value": "Valeur", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "La valeur ne peut pas être vide", + "@valueCannotBeEmpty": {}, + "valueRequired": "La valeur est requise", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Voir la pièce du fournisseur", + "@viewSupplierPart": {}, + "website": "Site web", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_he.arb b/lib/l10n/app_he.arb index 36d80aa..2d1bbf1 100644 --- a/lib/l10n/app_he.arb +++ b/lib/l10n/app_he.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "he", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_hu.arb b/lib/l10n/app_hu.arb index 36d80aa..98a69b4 100644 --- a/lib/l10n/app_hu.arb +++ b/lib/l10n/app_hu.arb @@ -1,5 +1,745 @@ { - "@@locale": "en", + "@@locale": "hu", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Névjegy", + "@about": {}, + "accountDetails": "Felhasználó adatok", + "@accountDetails": {}, + "actions": "Műveletek", + "@actions": { + "description": "" + }, + "actionsNone": "Nincsenek műveletek", + "@actionsNone": {}, + "add": "Hozzáadás", + "@add": { + "description": "add" + }, + "addStock": "Készlet növelése", + "@addStock": { + "description": "add stock" + }, + "address": "Cím", + "@address": {}, + "appAbout": "InvenTree névjegy", + "@appAbout": {}, + "appCredits": "További közreműködők", + "@appCredits": {}, + "appDetails": "App részletek", + "@appDetails": {}, + "appReleaseNotes": "Kiadási közlemények", + "@appReleaseNotes": {}, + "appSettings": "Alkalmazásbeállítások", + "@appSettings": {}, + "appSettingsDetails": "Inventree alkalmazás beállításai", + "@appSettingsDetails": {}, + "attachments": "Mellékletek", + "@attachments": {}, + "attachImage": "Kép csatolása", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nem találhatók mellékletek", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Melléklet kiválasztása", + "@attachmentSelect": {}, + "attention": "Figyelem", + "@attention": {}, + "availableStock": "Elérhető készlet", + "@availableStock": {}, + "barcodeAssign": "Vonalkód hozzárendelése", + "@barcodeAssign": {}, + "barcodeAssigned": "Vonalkód hozzárendelve", + "@barcodeAssigned": {}, + "barcodeError": "Vonalkód olvasási hiba", + "@barcodeError": {}, + "barcodeInUse": "Vonalkód már hozzárendelve", + "@barcodeInUse": {}, + "barcodeMissingHash": "Vonalkód hash hiányzik a válaszból", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nincs egyezés vonalkódra", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Készlet bevételezése az adott helyre", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Hely beolvasása", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Készlet tétel beolvasása", + "@barcodeScanItem": {}, + "barcodeTones": "Vonalkód hangszín", + "@barcodeTones": {}, + "barcodeUnassign": "Vonalkód leválasztása", + "@barcodeUnassign": {}, + "barcodeUnknown": "Vonalkód nem ismerhető fel", + "@barcodeUnknown": {}, + "batchCode": "Batch kód", + "@batchCode": {}, + "billOfMaterials": "Alkatrészjegyzék", + "@billOfMaterials": {}, + "bom": "Alkatrészjegyzék", + "@bom": {}, + "build": "Gyártás", + "@build": {}, + "building": "Gyártásban", + "@building": {}, + "cancel": "Mégsem", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategória", + "@category": {}, + "categoryCreate": "Új kategória", + "@categoryCreate": {}, + "categoryCreateDetail": "Alkatrész kategória létrehozása", + "@categoryCreateDetail": {}, + "categoryUpdated": "Alkatrész kategória módosítva", + "@categoryUpdated": {}, + "company": "Cég", + "@company": {}, + "companyEdit": "Cég szerkesztése", + "@companyEdit": {}, + "companyNoResults": "Nincs a lekérdezésnek megfelelő cég", + "@companyNoResults": {}, + "companyUpdated": "Cég adatai frissítve", + "@companyUpdated": {}, + "companies": "Cégek", + "@companies": {}, + "configureServer": "Kiszolgáló beállítások konfigurálása", + "@configureServer": {}, + "connectionRefused": "A kapcsolat visszautasítva", + "@connectionRefused": {}, + "count": "Mennyiség", + "@count": { + "description": "Count" + }, + "countStock": "Leltározás", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Közreműködők", + "@credits": {}, + "customers": "Vevők", + "@customers": {}, + "damaged": "Sérült", + "@damaged": {}, + "delete": "Törlés", + "@delete": {}, + "deletePart": "Alkatrész törlése", + "@deletePart": {}, + "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", + "@deletePartDetail": {}, + "description": "Leírás", + "@description": {}, + "destroyed": "Megsemmisült", + "@destroyed": {}, + "details": "Részletek", + "@details": { + "description": "details" + }, + "documentation": "Dokumentáció", + "@documentation": {}, + "downloading": "Fájl letöltése", + "@downloading": {}, + "downloadError": "Letöltési hiba", + "@downloadError": {}, + "edit": "Szerkesztés", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategória szerkesztése", + "@editCategory": {}, + "editLocation": "Hely szerkesztése", + "@editLocation": {}, + "editNotes": "Megjegyzések szerkesztése", + "@editNotes": {}, + "editPart": "Alkatrész szerkesztése", + "@editPart": { + "description": "edit part" + }, + "editItem": "Készlet tétel szerkesztése", + "@editItem": {}, + "enterPassword": "Jelszó megadása", + "@enterPassword": {}, + "enterUsername": "Felhasználó megadása", + "@enterUsername": {}, + "error": "Hiba", + "@error": { + "description": "Error" + }, + "errorCreate": "Hiba az adatbázis bejegyzés létrehozása közben", + "@errorCreate": {}, + "errorDelete": "Hiba az adatbázis bejegyzés törlése közben", + "@errorDelete": {}, + "errorDetails": "Hiba részletei", + "@errorDetails": {}, + "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", + "@errorFetch": {}, + "errorReporting": "Hibajelentés", + "@errorReporting": {}, + "errorReportUpload": "Hibajelentések feltöltése", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", + "@errorReportUploadDetails": {}, + "feedback": "Visszajelzés", + "@feedback": {}, + "feedbackError": "Visszajelzés küldése sikertelen", + "@feedbackError": {}, + "feedbackSuccess": "Visszajelzés elküldve", + "@feedbackSuccess": {}, + "formatException": "Formátum hiba", + "@formatException": {}, + "formatExceptionJson": "JSON adatformátum hiba", + "@formatExceptionJson": {}, + "formError": "Form hiba", + "@formError": {}, + "history": "Előzmények", + "@history": { + "description": "history" + }, + "homeScreen": "Főképernyő", + "@homeScreen": {}, + "homeScreenSettings": "Főképernyő beállítások konfigurálása", + "@homeScreenSettings": {}, + "homeShowPo": "Beszerzési rendelések megjelenítése", + "@homeShowPo": {}, + "homeShowSubscribed": "Értesítésre beállított alkatrészek", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Beszállítók megjelenítése", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Gyártók megjelenítése", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Gyártók gomb megjelenítése a főoldalon", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Vevők megjelenítése", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Vevők gomb megjelenítése a főoldalon", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Kép feltöltése sikertelen", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Kép feltöltve", + "@imageUploadSuccess": {}, + "inactive": "Inaktív", + "@inactive": {}, + "inactiveDetail": "Ez az alkatrész inaktív lett", + "@inactiveDetail": {}, + "includeSubcategories": "Alkategóriákkal együtt", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Al-kategóriájú alkatrészek megjelenítése a lista nézetben", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alhelyekkel együtt", + "@includeSublocations": {}, + "includeSublocationsDetail": "Al-helyen lévő alkatrészek megjelenítése a lista nézetben", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Nem teljes profil adatok", + "@incompleteDetails": {}, + "internalPartNumber": "Belső alkatrész azonosító", + "@internalPartNumber": {}, + "info": "Infó", + "@info": {}, + "inProduction": "Gyártásban", + "@inProduction": {}, + "inProductionDetail": "Ez a készlet tétel gyártásban van", + "@inProductionDetail": {}, + "invalidHost": "Érvénytelen hostnév", + "@invalidHost": {}, + "invalidHostDetails": "A megadott hostnév nem érvényes", + "@invalidHostDetails": {}, + "invalidPart": "Érvénytelen alkatrész", + "@invalidPart": {}, + "invalidPartCategory": "Érvénytelen kategória", + "@invalidPartCategory": {}, + "invalidStockLocation": "Érvénytelen készlet hely", + "@invalidStockLocation": {}, + "invalidStockItem": "Érvénytelen készlet tétel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", + "@invalidUsernamePassword": {}, + "issueDate": "Kiállítás dátuma", + "@issueDate": {}, + "itemInLocation": "A tétel már a megadott helyen van", + "@itemInLocation": {}, + "keywords": "Kulcsszavak", + "@keywords": {}, + "lastStocktake": "Utolsó leltár", + "@lastStocktake": {}, + "lastUpdated": "Utoljára módosítva", + "@lastUpdated": {}, + "lineItem": "Sortétel", + "@lineItem": {}, + "lineItems": "Sortételek", + "@lineItems": {}, + "locationCreate": "Új hely", + "@locationCreate": {}, + "locationCreateDetail": "Új készlet hely létrehozása", + "@locationCreateDetail": {}, + "locationNotSet": "Nincs megadva hely", + "@locationNotSet": {}, + "locationUpdated": "Készlet hely adatai frissítve", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Elveszett", + "@lost": {}, + "manufacturers": "Gyártók", + "@manufacturers": {}, + "missingData": "Hiányzó adatok", + "@missingData": {}, + "name": "Név", + "@name": {}, + "notConnected": "Nincs kapcsolódva", + "@notConnected": {}, + "notes": "Megjegyzések", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nincs válasz a kiszolgálótól", + "@noResponse": {}, + "noResults": "Nincs találat", + "@noResults": {}, + "noSubcategories": "Nincsenek alkategóriák", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nincsenek alkategóriák", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Érvénytelen szám", + "@numberInvalid": {}, + "onOrder": "Beszállítás alatt", + "@onOrder": {}, + "onOrderDetails": "Alaktrészek beszállítás alatt", + "@onOrderDetails": {}, + "packaging": "Csomagolás", + "@packaging": {}, + "packageName": "Csomag neve", + "@packageName": {}, + "parent": "Szülő", + "@parent": {}, + "parentCategory": "Szülő kategória", + "@parentCategory": {}, + "parentLocation": "Szülő hely", + "@parentLocation": {}, + "part": "Alkatrész", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Új alkatrész", + "@partCreate": {}, + "partCreateDetail": "Alkatrész létrehozása ebben a kategóriában", + "@partCreateDetail": {}, + "partEdited": "Alkatrész frissítve", + "@partEdited": {}, + "parts": "Alkatrészek", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Nincsenek alkatrészek", + "@partsNone": {}, + "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", + "@partNoResults": {}, + "partsStarred": "Értesítésre beállított alkatrészek", + "@partsStarred": {}, + "partsStarredNone": "Nincsenek csillagozott alkatrészek", + "@partsStarredNone": {}, + "partSuppliers": "Alkatrész beszállítók", + "@partSuppliers": {}, + "partCategory": "Alkatrész kategória", + "@partCategory": {}, + "partCategoryTopLevel": "Legfelső szintű alkatrész kategória", + "@partCategoryTopLevel": {}, + "partCategories": "Alkatrész kategóriák", + "@partCategories": {}, + "partDetails": "Alkatrész részletei", + "@partDetails": {}, + "partNotes": "Alkatrész megjegyzések", + "@partNotes": {}, + "partStock": "Alkatrész készlet", + "@partStock": { + "description": "part stock" + }, + "password": "Jelszó", + "@password": {}, + "passwordEmpty": "Jelszó nem lehet üres", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", + "@permissionAccountDenied": {}, + "permissionRequired": "Engedély szükséges", + "@permissionRequired": {}, + "printLabel": "Címke nyomtatása", + "@printLabel": {}, + "printLabelFailure": "Címkenyomtatás sikertelen", + "@printLabelFailure": {}, + "printLabelSuccess": "Címke nyomtatónak elküldve", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Kiszolgáló profil hozzáadása", + "@profileAdd": {}, + "profileConnect": "Kapcsolódás a kiszolgálóhoz", + "@profileConnect": {}, + "profileEdit": "Kiszolgáló profil szerkesztése", + "@profileEdit": {}, + "profileDelete": "Kiszolgáló profil törlése", + "@profileDelete": {}, + "profileName": "Profil neve", + "@profileName": {}, + "profileNone": "Nincsenek profilok", + "@profileNone": {}, + "profileNotSelected": "Nincs kiválasztva profil", + "@profileNotSelected": {}, + "profileSelect": "Válassz InvenTree kiszolgálót", + "@profileSelect": {}, + "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", + "@profileTapToCreate": {}, + "purchaseOrder": "Beszerzési rendelés", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Beszerzési rendelések", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Beszerzési rendelés frissítve", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Beszerzési ár", + "@purchasePrice": {}, + "quantity": "Mennyiség", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Mennyiség üres", + "@quantityEmpty": {}, + "quantityInvalid": "Mennyiség érvénytelen", + "@quantityInvalid": {}, + "quantityPositive": "Mennyiség pozitív kell legyen", + "@quantityPositive": {}, + "queryNoResults": "Nincs találat", + "@queryNoResults": {}, + "received": "Beérkezett", + "@received": {}, + "receiveItem": "Bevételezés", + "@receiveItem": {}, + "receivedItem": "Beérkezett készlet", + "@receivedItem": {}, + "refresh": "Frissítés", + "@refresh": {}, + "refreshing": "Frissítés...", + "@refreshing": {}, + "rejected": "Elutasított", + "@rejected": {}, + "releaseNotes": "Kiadási közlemények", + "@releaseNotes": {}, + "remove": "Törlés", + "@remove": { + "description": "remove" + }, + "removeStock": "Készlet csökkentése", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hibabejelentés", + "@reportBug": {}, + "reportBugDescription": "Hibabejelentés küldése (GitHub fiók szükséges)", + "@reportBugDescription": {}, + "results": "Eredmények", + "@results": {}, + "request": "Kérés", + "@request": {}, + "requestingData": "Adatok lekérése", + "@requestingData": {}, + "required": "Kötelező", + "@required": { + "description": "This field is required" + }, + "response400": "Rossz kérés", + "@response400": {}, + "response401": "Jogosulatlan", + "@response401": {}, + "response403": "Hozzáférés megtagadva", + "@response403": {}, + "response404": "Erőforrás nem található", + "@response404": {}, + "response405": "Metódus nincs engedélyezve", + "@response405": {}, + "response429": "Túl sok kérés", + "@response429": {}, + "response500": "Belső kiszolgáló hiba", + "@response500": {}, + "response501": "Nincs implementálva", + "@response501": {}, + "response502": "Rossz átjáró", + "@response502": {}, + "response503": "A szolgáltatás nem érhető el", + "@response503": {}, + "response504": "Átjáró időtúllépés", + "@response504": {}, + "response505": "HTTP verzió nem támogatott", + "@response505": {}, + "responseData": "Válasz adatok", + "@responseData": {}, + "responseInvalid": "Érvénytelen válasz kód", + "@responseInvalid": {}, + "responseUnknown": "Ismeretlen válasz", + "@responseUnknown": {}, + "result": "Eredmény", + "@result": { + "description": "" + }, + "returned": "Visszaküldve", + "@returned": {}, + "salesOrders": "Vevői rendelések", + "@salesOrders": {}, + "save": "Mentés", + "@save": { + "description": "Save" + }, + "scanBarcode": "Vonalkód beolvasása", + "@scanBarcode": {}, + "scanIntoLocation": "Beolvasás helyre", + "@scanIntoLocation": {}, + "search": "Keresés", + "@search": { + "description": "search" + }, + "searchLocation": "Hely keresése", + "@searchLocation": {}, + "searchParts": "Alkatrészek keresése", + "@searchParts": {}, + "searchStock": "Készlet keresése", + "@searchStock": {}, + "select": "Kiválaszt", + "@select": {}, + "selectFile": "Fájl kiválasztása", + "@selectFile": {}, + "selectImage": "Válassz képet", + "@selectImage": {}, + "selectLocation": "Válassz helyet", + "@selectLocation": {}, + "send": "Küldés", + "@send": {}, + "serialNumber": "Sorozatszám", + "@serialNumber": {}, + "server": "Kiszolgáló", + "@server": {}, + "serverAddress": "Kiszolgáló címe", + "@serverAddress": {}, + "serverApiRequired": "Szükséges API verzió", + "@serverApiRequired": {}, + "serverApiVersion": "Szerver API verzió", + "@serverApiVersion": {}, + "serverAuthenticationError": "Hitelesítési hiba", + "@serverAuthenticationError": {}, + "serverCertificateError": "Tanúsítvány hiba", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Érvénytelen kiszolgáló HTTPS tanúsítvány", + "@serverCertificateInvalid": {}, + "serverConnected": "Kapcsolódva a kiszolgálóhoz", + "@serverConnected": {}, + "serverConnecting": "Kapcsolódás a kiszolgálóhoz", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nem sikerült kapcsolódni a kiszolgálóhoz", + "@serverCouldNotConnect": {}, + "serverEmpty": "A kiszolgálónév nem lehet üres", + "@serverEmpty": {}, + "serverError": "Kiszolgálóhiba", + "@serverError": {}, + "serverDetails": "Kiszolgáló részletei", + "@serverDetails": {}, + "serverMissingData": "A kiszolgáló válaszából szükséges mezők hiányoznak", + "@serverMissingData": {}, + "serverOld": "Régi kiszolgáló verzió", + "@serverOld": {}, + "serverSettings": "Kiszolgáló beállítások", + "@serverSettings": {}, + "serverStart": "A kiszolgálónak http(s) kezdetűnek kell lennie", + "@serverStart": {}, + "settings": "Beállítások", + "@settings": {}, + "serverInstance": "Kiszolgáló példány", + "@serverInstance": {}, + "serverNotConnected": "Kiszolgáló nem csatlakozik", + "@serverNotConnected": {}, + "sounds": "Hangok", + "@sounds": {}, + "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", + "@soundOnServerError": {}, + "status": "Állapot", + "@status": {}, + "statusCode": "Állapot kód", + "@statusCode": {}, + "stock": "Készlet", + "@stock": { + "description": "stock" + }, + "stockDetails": "Jelenleg elérhető készlet mennyiség", + "@stockDetails": {}, + "stockItem": "Készlet tétel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Készlet tételek", + "@stockItems": {}, + "stockItemCreate": "Új készlet tétel", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Új készlet tétel létrehozása ezen a helyen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Készlet tétel törlése", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Biztosan törölni szeretnéd ezt a készlet tételt?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Készlet tétel nem törölhető", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Készlet tétel törölve", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Készlettörténet", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Készlettörténet megjelenítése", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Készlet áthelyezve", + "@stockItemTransferred": {}, + "stockItemUpdated": "Készlet tétel feltöltve", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nincs elérhető készlet", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Készlet tétel megjegyzések", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Készlet tétel feltöltve", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Készlet tétel módosítása sikertelen", + "@stockItemUpdateFailure": {}, + "stockLocation": "Készlet hely", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Készlethelyek", + "@stockLocations": {}, + "stockTopLevel": "Legfelső szintű készlet hely", + "@stockTopLevel": {}, + "strictHttps": "Kizárólag HTTPS használata", + "@strictHttps": {}, + "strictHttpsDetails": "HTTPS tanúsítványok szigorú ellenőrzése", + "@strictHttpsDetails": {}, + "subcategory": "Alkategória", + "@subcategory": {}, + "subcategories": "Alkategóriák", + "@subcategories": {}, + "sublocation": "Alhely", + "@sublocation": {}, + "sublocations": "Alhelyek", + "@sublocations": {}, + "sublocationNone": "Nincsenek alhelyek", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nincsenek elérhető alhelyek", + "@sublocationNoneDetail": {}, + "submitFeedback": "Visszajelzés Küldése", + "@submitFeedback": {}, + "suppliedParts": "Szállított alkatrészek", + "@suppliedParts": {}, + "supplier": "Beszállító", + "@supplier": {}, + "suppliers": "Beszállítók", + "@suppliers": {}, + "supplierReference": "Beszállítói azonosító", + "@supplierReference": {}, + "takePicture": "Fotó készítése", + "@takePicture": {}, + "targetDate": "Cél dátum", + "@targetDate": {}, + "templatePart": "Szülő sablon alkatrész", + "@templatePart": {}, + "testName": "Teszt neve", + "@testName": {}, + "testPassedOrFailed": "Teszt sikeres vagy sikertelen", + "@testPassedOrFailed": {}, + "testsRequired": "Szükséges tesztek", + "@testsRequired": {}, + "testResults": "Teszt eredmények", + "@testResults": { + "description": "" + }, + "testResultAdd": "Teszt eredmény hozzáadása", + "@testResultAdd": {}, + "testResultNone": "Nincsenek teszt eredmények", + "@testResultNone": {}, + "testResultNoneDetail": "Teszt eredmény nem áll rendelkezésre", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hiba a teszt eredmény feltöltése közben", + "@testResultUploadFail": {}, + "testResultUploadPass": "Teszt eredmény feltöltve", + "@testResultUploadPass": {}, + "timeout": "Időtúllépés", + "@timeout": { + "description": "" + }, + "tokenError": "Token hiba", + "@tokenError": {}, + "tokenMissing": "Hiányzó token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", + "@tokenMissingFromResponse": {}, + "transfer": "Áthelyezés", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Készlet áthelyezése", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Fordítás", + "@translate": {}, + "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", + "@translateHelp": {}, + "units": "Mértékegységek", + "@units": {}, + "unknownResponse": "Ismeretlen válasz", + "@unknownResponse": {}, + "upload": "Feltöltés", + "@upload": {}, + "uploadFailed": "Fájl feltöltése sikertelen", + "@uploadFailed": {}, + "uploadSuccess": "Fájl feltöltve", + "@uploadSuccess": {}, + "usedIn": "Felhasználva ebben", + "@usedIn": {}, + "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", + "@usedInDetails": {}, + "username": "Felhasználónév", + "@username": {}, + "usernameEmpty": "Felhasználónév nem lehet üres", + "@usernameEmpty": {}, + "value": "Érték", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Az érték nem lehet üres", + "@valueCannotBeEmpty": {}, + "valueRequired": "Érték megadása szükséges", + "@valueRequired": {}, + "version": "Verzió", + "@version": {}, + "viewSupplierPart": "Beszállítói alkatrész megtekintése", + "@viewSupplierPart": {}, + "website": "Weboldal", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 36d80aa..c917076 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "id", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 36d80aa..4df3b7d 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1,5 +1,505 @@ { - "@@locale": "en", + "@@locale": "it", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Info", + "@about": {}, + "accountDetails": "Dettagli account", + "@accountDetails": {}, + "actions": "Azioni", + "@actions": { + "description": "" + }, + "actionsNone": "Nessuna azione disponibile", + "@actionsNone": {}, + "add": "Aggiungi", + "@add": { + "description": "add" + }, + "address": "Indirizzo", + "@address": {}, + "appAbout": "Info su InvenTree", + "@appAbout": {}, + "appCredits": "Riconoscimenti addizionali", + "@appCredits": {}, + "appDetails": "Dettagli App", + "@appDetails": {}, + "appReleaseNotes": "Mostra le note di rilascio dell'app", + "@appReleaseNotes": {}, + "appSettings": "Impostazioni App", + "@appSettings": {}, + "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", + "@appSettingsDetails": {}, + "attachments": "Allegati", + "@attachments": {}, + "attachImage": "Allega Immagine", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nessun allegato trovato", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Seleziona allegato", + "@attachmentSelect": {}, + "attention": "Attenzione", + "@attention": {}, + "barcodeAssign": "Assegna Codice A Barre", + "@barcodeAssign": {}, + "barcodeAssigned": "Codice a barre assegnato", + "@barcodeAssigned": {}, + "barcodeError": "Errore scansione codice a barre", + "@barcodeError": {}, + "barcodeInUse": "Codice a barre già in uso", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dati hash codice a barre mancanti dalla risposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nessuna corrispondenza per il codice a barre", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Codice a barre non assegnato", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scansiona per assegnare codice a barre", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeTones": "Toni Codice a Barre", + "@barcodeTones": {}, + "barcodeUnassign": "Deseleziona Il Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Codice a barre non leggibile", + "@barcodeUnknown": {}, + "batchCode": "Codice Lotto", + "@batchCode": {}, + "billOfMaterials": "Distinta materiali", + "@billOfMaterials": {}, + "bom": "Distinta materiali", + "@bom": {}, + "build": "Crea", + "@build": {}, + "cancel": "Annulla", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nuova categoria", + "@categoryCreate": {}, + "company": "Azienda", + "@company": {}, + "companyEdit": "Modifica azienda", + "@companyEdit": {}, + "companyNoResults": "Nessuna azienda corrispondente alla query", + "@companyNoResults": {}, + "companies": "Aziende", + "@companies": {}, + "connectionRefused": "Connessione rifiutata", + "@connectionRefused": {}, + "count": "Quantità", + "@count": { + "description": "Count" + }, + "credits": "Riconoscimenti", + "@credits": {}, + "customers": "Clienti", + "@customers": {}, + "damaged": "Danneggiato", + "@damaged": {}, + "delete": "Cancella", + "@delete": {}, + "description": "Descrizione", + "@description": {}, + "destroyed": "Distrutto", + "@destroyed": {}, + "details": "Dettagli", + "@details": { + "description": "details" + }, + "documentation": "Documentazione", + "@documentation": {}, + "downloading": "File in download", + "@downloading": {}, + "downloadError": "Errore download", + "@downloadError": {}, + "edit": "Modifica", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifica Categoria", + "@editCategory": {}, + "enterPassword": "Inserire la password", + "@enterPassword": {}, + "enterUsername": "Inserisci nome utente", + "@enterUsername": {}, + "error": "Errore", + "@error": { + "description": "Error" + }, + "errorCreate": "Errore nella creazione della voce del database", + "@errorCreate": {}, + "errorDetails": "Dettagli errore", + "@errorDetails": {}, + "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", + "@errorFetch": {}, + "feedback": "Commenti e suggerimenti", + "@feedback": {}, + "feedbackError": "Errore nell'invio del feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback inviato", + "@feedbackSuccess": {}, + "formatException": "Eccezione Formato", + "@formatException": {}, + "formatExceptionJson": "Eccezione formato dati JSON", + "@formatExceptionJson": {}, + "formError": "Errore Modulo", + "@formError": {}, + "history": "Cronologia", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Il caricamento della foto è fallito", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Immagine caricata", + "@imageUploadSuccess": {}, + "inactive": "Inattivo", + "@inactive": {}, + "includeSubcategories": "Includi sottocategorie", + "@includeSubcategories": {}, + "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", + "@incompleteDetails": {}, + "info": "Info", + "@info": {}, + "invalidHost": "Nome host non valido", + "@invalidHost": {}, + "invalidHostDetails": "Il nome host fornito non è valido", + "@invalidHostDetails": {}, + "invalidUsernamePassword": "Combinazione nome utente e password non valida", + "@invalidUsernamePassword": {}, + "issueDate": "Data di emissione", + "@issueDate": {}, + "itemInLocation": "Elemento già in posizione", + "@itemInLocation": {}, + "keywords": "Parole Chiave", + "@keywords": {}, + "lastUpdated": "Ultimo aggiornamento", + "@lastUpdated": {}, + "lost": "Perso", + "@lost": {}, + "manufacturers": "Produttori", + "@manufacturers": {}, + "missingData": "Dati mancanti", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "notConnected": "Non connesso", + "@notConnected": {}, + "notes": "Note", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nessuna risposta dal server", + "@noResponse": {}, + "noResults": "Nessun risultato", + "@noResults": {}, + "noSubcategories": "Nessuna sotto categoria", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Numero non valido", + "@numberInvalid": {}, + "onOrderDetails": "Articoli attualmente in ordine", + "@onOrderDetails": {}, + "packaging": "Confezionamento", + "@packaging": {}, + "packageName": "Nome pacchetto", + "@packageName": {}, + "parent": "Superiore", + "@parent": {}, + "parentCategory": "Categoria Superiore", + "@parentCategory": {}, + "parts": "Articoli", + "@parts": { + "description": "Part (multiple)" + }, + "partSuppliers": "Fornitori articoli", + "@partSuppliers": {}, + "password": "Password", + "@password": {}, + "passwordEmpty": "La password non può essere vuota", + "@passwordEmpty": {}, + "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorizzazione necessaria", + "@permissionRequired": {}, + "profile": "Profilo", + "@profile": {}, + "profileAdd": "Aggiungi Profilo Server", + "@profileAdd": {}, + "profileConnect": "Connetti al Server", + "@profileConnect": {}, + "profileEdit": "Modifica il profilo del Server", + "@profileEdit": {}, + "profileDelete": "Elimina Profilo Del Server", + "@profileDelete": {}, + "profileName": "Nome Profilo", + "@profileName": {}, + "profileNone": "Nessun profilo disponibile", + "@profileNone": {}, + "profileNotSelected": "Nessun profilo selezionato", + "@profileNotSelected": {}, + "profileSelect": "Seleziona Server InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Tocca per creare o selezionare un profilo", + "@profileTapToCreate": {}, + "purchaseOrder": "Ordine d'acquisto", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifica ordine d'acquisto", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Ordini d'acquisto", + "@purchaseOrders": {}, + "purchasePrice": "Prezzo d'acquisto", + "@purchasePrice": {}, + "quantity": "Quantità", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Quantità vuota", + "@quantityEmpty": {}, + "quantityInvalid": "La quantità non è valida", + "@quantityInvalid": {}, + "quantityPositive": "La quantità deve essere positiva", + "@quantityPositive": {}, + "queryNoResults": "Nessun risultato per la tua ricerca", + "@queryNoResults": {}, + "received": "Ricevuto", + "@received": {}, + "receiveItem": "Ricevi Articolo", + "@receiveItem": {}, + "refresh": "Aggiorna", + "@refresh": {}, + "refreshing": "In aggiornamento", + "@refreshing": {}, + "rejected": "Respinto", + "@rejected": {}, + "releaseNotes": "Note di Rilascio", + "@releaseNotes": {}, + "remove": "Rimuovi", + "@remove": { + "description": "remove" + }, + "reportBug": "Segnala un bug", + "@reportBug": {}, + "results": "Risultati", + "@results": {}, + "request": "Richiesta", + "@request": {}, + "requestingData": "Dati in richiesta", + "@requestingData": {}, + "required": "Richiesto", + "@required": { + "description": "This field is required" + }, + "response400": "Richiesta non valida", + "@response400": {}, + "response401": "Non Autorizzato", + "@response401": {}, + "response403": "Permesso negato", + "@response403": {}, + "response404": "Risorsa non trovata", + "@response404": {}, + "response405": "Metodo non consentito", + "@response405": {}, + "response429": "Troppe richieste", + "@response429": {}, + "response500": "Errore Interno del Server", + "@response500": {}, + "response501": "Non implementato", + "@response501": {}, + "response502": "Gateway Errato", + "@response502": {}, + "response503": "Servizio Non Disponibile", + "@response503": {}, + "response504": "Timeout del gateway", + "@response504": {}, + "response505": "Versione HTTP non supportata", + "@response505": {}, + "responseData": "Dati risposta", + "@responseData": {}, + "responseInvalid": "Codice Risposta Non Valido", + "@responseInvalid": {}, + "responseUnknown": "Risposta Sconosciuta", + "@responseUnknown": {}, + "result": "Risultato", + "@result": { + "description": "" + }, + "returned": "Restituito", + "@returned": {}, + "salesOrders": "Ordini di vendita", + "@salesOrders": {}, + "save": "Salva", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scansiona codice a barre", + "@scanBarcode": {}, + "search": "Cerca", + "@search": { + "description": "search" + }, + "select": "Seleziona", + "@select": {}, + "selectFile": "Seleziona file", + "@selectFile": {}, + "selectImage": "Seleziona un'immagine", + "@selectImage": {}, + "send": "Invia", + "@send": {}, + "serialNumber": "Numero seriale", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Indirizzo del server", + "@serverAddress": {}, + "serverApiRequired": "Versione API Richiesta", + "@serverApiRequired": {}, + "serverApiVersion": "Versione API Server", + "@serverApiVersion": {}, + "serverAuthenticationError": "Errore di autenticazione", + "@serverAuthenticationError": {}, + "serverCertificateError": "Errore certificato", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Il certificato del server non è valido", + "@serverCertificateInvalid": {}, + "serverConnected": "Connesso al Server", + "@serverConnected": {}, + "serverConnecting": "Connessione al server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Impossibile connettersi al server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Nome server non può essere vuoto", + "@serverEmpty": {}, + "serverError": "Errore del server", + "@serverError": {}, + "serverDetails": "Dettagli del server", + "@serverDetails": {}, + "serverMissingData": "Dati mancanti nella risposta del server", + "@serverMissingData": {}, + "serverOld": "Versione Vecchia Del Server", + "@serverOld": {}, + "serverSettings": "Impostazioni Server", + "@serverSettings": {}, + "serverStart": "Il server deve iniziare con http[s]", + "@serverStart": {}, + "settings": "Impostazioni", + "@settings": {}, + "serverInstance": "Istanza Del Server", + "@serverInstance": {}, + "serverNotConnected": "Server non connesso", + "@serverNotConnected": {}, + "sounds": "Audio", + "@sounds": {}, + "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Riproduci il tono sonoro su un errore del server", + "@soundOnServerError": {}, + "status": "Stato", + "@status": {}, + "statusCode": "Codice di stato", + "@statusCode": {}, + "stock": "Magazzino", + "@stock": { + "description": "stock" + }, + "subcategory": "Sottocategoria", + "@subcategory": {}, + "subcategories": "Sottocategorie", + "@subcategories": {}, + "submitFeedback": "Invia feedback", + "@submitFeedback": {}, + "supplier": "Fornitore", + "@supplier": {}, + "suppliers": "Fornitori", + "@suppliers": {}, + "supplierReference": "Riferimento fornitore", + "@supplierReference": {}, + "takePicture": "Scatta Foto", + "@takePicture": {}, + "testName": "Nome del test", + "@testName": {}, + "testPassedOrFailed": "Test superato o fallito", + "@testPassedOrFailed": {}, + "testsRequired": "Test Richiesti", + "@testsRequired": {}, + "testResults": "Risultati del test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Aggiungi Risultato Test", + "@testResultAdd": {}, + "testResultNone": "Nessun Risultato Del Test", + "@testResultNone": {}, + "testResultNoneDetail": "Nessun risultato del test disponibile", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Errore nel caricamento del risultato del test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Risultato del test caricato", + "@testResultUploadPass": {}, + "timeout": "Tempo Scaduto", + "@timeout": { + "description": "" + }, + "tokenError": "Errore Token", + "@tokenError": {}, + "tokenMissing": "Token Mancante", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", + "@tokenMissingFromResponse": {}, + "transfer": "Trasferisci", + "@transfer": { + "description": "transfer" + }, + "translate": "Traduci", + "@translate": {}, + "translateHelp": "Aiuta a tradurre l'app InvenTree", + "@translateHelp": {}, + "units": "Unità", + "@units": {}, + "unknownResponse": "Risposta Sconosciuta", + "@unknownResponse": {}, + "upload": "Carica", + "@upload": {}, + "uploadFailed": "Caricamento di file non riuscito", + "@uploadFailed": {}, + "uploadSuccess": "File caricato", + "@uploadSuccess": {}, + "usedIn": "Viene utilizzato in", + "@usedIn": {}, + "username": "Nome utente", + "@username": {}, + "usernameEmpty": "Il nome utente non può essere vuoto", + "@usernameEmpty": {}, + "value": "Valore", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Il valore non può essere vuoto", + "@valueCannotBeEmpty": {}, + "valueRequired": "È richiesto un valore", + "@valueRequired": {}, + "version": "Versione", + "@version": {}, + "viewSupplierPart": "Visualizza Fornitore", + "@viewSupplierPart": {}, + "website": "Sito Web", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 36d80aa..c55ad78 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -1,5 +1,682 @@ { - "@@locale": "en", + "@@locale": "ja", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "概要", + "@about": {}, + "accountDetails": "アカウントの詳細", + "@accountDetails": {}, + "actions": "アクション", + "@actions": { + "description": "" + }, + "actionsNone": "利用可能なアクションはありません", + "@actionsNone": {}, + "add": "追加", + "@add": { + "description": "add" + }, + "addStock": "在庫を追加", + "@addStock": { + "description": "add stock" + }, + "address": "アドレス", + "@address": {}, + "appAbout": "InvenTree について", + "@appAbout": {}, + "appCredits": "すぺしゃる★さんくす!", + "@appCredits": {}, + "appDetails": "アプリ詳細", + "@appDetails": {}, + "appReleaseNotes": "アプリのリリースノートを表示", + "@appReleaseNotes": {}, + "appSettings": "アプリ設定", + "@appSettings": {}, + "appSettingsDetails": "アプリ設定を構成します", + "@appSettingsDetails": {}, + "attachments": "添付ファイル", + "@attachments": {}, + "attachImage": "画像を添付", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "添付ファイルが見つかりません。", + "@attachmentNone": {}, + "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "添付ファイルを選択", + "@attachmentSelect": {}, + "attention": "注意", + "@attention": {}, + "availableStock": "在庫あり", + "@availableStock": {}, + "barcodeAssign": "バーコードを割り当てる", + "@barcodeAssign": {}, + "barcodeAssigned": "バーコードが割り当てられました", + "@barcodeAssigned": {}, + "barcodeError": "バーコードのスキャンエラー", + "@barcodeError": {}, + "barcodeInUse": "バーコードは既に割り当てられています", + "@barcodeInUse": {}, + "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "バーコードが一致しません", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "バーコードが割り当てられていません", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "スキャンしてバーコードを割り当てます", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "InvenTree バーコードをスキャンする", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "在庫アイテムを在庫場所にスキャン", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "在庫場所をスキャン", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "在庫アイテムをスキャン", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "バーコードの割り当てを解除", + "@barcodeUnassign": {}, + "barcodeUnknown": "バーコードが認識されません", + "@barcodeUnknown": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "ビルド", + "@build": {}, + "building": "ビルド", + "@building": {}, + "cancel": "キャンセル", + "@cancel": { + "description": "Cancel" + }, + "category": "カテゴリ", + "@category": {}, + "categoryCreate": "新規カテゴリ", + "@categoryCreate": {}, + "categoryCreateDetail": "新しい部品カテゴリを作成", + "@categoryCreateDetail": {}, + "categoryUpdated": "部品カテゴリを更新しました", + "@categoryUpdated": {}, + "company": "会社", + "@company": {}, + "companyEdit": "会社を編集", + "@companyEdit": {}, + "companyNoResults": "検索条件に一致する会社はありません", + "@companyNoResults": {}, + "companyUpdated": "会社の詳細を更新しました", + "@companyUpdated": {}, + "companies": "会社", + "@companies": {}, + "configureServer": "サーバー設定", + "@configureServer": {}, + "connectionRefused": "接続を拒否しました", + "@connectionRefused": {}, + "count": "カウント", + "@count": { + "description": "Count" + }, + "countStock": "在庫数", + "@countStock": { + "description": "Count Stock" + }, + "credits": "謝辞", + "@credits": {}, + "customers": "顧客", + "@customers": {}, + "damaged": "破損", + "@damaged": {}, + "delete": "削除", + "@delete": {}, + "deletePart": "部品を削除", + "@deletePart": {}, + "deletePartDetail": "データベースからこの部品を削除します", + "@deletePartDetail": {}, + "description": "説明", + "@description": {}, + "destroyed": "破壊", + "@destroyed": {}, + "details": "詳細", + "@details": { + "description": "details" + }, + "documentation": "ドキュメント", + "@documentation": {}, + "downloading": "ファイルをダウンロード中", + "@downloading": {}, + "downloadError": "ダウンロードエラー", + "@downloadError": {}, + "edit": "編集", + "@edit": { + "description": "edit" + }, + "editCategory": "カテゴリの編集", + "@editCategory": {}, + "editLocation": "在庫場所を編集", + "@editLocation": {}, + "editNotes": "メモを編集", + "@editNotes": {}, + "editPart": "パートの編集", + "@editPart": { + "description": "edit part" + }, + "editItem": "在庫商品を編集", + "@editItem": {}, + "enterPassword": "パスワードを入力してください", + "@enterPassword": {}, + "enterUsername": "ユーザー名を入力してください", + "@enterUsername": {}, + "error": "エラー", + "@error": { + "description": "Error" + }, + "errorCreate": "データベースの作成中にエラーが発生しました", + "@errorCreate": {}, + "errorDelete": "データベースの削除中にエラーが発生しました", + "@errorDelete": {}, + "errorDetails": "エラーの詳細", + "@errorDetails": {}, + "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", + "@errorFetch": {}, + "errorReporting": "エラー報告", + "@errorReporting": {}, + "errorReportUpload": "エラー報告をアップロード", + "@errorReportUpload": {}, + "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", + "@errorReportUploadDetails": {}, + "feedback": "フィードバック", + "@feedback": {}, + "feedbackError": "フィードバックの送信エラー", + "@feedbackError": {}, + "feedbackSuccess": "フィードバックが送信されました", + "@feedbackSuccess": {}, + "formatException": "フォーマットの例外エラー", + "@formatException": {}, + "formatExceptionJson": "JSONデータフォーマット例外エラー", + "@formatExceptionJson": {}, + "formError": "フォームエラー", + "@formError": {}, + "history": "履歴", + "@history": { + "description": "history" + }, + "homeScreen": "ホーム画面", + "@homeScreen": {}, + "homeScreenSettings": "ホーム画面の設定", + "@homeScreenSettings": {}, + "homeShowPo": "注文書を表示", + "@homeShowPo": {}, + "homeShowSubscribed": "購読済みのパーツ", + "@homeShowSubscribed": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowSuppliers": "仕入先を表示", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "メーカーを表示", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "顧客を表示", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "画像のアップロードに失敗しました", + "@imageUploadFailure": {}, + "imageUploadSuccess": "アップロードされた画像", + "@imageUploadSuccess": {}, + "inactive": "無効", + "@inactive": {}, + "inactiveDetail": "この部品は無効としてマークされています", + "@inactiveDetail": {}, + "includeSubcategories": "サブカテゴリを含む", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "サブカテゴリをリストビューに表示します", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "サブ在庫場所を含める", + "@includeSublocations": {}, + "includeSublocationsDetail": "サブ在庫場所を表示します", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完全なプロフィールの詳細", + "@incompleteDetails": {}, + "internalPartNumber": "内部パーツ番号", + "@internalPartNumber": {}, + "info": "情報", + "@info": {}, + "inProduction": "生産中", + "@inProduction": {}, + "inProductionDetail": "この在庫品は生産中です", + "@inProductionDetail": {}, + "invalidHost": "無効なホスト名", + "@invalidHost": {}, + "invalidHostDetails": "このホスト名は無効です。", + "@invalidHostDetails": {}, + "invalidPart": "無効なパーツ", + "@invalidPart": {}, + "invalidPartCategory": "無効なパーツカテゴリー", + "@invalidPartCategory": {}, + "invalidStockLocation": "無効な在庫場所", + "@invalidStockLocation": {}, + "invalidStockItem": "無効な在庫アイテム", + "@invalidStockItem": {}, + "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", + "@invalidUsernamePassword": {}, + "issueDate": "発行日", + "@issueDate": {}, + "itemInLocation": "アイテムは既に在庫場所にあります", + "@itemInLocation": {}, + "keywords": "キーワード", + "@keywords": {}, + "lastUpdated": "最終更新", + "@lastUpdated": {}, + "locationCreate": "新しい場所", + "@locationCreate": {}, + "locationCreateDetail": "新しい在庫場所を作成", + "@locationCreateDetail": {}, + "locationNotSet": "在庫場所が指定されていません", + "@locationNotSet": {}, + "locationUpdated": "在庫場所を更新しました", + "@locationUpdated": {}, + "link": "リンク", + "@link": {}, + "lost": "損失", + "@lost": {}, + "missingData": "データ消失", + "@missingData": {}, + "name": "名前", + "@name": {}, + "notConnected": "接続されていません", + "@notConnected": {}, + "notes": "メモ", + "@notes": { + "description": "Notes" + }, + "noResponse": "サーバーからの応答がありません", + "@noResponse": {}, + "noResults": "一致する結果なし", + "@noResults": {}, + "noSubcategories": "サブカテゴリはありません", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "無効な値", + "@numberInvalid": {}, + "onOrder": "注文中", + "@onOrder": {}, + "packaging": "梱包中", + "@packaging": {}, + "packageName": "パッケージ名", + "@packageName": {}, + "parent": "親", + "@parent": {}, + "parentCategory": "親カテゴリ", + "@parentCategory": {}, + "parentLocation": "上位の場所", + "@parentLocation": {}, + "part": "パーツ", + "@part": { + "description": "Part (single)" + }, + "parts": "パーツ", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "パーツがありません", + "@partsNone": {}, + "partsStarredNone": "お気に入りのパーツはありません", + "@partsStarredNone": {}, + "partCategory": "パーツカテゴリー", + "@partCategory": {}, + "partCategoryTopLevel": "トップレベルのパーツカテゴリ", + "@partCategoryTopLevel": {}, + "partCategories": "パーツカテゴリー", + "@partCategories": {}, + "partDetails": "パーツ詳細", + "@partDetails": {}, + "partNotes": "パーツメモ", + "@partNotes": {}, + "partStock": "パーツ在庫:", + "@partStock": { + "description": "part stock" + }, + "password": "パスワード", + "@password": {}, + "passwordEmpty": "パスワードは空欄にできません。", + "@passwordEmpty": {}, + "permissionAccountDenied": "操作を行う権限がありません", + "@permissionAccountDenied": {}, + "permissionRequired": "権限が必要です", + "@permissionRequired": {}, + "printLabel": "ラベルを印刷", + "@printLabel": {}, + "printLabelFailure": "ラベルの印刷に失敗しました", + "@printLabelFailure": {}, + "printLabelSuccess": "ラベルをプリンタに送信しました", + "@printLabelSuccess": {}, + "profile": "プロフィール", + "@profile": {}, + "profileAdd": "サーバープロファイルを追加", + "@profileAdd": {}, + "profileConnect": "サーバーに接続", + "@profileConnect": {}, + "profileEdit": "サーバープロファイルを編集", + "@profileEdit": {}, + "profileDelete": "サーバープロファイルの削除", + "@profileDelete": {}, + "profileName": "プロファイル名", + "@profileName": {}, + "profileNone": "利用可能なプロファイルがありません", + "@profileNone": {}, + "profileNotSelected": "プロフィールが選択されていません", + "@profileNotSelected": {}, + "profileSelect": "InvenTreeサーバーを選択", + "@profileSelect": {}, + "profileTapToCreate": "タップしてプロフィールを作成または選択します", + "@profileTapToCreate": {}, + "purchaseOrder": "発注書", + "@purchaseOrder": {}, + "purchaseOrderEdit": "発注書の更新", + "@purchaseOrderEdit": {}, + "purchaseOrders": "発注書", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "発注書が更新されました", + "@purchaseOrderUpdated": {}, + "purchasePrice": "購入金額", + "@purchasePrice": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "数量が空です", + "@quantityEmpty": {}, + "quantityInvalid": "数量が無効です", + "@quantityInvalid": {}, + "quantityPositive": "数量は1以上", + "@quantityPositive": {}, + "queryNoResults": "検索結果はありません", + "@queryNoResults": {}, + "refresh": "更新", + "@refresh": {}, + "refreshing": "更新中", + "@refreshing": {}, + "rejected": "却下済み", + "@rejected": {}, + "releaseNotes": "リリースノート", + "@releaseNotes": {}, + "remove": "削除", + "@remove": { + "description": "remove" + }, + "removeStock": "在庫を削除", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "不具合の報告", + "@reportBug": {}, + "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", + "@reportBugDescription": {}, + "results": "結果", + "@results": {}, + "request": "リクエスト", + "@request": {}, + "requestingData": "データをリクエスト中", + "@requestingData": {}, + "required": "必須", + "@required": { + "description": "This field is required" + }, + "response400": "不正なリクエスト", + "@response400": {}, + "response401": "認証されていません", + "@response401": {}, + "response403": "権限がありません", + "@response403": {}, + "response404": "リソースが見つかりません", + "@response404": {}, + "response405": "メソッドが許可されていません", + "@response405": {}, + "response429": "リクエストが多すぎます", + "@response429": {}, + "response501": "未実装", + "@response501": {}, + "response503": "サービスは利用できません", + "@response503": {}, + "response505": "このHTTP バージョンはサポートされていません", + "@response505": {}, + "responseData": "応答データ", + "@responseData": {}, + "responseInvalid": "無効な応答", + "@responseInvalid": {}, + "responseUnknown": "不明な応答コード", + "@responseUnknown": {}, + "result": "結果", + "@result": { + "description": "" + }, + "returned": "返品済", + "@returned": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "バーコードをスキャン", + "@scanBarcode": {}, + "scanIntoLocation": "スキャンされた在庫場所", + "@scanIntoLocation": {}, + "search": "検索", + "@search": { + "description": "search" + }, + "searchLocation": "在庫場所場所を検索", + "@searchLocation": {}, + "searchParts": "パーツの検索", + "@searchParts": {}, + "searchStock": "在庫を検索", + "@searchStock": {}, + "select": "選択", + "@select": {}, + "selectFile": "ファイルを選択", + "@selectFile": {}, + "selectImage": "画像を選択", + "@selectImage": {}, + "selectLocation": "在庫場所を選択", + "@selectLocation": {}, + "send": "送信", + "@send": {}, + "serialNumber": "シリアルナンバー", + "@serialNumber": {}, + "server": "サーバー", + "@server": {}, + "serverAddress": "サーバーアドレス:", + "@serverAddress": {}, + "serverApiRequired": "必要なAPIバージョン", + "@serverApiRequired": {}, + "serverApiVersion": "サーバー API バージョン", + "@serverApiVersion": {}, + "serverAuthenticationError": "認証エラー", + "@serverAuthenticationError": {}, + "serverCertificateError": "認証エラー", + "@serverCertificateError": {}, + "serverCertificateInvalid": "サーバー HTTPS 証明書が無効です", + "@serverCertificateInvalid": {}, + "serverConnected": "サーバへ接続しました\n", + "@serverConnected": {}, + "serverConnecting": "サーバに接続中", + "@serverConnecting": {}, + "serverCouldNotConnect": "サーバーに接続できませんでした", + "@serverCouldNotConnect": {}, + "serverError": "サーバーエラー", + "@serverError": {}, + "serverDetails": "サーバの詳細", + "@serverDetails": {}, + "serverOld": "旧サーバーのバージョン", + "@serverOld": {}, + "serverSettings": "サーバー設定:", + "@serverSettings": {}, + "serverStart": "サーバーは http[s] で開始する必要があります", + "@serverStart": {}, + "settings": "設定", + "@settings": {}, + "serverInstance": "サーバインスタンス", + "@serverInstance": {}, + "serverNotConnected": "サーバーに接続されていません", + "@serverNotConnected": {}, + "sounds": "サウンド", + "@sounds": {}, + "soundOnBarcodeAction": "バーコード動作で音を鳴らす", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "サーバーのエラー時に音を鳴らす", + "@soundOnServerError": {}, + "status": "ステータス", + "@status": {}, + "statusCode": "ステータスコード", + "@statusCode": {}, + "stock": "在庫", + "@stock": { + "description": "stock" + }, + "stockItem": "在庫アイテム", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "在庫アイテム", + "@stockItems": {}, + "stockItemCreate": "新しい在庫アイテム", + "@stockItemCreate": {}, + "stockItemCreateDetail": "この場所に新しい在庫アイテムを作成", + "@stockItemCreateDetail": {}, + "stockItemDelete": "在庫アイテムを削除", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "この在庫アイテムを削除しますか?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "在庫アイテムを削除できませんでした。", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "在庫アイテムを削除しました", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "在庫履歴", + "@stockItemHistory": {}, + "stockItemTransferred": "在庫アイテムが転送されました", + "@stockItemTransferred": {}, + "stockItemUpdated": "在庫アイテムが更新されました", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "在庫アイテムがありません", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "在庫アイテムメモ", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "在庫アイテムが更新されました", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", + "@stockItemUpdateFailure": {}, + "stockLocation": "在庫場所", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "在庫場所", + "@stockLocations": {}, + "stockTopLevel": "トップレベルの在庫場所", + "@stockTopLevel": {}, + "strictHttps": "厳格なHTTPSを使用", + "@strictHttps": {}, + "subcategory": "サブカテゴリー", + "@subcategory": {}, + "subcategories": "サブカテゴリー", + "@subcategories": {}, + "sublocation": "サブ在庫場所", + "@sublocation": {}, + "sublocations": "サブ在庫場所", + "@sublocations": {}, + "sublocationNone": "サブ在庫場所がありません", + "@sublocationNone": {}, + "sublocationNoneDetail": "利用可能なサブ在庫場所がありません", + "@sublocationNoneDetail": {}, + "submitFeedback": "フィードバックを送信", + "@submitFeedback": {}, + "supplier": "サプライヤー", + "@supplier": {}, + "suppliers": "サプライヤー", + "@suppliers": {}, + "takePicture": "画像を撮影", + "@takePicture": {}, + "templatePart": "上位テンプレートパーツ", + "@templatePart": {}, + "testName": "テスト名", + "@testName": {}, + "testPassedOrFailed": "テストの合格または失敗", + "@testPassedOrFailed": {}, + "testsRequired": "必須テスト", + "@testsRequired": {}, + "testResults": "テスト結果", + "@testResults": { + "description": "" + }, + "testResultAdd": "テスト結果を追加", + "@testResultAdd": {}, + "testResultNone": "テスト結果がありません", + "@testResultNone": {}, + "testResultNoneDetail": "利用可能なテスト結果がありません", + "@testResultNoneDetail": {}, + "testResultUploadFail": "テスト結果のアップロードエラー", + "@testResultUploadFail": {}, + "testResultUploadPass": "テスト結果がアップロードされました", + "@testResultUploadPass": {}, + "timeout": "タイムアウト", + "@timeout": { + "description": "" + }, + "tokenError": "トークンエラー", + "@tokenError": {}, + "tokenMissing": "トークンがありません", + "@tokenMissing": {}, + "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", + "@tokenMissingFromResponse": {}, + "transfer": "転送", + "@transfer": { + "description": "transfer" + }, + "transferStock": "在庫の転送", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "翻訳", + "@translate": {}, + "translateHelp": "InvenTree アプリの翻訳に協力する", + "@translateHelp": {}, + "units": "単位", + "@units": {}, + "unknownResponse": "不明な応答", + "@unknownResponse": {}, + "upload": "アップロード", + "@upload": {}, + "uploadFailed": "ファイルのアップロードに失敗しました。", + "@uploadFailed": {}, + "uploadSuccess": "アップロードされたファイル", + "@uploadSuccess": {}, + "username": "ユーザー名", + "@username": {}, + "usernameEmpty": "ユーザー名は空にできません。", + "@usernameEmpty": {}, + "value": "設定値", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "値を空にすることはできません。", + "@valueCannotBeEmpty": {}, + "valueRequired": "値が必要です", + "@valueRequired": {}, + "version": "バージョン", + "@version": {}, + "website": "Webサイト", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 36d80aa..0bc359b 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -1,5 +1,105 @@ { - "@@locale": "en", + "@@locale": "ko", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "add": "추가", + "@add": { + "description": "add" + }, + "address": "주소", + "@address": {}, + "appAbout": "InvenTree 소개", + "@appAbout": {}, + "appReleaseNotes": "앱 릴리즈 노트 표시", + "@appReleaseNotes": {}, + "appSettings": "앱 설정", + "@appSettings": {}, + "billOfMaterials": "부품 명세서", + "@billOfMaterials": {}, + "cancel": "취소", + "@cancel": { + "description": "Cancel" + }, + "company": "회사", + "@company": {}, + "companyEdit": "회사 수정", + "@companyEdit": {}, + "error": "오류", + "@error": { + "description": "Error" + }, + "errorDetails": "오류 세부 정보", + "@errorDetails": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "keywords": "키워드", + "@keywords": {}, + "noResults": "결과 없음", + "@noResults": {}, + "password": "비밀번호", + "@password": {}, + "passwordEmpty": "비밀번호는 비워둘 수 없습니다", + "@passwordEmpty": {}, + "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", + "@permissionAccountDenied": {}, + "profileConnect": "서버에 연결", + "@profileConnect": {}, + "quantity": "수량", + "@quantity": { + "description": "Quantity" + }, + "reportBug": "버그 신고", + "@reportBug": {}, + "response505": "지원되지 않는 HTTP 버전", + "@response505": {}, + "save": "저장", + "@save": { + "description": "Save" + }, + "select": "선택", + "@select": {}, + "selectFile": "파일 선택", + "@selectFile": {}, + "server": "서버", + "@server": {}, + "serverAddress": "서버 주소", + "@serverAddress": {}, + "serverApiRequired": "필요한 API 버전", + "@serverApiRequired": {}, + "serverApiVersion": "서버 API 버전", + "@serverApiVersion": {}, + "serverAuthenticationError": "인증 오류", + "@serverAuthenticationError": {}, + "serverConnecting": "서버에 연결하는 중", + "@serverConnecting": {}, + "serverError": "서버 오류", + "@serverError": {}, + "serverOld": "오래된 서버 버전", + "@serverOld": {}, + "serverSettings": "서버 설정", + "@serverSettings": {}, + "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", + "@serverStart": {}, + "status": "상태", + "@status": {}, + "statusCode": "상태 코드", + "@statusCode": {}, + "targetDate": "목표 날짜", + "@targetDate": {}, + "timeout": "시간 초과", + "@timeout": { + "description": "" + }, + "tokenError": "토큰 오류", + "@tokenError": {}, + "translate": "번역", + "@translate": {}, + "translateHelp": "InvenTree 앱의 번역을 도와주세요", + "@translateHelp": {}, + "version": "버전", + "@version": {}, + "website": "웹사이트", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 36d80aa..40c32de 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "nl", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_no.arb b/lib/l10n/app_no.arb index 36d80aa..34df543 100644 --- a/lib/l10n/app_no.arb +++ b/lib/l10n/app_no.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "no", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 36d80aa..4274486 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1,5 +1,739 @@ { - "@@locale": "en", + "@@locale": "pl", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "O nas", + "@about": {}, + "accountDetails": "Szczegóły konta", + "@accountDetails": {}, + "actions": "Działania", + "@actions": { + "description": "" + }, + "actionsNone": "Brak dostępnych działań", + "@actionsNone": {}, + "add": "Dodaj", + "@add": { + "description": "add" + }, + "addStock": "Dodaj stan", + "@addStock": { + "description": "add stock" + }, + "address": "Adresy", + "@address": {}, + "appAbout": "O InvenTree", + "@appAbout": {}, + "appCredits": "Dodatkowe podziękowania autorskie", + "@appCredits": {}, + "appDetails": "Szczegóły aplikacji", + "@appDetails": {}, + "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", + "@appReleaseNotes": {}, + "appSettings": "Ustawienia aplikacji", + "@appSettings": {}, + "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", + "@appSettingsDetails": {}, + "attachments": "Załączniki", + "@attachments": {}, + "attachImage": "Dodaj zdjęcie", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nie znaleziono załączników", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Brak załączników dla tego komponentu", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Wybierz załącznik", + "@attachmentSelect": {}, + "attention": "Uwaga", + "@attention": {}, + "barcodeAssign": "Przypisz kod kreskowy", + "@barcodeAssign": {}, + "barcodeAssigned": "Kod kreskowy przypisany", + "@barcodeAssigned": {}, + "barcodeError": "Błąd czytnika kodów kreskowych", + "@barcodeError": {}, + "barcodeInUse": "Kod kreskowy jest już przypisany", + "@barcodeInUse": {}, + "barcodeMissingHash": "Brak danych haszujących w odpowiedzi kodu kreskowego", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Brak dopasowania dla kodu kreskowego", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Kod kreskowy nieprzypisany", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Zeskanuj przedmioty do lokalizacji", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skanuj lokalizację zapasów", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skanuj element magazynowy", + "@barcodeScanItem": {}, + "barcodeTones": "Dźwięki kodów kreskowych", + "@barcodeTones": {}, + "barcodeUnassign": "Nieprzydzielony kod kreskowy", + "@barcodeUnassign": {}, + "barcodeUnknown": "Nie rozpoznano kodu kreskowego", + "@barcodeUnknown": {}, + "batchCode": "Kod partii", + "@batchCode": {}, + "billOfMaterials": "Zestawienie materiałów", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Budowa", + "@build": {}, + "building": "Budowanie", + "@building": {}, + "cancel": "Anuluj", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategoria", + "@category": {}, + "categoryCreate": "Nowa Kategoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Utwórz nową kategorię komponentu", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategoria części została zmieniona", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Edytuj Firmę", + "@companyEdit": {}, + "companyNoResults": "Brak firm pasujących do zapytania", + "@companyNoResults": {}, + "companyUpdated": "Szczegóły firmy zostały zaktualizowane", + "@companyUpdated": {}, + "companies": "Firmy", + "@companies": {}, + "configureServer": "Konfiguruj ustawienia serwera", + "@configureServer": {}, + "connectionRefused": "Połączenie odrzucone", + "@connectionRefused": {}, + "count": "Ilość", + "@count": { + "description": "Count" + }, + "countStock": "Przelicz stan", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Podziękowania", + "@credits": {}, + "customers": "Klienci", + "@customers": {}, + "damaged": "Uszkodzone", + "@damaged": {}, + "delete": "Usuń", + "@delete": {}, + "deletePart": "Usuń Komponent", + "@deletePart": {}, + "deletePartDetail": "Usuń ten komponent z bazy danych", + "@deletePartDetail": {}, + "description": "Opis", + "@description": {}, + "destroyed": "Zniszczony", + "@destroyed": {}, + "details": "Szczegóły", + "@details": { + "description": "details" + }, + "documentation": "Dokumentacja", + "@documentation": {}, + "downloading": "Pobieranie Pliku", + "@downloading": {}, + "downloadError": "Błąd Pobierania", + "@downloadError": {}, + "edit": "Edytuj", + "@edit": { + "description": "edit" + }, + "editCategory": "Edytuj kategorię", + "@editCategory": {}, + "editLocation": "Edytuj lokację", + "@editLocation": {}, + "editNotes": "Edytuj Notatki", + "@editNotes": {}, + "editPart": "Edytuj część", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edytuj Pozycję Magazynową", + "@editItem": {}, + "enterPassword": "Wprowadź hasło", + "@enterPassword": {}, + "enterUsername": "Wprowadź nazwę użytkownika", + "@enterUsername": {}, + "error": "Błąd", + "@error": { + "description": "Error" + }, + "errorCreate": "Błąd tworzenia wpisu w bazie danych", + "@errorCreate": {}, + "errorDelete": "Błąd podczas usuwania wpisu bazy danych", + "@errorDelete": {}, + "errorDetails": "Szczegóły błędu", + "@errorDetails": {}, + "errorFetch": "Błąd pobierania danych z serwea", + "@errorFetch": {}, + "errorReporting": "Raportowanie błędów", + "@errorReporting": {}, + "errorReportUpload": "Prześlij raport o błędach", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", + "@errorReportUploadDetails": {}, + "feedback": "Opinie", + "@feedback": {}, + "feedbackError": "Błąd dodawania opinii", + "@feedbackError": {}, + "feedbackSuccess": "Opinia przesłana", + "@feedbackSuccess": {}, + "formatException": "Wyjątek formatowania", + "@formatException": {}, + "formatExceptionJson": "Wyjątek formatu danych JSON", + "@formatExceptionJson": {}, + "formError": "Błąd Formularza", + "@formError": {}, + "history": "Historia", + "@history": { + "description": "history" + }, + "homeScreen": "Ekran główny", + "@homeScreen": {}, + "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", + "@homeScreenSettings": {}, + "homeShowPo": "Pokaż zamówienia zakupu", + "@homeShowPo": {}, + "homeShowSubscribed": "Obserwowane części", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Pokaż dostawców", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Pokaż producentów", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Pokaż przycisk producentów na ekranie głównym", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Pokaż klientów", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Pokaż przycisk klientów na ekranie głównym", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Przesyłanie zdjęcia nie powiodło się", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Obraz przesłany", + "@imageUploadSuccess": {}, + "inactive": "Nieaktywny", + "@inactive": {}, + "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", + "@inactiveDetail": {}, + "includeSubcategories": "Zawieraj podkategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Wyświetl części z podkategorii w widoku listy", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Zawieraj sublokacje", + "@includeSublocations": {}, + "includeSublocationsDetail": "Wyświetl części z sublokacji w widoku listy", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Niekompletne szczegóły profilu", + "@incompleteDetails": {}, + "internalPartNumber": "Wewnętrzny numer części", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "W produkcji", + "@inProduction": {}, + "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", + "@inProductionDetail": {}, + "invalidHost": "Nieprawidłowa nazwa hosta", + "@invalidHost": {}, + "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", + "@invalidHostDetails": {}, + "invalidPart": "Nieprawidłowa część", + "@invalidPart": {}, + "invalidPartCategory": "Nieprawidłowa kategoria części", + "@invalidPartCategory": {}, + "invalidStockLocation": "Nieprawidłowa lokacja magazynowa", + "@invalidStockLocation": {}, + "invalidStockItem": "Nieprawidłowa część magazynowa", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nieprawidłowy login lub hasło", + "@invalidUsernamePassword": {}, + "issueDate": "Data Wystawienia", + "@issueDate": {}, + "itemInLocation": "Część jest już w lokacji", + "@itemInLocation": {}, + "keywords": "Słowa kluczowe", + "@keywords": {}, + "lastStocktake": "Ostatnia inwentaryzacja", + "@lastStocktake": {}, + "lastUpdated": "Ostatnia aktualizacja", + "@lastUpdated": {}, + "lineItem": "Pozycja", + "@lineItem": {}, + "lineItems": "Pozycje", + "@lineItems": {}, + "locationCreate": "Nowa Lokalizacja", + "@locationCreate": {}, + "locationCreateDetail": "Utwórz nową pozycję magazynową", + "@locationCreateDetail": {}, + "locationNotSet": "Nie określono lokacji", + "@locationNotSet": {}, + "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Zagubiono", + "@lost": {}, + "manufacturers": "Producenci", + "@manufacturers": {}, + "missingData": "Brakujące dane", + "@missingData": {}, + "name": "Nazwa", + "@name": {}, + "notConnected": "Nie połączony", + "@notConnected": {}, + "notes": "Notatki", + "@notes": { + "description": "Notes" + }, + "noResponse": "Brak odpowiedzi od serwera", + "@noResponse": {}, + "noResults": "Brak wyników", + "@noResults": {}, + "noSubcategories": "Brak podkategorii", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Brak dostępnych podkategorii", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Błędny numer", + "@numberInvalid": {}, + "onOrder": "W Zamówieniu", + "@onOrder": {}, + "onOrderDetails": "Pozycje obecnie w zamówieniu", + "@onOrderDetails": {}, + "packaging": "Opakowanie", + "@packaging": {}, + "packageName": "Nazwa pakietu", + "@packageName": {}, + "parent": "Nadrzędny", + "@parent": {}, + "parentCategory": "Kategoria nadrzędna", + "@parentCategory": {}, + "parentLocation": "Lokalizacja Nadrzędna", + "@parentLocation": {}, + "part": "Część", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nowy Komponent", + "@partCreate": {}, + "partCreateDetail": "Utwórz nowy komponent w tej kategorii", + "@partCreateDetail": {}, + "partEdited": "Część zaktualizowana", + "@partEdited": {}, + "parts": "Części", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Brak części", + "@partsNone": {}, + "partNoResults": "Brak komponentów pasujących do zapytania", + "@partNoResults": {}, + "partsStarred": "Obserwowane części", + "@partsStarred": {}, + "partsStarredNone": "Brak części oznaczonych gwiazdką", + "@partsStarredNone": {}, + "partSuppliers": "Dostawcy Części", + "@partSuppliers": {}, + "partCategory": "Kategoria części", + "@partCategory": {}, + "partCategoryTopLevel": "Kategoria części najwyższego poziomu", + "@partCategoryTopLevel": {}, + "partCategories": "Kategorie części", + "@partCategories": {}, + "partDetails": "Szczegóły części", + "@partDetails": {}, + "partNotes": "Notatki do części", + "@partNotes": {}, + "partStock": "Zapasy cześci", + "@partStock": { + "description": "part stock" + }, + "password": "Hasło", + "@password": {}, + "passwordEmpty": "Hasło nie może być puste", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", + "@permissionAccountDenied": {}, + "permissionRequired": "Wymagane uprawnienia", + "@permissionRequired": {}, + "printLabel": "Drukuj etykietę", + "@printLabel": {}, + "printLabelFailure": "Drukowanie etykiet nie powiodło się", + "@printLabelFailure": {}, + "printLabelSuccess": "Etykieta wysłana do drukarki", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Dodaj profil serwera", + "@profileAdd": {}, + "profileConnect": "Połącz się z serwerem", + "@profileConnect": {}, + "profileEdit": "Edytuj profil serwera", + "@profileEdit": {}, + "profileDelete": "Usuń profil serwera", + "@profileDelete": {}, + "profileName": "Nazwa Profilu", + "@profileName": {}, + "profileNone": "Brak dostępnych profili", + "@profileNone": {}, + "profileNotSelected": "Nie wybrano profilu", + "@profileNotSelected": {}, + "profileSelect": "Wybierz serwer InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Zlecenie Zakupu", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Zlecenia zakupu", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Cena Zakupu", + "@purchasePrice": {}, + "quantity": "Ilość", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Ilość jest pusta", + "@quantityEmpty": {}, + "quantityInvalid": "Ilość jest nieprawidłowa", + "@quantityInvalid": {}, + "quantityPositive": "Ilość musi być dodatnia", + "@quantityPositive": {}, + "queryNoResults": "Nie znaleziono wyników dla zapytania", + "@queryNoResults": {}, + "received": "Odebrane", + "@received": {}, + "receiveItem": "Przyjmij artykuły", + "@receiveItem": {}, + "receivedItem": "Przyjęta Pozycja Magazynowa", + "@receivedItem": {}, + "refresh": "Odśwież", + "@refresh": {}, + "refreshing": "Odświeżanie", + "@refreshing": {}, + "rejected": "Odrzucono", + "@rejected": {}, + "releaseNotes": "Lista zmian", + "@releaseNotes": {}, + "remove": "Usuń", + "@remove": { + "description": "remove" + }, + "removeStock": "Usuń stan", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Zgłoś błąd", + "@reportBug": {}, + "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", + "@reportBugDescription": {}, + "results": "Wyniki", + "@results": {}, + "request": "Żądanie", + "@request": {}, + "requestingData": "Żądanie danych", + "@requestingData": {}, + "required": "Wymagane", + "@required": { + "description": "This field is required" + }, + "response400": "Błędne żądanie", + "@response400": {}, + "response401": "Nieautoryzowany", + "@response401": {}, + "response403": "Odmowa dostępu", + "@response403": {}, + "response404": "Nie znaleziono", + "@response404": {}, + "response405": "Metoda niedozwolona", + "@response405": {}, + "response429": "Zbyt wiele żądań", + "@response429": {}, + "response500": "Wewnętrzny błąd serwera", + "@response500": {}, + "response501": "Nie zaimplementowano", + "@response501": {}, + "response502": "Zła brama", + "@response502": {}, + "response503": "Usługa niedostępna", + "@response503": {}, + "response504": "Przekroczono limit czasu", + "@response504": {}, + "response505": "Wersja HTTP nie obsługiwana", + "@response505": {}, + "responseData": "Dane odpowiedzi", + "@responseData": {}, + "responseInvalid": "Nieprawidłowy kod odpowiedzi", + "@responseInvalid": {}, + "responseUnknown": "Nieznana odpowiedź", + "@responseUnknown": {}, + "result": "Wynik", + "@result": { + "description": "" + }, + "returned": "Zwrócono", + "@returned": {}, + "salesOrders": "Zlecenia Sprzedaży", + "@salesOrders": {}, + "save": "Zapisz", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skanuj kod kreskowy", + "@scanBarcode": {}, + "scanIntoLocation": "Skanuj do lokacji", + "@scanIntoLocation": {}, + "search": "Szukaj", + "@search": { + "description": "search" + }, + "searchLocation": "Wyszukaj lokalizację", + "@searchLocation": {}, + "searchParts": "Szukaj części", + "@searchParts": {}, + "searchStock": "Szukaj zapasów", + "@searchStock": {}, + "select": "Wybierz", + "@select": {}, + "selectFile": "Wybierz Plik", + "@selectFile": {}, + "selectImage": "Wybierz obraz", + "@selectImage": {}, + "selectLocation": "Wybierz lokację", + "@selectLocation": {}, + "send": "Wyślij", + "@send": {}, + "serialNumber": "Numer seryjny", + "@serialNumber": {}, + "server": "Serwer", + "@server": {}, + "serverAddress": "Adres serwera", + "@serverAddress": {}, + "serverApiRequired": "Wymagana wersja API", + "@serverApiRequired": {}, + "serverApiVersion": "Wersja API serwera", + "@serverApiVersion": {}, + "serverAuthenticationError": "Błąd uwierzytelniania", + "@serverAuthenticationError": {}, + "serverCertificateError": "Błąd certyfikatu", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Certyfikat serwera HTTPS jest nieprawidłowy", + "@serverCertificateInvalid": {}, + "serverConnected": "Połączony z serwerem", + "@serverConnected": {}, + "serverConnecting": "Łączenie z serwerem", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nie można połączyć się z serwerem", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serwer nie może być pusty", + "@serverEmpty": {}, + "serverError": "Błąd serwera", + "@serverError": {}, + "serverDetails": "Szczegóły serwera", + "@serverDetails": {}, + "serverMissingData": "Odpowiedź serwera nie ma wymaganych pól", + "@serverMissingData": {}, + "serverOld": "Stara wersja serwera", + "@serverOld": {}, + "serverSettings": "Ustawienia Serwera", + "@serverSettings": {}, + "serverStart": "Serwer musi zaczynać się od http[s]", + "@serverStart": {}, + "settings": "Ustawienia", + "@settings": {}, + "serverInstance": "Instancja serwera", + "@serverInstance": {}, + "serverNotConnected": "Serwer nie podłączony", + "@serverNotConnected": {}, + "sounds": "Dźwięki", + "@sounds": {}, + "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Kod statusu", + "@statusCode": {}, + "stock": "Stan", + "@stock": { + "description": "stock" + }, + "stockItem": "Element magazynowy", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Elementy magazynowe", + "@stockItems": {}, + "stockItemCreate": "Nowa Pozycja Magazynowa", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Utwórz nową pozycję magazynową w tej lokalizacji", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Usuń przedmiot magazynowy", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Czy jesteś pewien, że chcesz usunąć ten przedmiot magazynowy?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Nie można usunąć przedmiotu magazynowego", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Przedmiot magazynowy usunięty", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historia zapasów", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Wyświetl historyczne informacje o śledzeniu stanów magazynowych", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Element magazynowy przeniesiony", + "@stockItemTransferred": {}, + "stockItemUpdated": "Zaktualizowano element magazynowy", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Brak dostępnych elementów", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notatki przedmiotu magazynowego", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Zaktualizowano element magazynowy", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Nie zaktualizowano elementu magazynowego", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lokacja stanu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lokacje stanów", + "@stockLocations": {}, + "stockTopLevel": "Najwyższy poziom lokalizacji magazynu", + "@stockTopLevel": {}, + "strictHttps": "Ścisły HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Wymuś ścisłe sprawdzanie certyfikatów HTTPS", + "@strictHttpsDetails": {}, + "subcategory": "Podkategoria", + "@subcategory": {}, + "subcategories": "Podkategorie", + "@subcategories": {}, + "sublocation": "Sublokacja", + "@sublocation": {}, + "sublocations": "Subblokacje", + "@sublocations": {}, + "sublocationNone": "Brak subblokacji", + "@sublocationNone": {}, + "sublocationNoneDetail": "Brak dostępnych podlokalizacji", + "@sublocationNoneDetail": {}, + "submitFeedback": "Prześlij opinię", + "@submitFeedback": {}, + "suppliedParts": "Dostarczone Części", + "@suppliedParts": {}, + "supplier": "Dostawca", + "@supplier": {}, + "suppliers": "Dostawcy", + "@suppliers": {}, + "supplierReference": "Identyfikator Dostawcy", + "@supplierReference": {}, + "takePicture": "Zrób zdjęcie", + "@takePicture": {}, + "targetDate": "Data Docelowa", + "@targetDate": {}, + "testName": "Nazwa testu", + "@testName": {}, + "testPassedOrFailed": "Test zaliczony lub nieudany", + "@testPassedOrFailed": {}, + "testsRequired": "Wymagane testy", + "@testsRequired": {}, + "testResults": "Wyniki testu", + "@testResults": { + "description": "" + }, + "testResultAdd": "Dodaj wynik testu", + "@testResultAdd": {}, + "testResultNone": "Brak wyników testu", + "@testResultNone": {}, + "testResultNoneDetail": "Brak dostępnych wyników testu", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Błąd przesyłania wyniku testu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Wynik testu przesłany", + "@testResultUploadPass": {}, + "timeout": "Upłynął limit czasu", + "@timeout": { + "description": "" + }, + "tokenError": "Błąd tokenu", + "@tokenError": {}, + "tokenMissing": "Brakujący token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", + "@tokenMissingFromResponse": {}, + "transfer": "Przenieś", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Przenieś stan", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Przetłumacz", + "@translate": {}, + "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", + "@translateHelp": {}, + "units": "Jednostki", + "@units": {}, + "unknownResponse": "Nieznana odpowiedź", + "@unknownResponse": {}, + "upload": "Wyślij", + "@upload": {}, + "uploadFailed": "Błąd wysyłania pliku", + "@uploadFailed": {}, + "uploadSuccess": "Plik przesłany", + "@uploadSuccess": {}, + "usedIn": "Użyte w", + "@usedIn": {}, + "usedInDetails": "Złożenie, które wymagają tego komponentu", + "@usedInDetails": {}, + "username": "Nazwa użytkownika", + "@username": {}, + "usernameEmpty": "Nazwa użytkownika nie może być pusta", + "@usernameEmpty": {}, + "value": "Wartość", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Wartość nie może być pusta", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wartość jest wymagana", + "@valueRequired": {}, + "version": "Wersja", + "@version": {}, + "viewSupplierPart": "Zobacz Dostawcę Części", + "@viewSupplierPart": {}, + "website": "Strona WWW", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 36d80aa..65bbe17 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1,5 +1,193 @@ { - "@@locale": "en", + "@@locale": "pt", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Sobre", + "@about": {}, + "accountDetails": "Detalhes da Conta", + "@accountDetails": {}, + "actions": "Ações", + "@actions": { + "description": "" + }, + "actionsNone": "Nenhuma ação disponível", + "@actionsNone": {}, + "add": "Adicionar", + "@add": { + "description": "add" + }, + "addStock": "Adicionar ao estoque", + "@addStock": { + "description": "add stock" + }, + "address": "Endereço", + "@address": {}, + "appAbout": "Sobre o InvenTree", + "@appAbout": {}, + "appCredits": "Créditos adicionais do aplicativo", + "@appCredits": {}, + "appDetails": "Detalhes do App", + "@appDetails": {}, + "appReleaseNotes": "Exibir notas de versão do aplicativo", + "@appReleaseNotes": {}, + "appSettings": "Configurações do App", + "@appSettings": {}, + "appSettingsDetails": "Configurar os parâmetros do InvenTree", + "@appSettingsDetails": {}, + "attachments": "Anexos", + "@attachments": {}, + "attachImage": "Anexar Imagem", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Não foram encontrados quaisquer anexos", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Selecionar anexo", + "@attachmentSelect": {}, + "attention": "Aviso", + "@attention": {}, + "barcodeAssign": "Atribuir Código de Barras", + "@barcodeAssign": {}, + "barcodeAssigned": "Código de barras atribuído", + "@barcodeAssigned": {}, + "barcodeError": "Erro ao escanear código de barras", + "@barcodeError": {}, + "barcodeInUse": "Código de barras já atribuído", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Não corresponde a nenhum código de barras", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Código de barras não atribuído", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Escaneie para atribuir código de barras", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Escaneie itens de estoque no local", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear Localização", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Escaneado no local", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "Escanear ítem", + "@barcodeScanItem": {}, + "barcodeTones": "Tons do código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Remover código de barras pre-designado", + "@barcodeUnassign": {}, + "barcodeUnknown": "Código de barras não reconhecido", + "@barcodeUnknown": {}, + "batchCode": "Código de lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiais", + "@billOfMaterials": {}, + "bom": "Lista de Materiais", + "@bom": {}, + "build": "Compilar", + "@build": {}, + "building": "Compilando", + "@building": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nova Categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Criar nova categoria de peças", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria de peça atualizada", + "@categoryUpdated": {}, + "company": "Empresa", + "@company": {}, + "companyEdit": "Editar empresa", + "@companyEdit": {}, + "companyNoResults": "Nenhuma empresa corresponde a consulta", + "@companyNoResults": {}, + "companyUpdated": "Dados da empresa atualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "configureServer": "Configurar os parâmetros do servidor de email", + "@configureServer": {}, + "connectionRefused": "Conexão recusada", + "@connectionRefused": {}, + "count": "Contagem", + "@count": { + "description": "Count" + }, + "countStock": "Contagem de Estoque", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "customers": "Clientes", + "@customers": {}, + "damaged": "Danificado", + "@damaged": {}, + "delete": "Excluir", + "@delete": {}, + "deletePart": "Excluir esta parte", + "@deletePart": {}, + "deletePartDetail": "Remover esta peça da base de dados", + "@deletePartDetail": {}, + "description": "Descrição", + "@description": {}, + "destroyed": "Destruído", + "@destroyed": {}, + "details": "Detalhes", + "@details": { + "description": "details" + }, + "documentation": "Documentação", + "@documentation": {}, + "downloading": "Baixando arquivo", + "@downloading": {}, + "downloadError": "Erro de download", + "@downloadError": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editCategory": "Editar categoria", + "@editCategory": {}, + "editLocation": "Editar Localização", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editPart": "Editar a peça", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar Item do Estoque", + "@editItem": {}, + "enterPassword": "Digite a senha", + "@enterPassword": {}, + "enterUsername": "Inserir usuário", + "@enterUsername": {}, + "error": "Erro", + "@error": { + "description": "Error" + }, + "errorCreate": "Erro ao criar entrada de banco de dados", + "@errorCreate": {}, + "errorDelete": "Erro ao excluir entrada no banco de dados", + "@errorDelete": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "lastUpdated": "Ultima atualização", + "@lastUpdated": {}, + "lineItems": "Itens de linha", + "@lineItems": {} } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 36d80aa..d89f472 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1,5 +1,263 @@ { - "@@locale": "en", + "@@locale": "ru", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "ОК", + "@ok": { + "description": "OK" + }, + "about": "О проекте", + "@about": {}, + "accountDetails": "Данные аккаунта", + "@accountDetails": {}, + "actions": "Действия", + "@actions": { + "description": "" + }, + "actionsNone": "Действия недоступны", + "@actionsNone": {}, + "add": "Добавить", + "@add": { + "description": "add" + }, + "addStock": "Добавить запасы", + "@addStock": { + "description": "add stock" + }, + "address": "Адрес", + "@address": {}, + "appAbout": "О InvenTree", + "@appAbout": {}, + "appCredits": "Благодарности за помощь и поддержку", + "@appCredits": {}, + "appDetails": "Информация о приложении", + "@appDetails": {}, + "appReleaseNotes": "Показать заметки о выпуске приложения", + "@appReleaseNotes": {}, + "appSettings": "Настройки приложения", + "@appSettings": {}, + "companyNoResults": "Нет организаций, соответствующих запросу", + "@companyNoResults": {}, + "downloading": "Загрузка файла", + "@downloading": {}, + "downloadError": "Ошибка загрузки", + "@downloadError": {}, + "edit": "Изменить", + "@edit": { + "description": "edit" + }, + "editCategory": "Редактировать категорию", + "@editCategory": {}, + "editLocation": "Редактировать местонахождение", + "@editLocation": {}, + "editNotes": "Редактировать примечания", + "@editNotes": {}, + "editPart": "Ред. эту часть", + "@editPart": { + "description": "edit part" + }, + "editItem": "Отредактированный товар", + "@editItem": {}, + "enterPassword": "Введите пароль", + "@enterPassword": {}, + "enterUsername": "Введите имя пользователя", + "@enterUsername": {}, + "error": "Ошибка", + "@error": { + "description": "Error" + }, + "errorCreate": "Ошибка создания записи базы данных", + "@errorCreate": {}, + "errorDetails": "Подробнее об ошибке", + "@errorDetails": {}, + "errorFetch": "Ошибка при получении данных с сервера", + "@errorFetch": {}, + "feedback": "Обратная Связь", + "@feedback": {}, + "feedbackError": "Ошибка отправки отзыва", + "@feedbackError": {}, + "feedbackSuccess": "Отзыв отправлен", + "@feedbackSuccess": {}, + "formatException": "Формат исключения", + "@formatException": {}, + "formatExceptionJson": "Ошибка формата JSON", + "@formatExceptionJson": {}, + "formError": "Ошибка в форме", + "@formError": {}, + "history": "История", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Не удалось загрузить изображение", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Изображение загружено", + "@imageUploadSuccess": {}, + "inactive": "Неактивный", + "@inactive": {}, + "inactiveDetail": "Эта часть помечена как неактивная", + "@inactiveDetail": {}, + "includeSubcategories": "Включить подкатегории", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Отображать подкатегории в виде списка", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Добавить доп. местоположения", + "@includeSublocations": {}, + "includeSublocationsDetail": "Отображать доп. местоположения в виде списка", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Неполные данные профиля", + "@incompleteDetails": {}, + "internalPartNumber": "Внутренний номер", + "@internalPartNumber": {}, + "info": "Информация", + "@info": {}, + "invalidHost": "Неверное имя хоста", + "@invalidHost": {}, + "invalidHostDetails": "Недопустимый пароль", + "@invalidHostDetails": {}, + "invalidPart": "Недопустимый элемент", + "@invalidPart": {}, + "invalidPartCategory": "Неверная категория элемента", + "@invalidPartCategory": {}, + "invalidStockLocation": "Неверное расположение склада", + "@invalidStockLocation": {}, + "invalidStockItem": "Недопустимый товарный пункт", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", + "@invalidUsernamePassword": {}, + "issueDate": "Дата проблемы", + "@issueDate": {}, + "itemInLocation": "Элемент уже находится на месте", + "@itemInLocation": {}, + "keywords": "Ключевые слова", + "@keywords": {}, + "lastStocktake": "Последняя инвентаризация", + "@lastStocktake": {}, + "lastUpdated": "Последние обновлённые", + "@lastUpdated": {}, + "lineItem": "Элемент строки", + "@lineItem": {}, + "lineItems": "Элементы строки", + "@lineItems": {}, + "locationCreate": "Новое местоположение", + "@locationCreate": {}, + "locationCreateDetail": "Создать новое расположение склада", + "@locationCreateDetail": {}, + "locationNotSet": "Не указано месторасположение", + "@locationNotSet": {}, + "link": "Ссылка", + "@link": {}, + "lost": "Потерян", + "@lost": {}, + "manufacturers": "Производители", + "@manufacturers": {}, + "missingData": "Отсутствующие данные", + "@missingData": {}, + "name": "Название", + "@name": {}, + "notConnected": "Соединение не установлено", + "@notConnected": {}, + "notes": "Заметки", + "@notes": { + "description": "Notes" + }, + "noResponse": "Нет ответа от сервера", + "@noResponse": {}, + "noResults": "Нет результатов", + "@noResults": {}, + "noSubcategories": "Нет подкатегории", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Нет доступных подкатегорий", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Неправильный номер", + "@numberInvalid": {}, + "onOrder": "Под заказ", + "@onOrder": {}, + "onOrderDetails": "Заказаные элементы", + "@onOrderDetails": {}, + "packaging": "Упаковка", + "@packaging": {}, + "packageName": "Название упаковки", + "@packageName": {}, + "parent": "Родитель", + "@parent": {}, + "parentCategory": "Родительская категория", + "@parentCategory": {}, + "parentLocation": "Родительское местоположение", + "@parentLocation": {}, + "part": "Компонент", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Новый компонент", + "@partCreate": {}, + "partCreateDetail": "Создать компонент в данной категории", + "@partCreateDetail": {}, + "parts": "Номенклатура", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Нет компонентов", + "@partsNone": {}, + "partNoResults": "Нет компонентов, соответствующих запросу", + "@partNoResults": {}, + "response405": "405 Метод не разрешен", + "@response405": {}, + "response429": "Слишком много запросов", + "@response429": {}, + "response500": "Внутренняя ошибка сервера", + "@response500": {}, + "response501": "Не реализовано", + "@response501": {}, + "response502": "Недопустимый шлюз", + "@response502": {}, + "response503": "Сервис недоступен", + "@response503": {}, + "response504": "504: тайм-аут шлюза", + "@response504": {}, + "response505": "505: версия не поддерживается", + "@response505": {}, + "responseData": "Информация об ответе", + "@responseData": {}, + "responseInvalid": "Неверный код ответа", + "@responseInvalid": {}, + "responseUnknown": "Неизвестный ответ", + "@responseUnknown": {}, + "result": "Результат", + "@result": { + "description": "" + }, + "returned": "Возвращено", + "@returned": {}, + "salesOrders": "Заказы на продажу", + "@salesOrders": {}, + "save": "Сохранить", + "@save": { + "description": "Save" + }, + "scanBarcode": "Сканировать штрихкод", + "@scanBarcode": {}, + "scanIntoLocation": "Сканировать в местоположение", + "@scanIntoLocation": {}, + "search": "Поиск", + "@search": { + "description": "search" + }, + "searchLocation": "Искать по месту", + "@searchLocation": {}, + "searchParts": "Найти номенклатуру", + "@searchParts": {}, + "searchStock": "Поиск в наличии", + "@searchStock": {}, + "select": "Выбрать", + "@select": {}, + "selectFile": "Выбрать файл", + "@selectFile": {}, + "selectImage": "Выбрать изображение", + "@selectImage": {}, + "website": "Сайт", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 36d80aa..e37c200 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "sv", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index 36d80aa..5fdf211 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "th", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 36d80aa..447ecee 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -1,5 +1,735 @@ { - "@@locale": "en", + "@@locale": "tr", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "TAMAM", + "@ok": { + "description": "OK" + }, + "about": "Hakkında", + "@about": {}, + "accountDetails": "Hesap Detayları", + "@accountDetails": {}, + "actions": "Eylemler", + "@actions": { + "description": "" + }, + "actionsNone": "Kullanılabilir eylem yok", + "@actionsNone": {}, + "add": "Ekle", + "@add": { + "description": "add" + }, + "addStock": "Stok ekle", + "@addStock": { + "description": "add stock" + }, + "address": "Adres", + "@address": {}, + "appAbout": "InvenTree Hakkında", + "@appAbout": {}, + "appCredits": "Uygulama kredisi ekle", + "@appCredits": {}, + "appDetails": "Uygulama Detayları", + "@appDetails": {}, + "appReleaseNotes": "Uygulama yayınlama notları", + "@appReleaseNotes": {}, + "appSettings": "Uygulama Ayarları", + "@appSettings": {}, + "appSettingsDetails": "Uygulama ayarlarından yapılandır", + "@appSettingsDetails": {}, + "attachments": "Ekler", + "@attachments": {}, + "attachImage": "Resim ekle", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Hiçbir ek bulunamadı", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Ek seçin", + "@attachmentSelect": {}, + "attention": "Dikkat", + "@attention": {}, + "barcodeAssign": "Barkod Ata", + "@barcodeAssign": {}, + "barcodeAssigned": "Barkod atandı", + "@barcodeAssigned": {}, + "barcodeError": "Barkod tarama hatası", + "@barcodeError": {}, + "barcodeInUse": "Barkod zaten kullanımda", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash verisi alınamadı", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Barkod için eşleşme yok", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barkod atanmış değil", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Atanmış barkodu tara", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Bir Iventree barkodu tara", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Stok öğelerini konum içine tara", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Stok konumu tara", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Konuma tarandı", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Madde taranmış değil", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Stok öğesi tara", + "@barcodeScanItem": {}, + "barcodeTones": "Barkod Tonları", + "@barcodeTones": {}, + "barcodeUnassign": "Atanmamış barkod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barkod tanınmadı", + "@barcodeUnknown": {}, + "batchCode": "Grup kodu", + "@batchCode": {}, + "billOfMaterials": "Fatura materyalleri", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Oluştur", + "@build": {}, + "building": "Oluşturma", + "@building": {}, + "cancel": "İptal", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Yeni Kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Yeni parça kategorisi oluştur", + "@categoryCreateDetail": {}, + "categoryUpdated": "Parça Kategorisi güncellendi", + "@categoryUpdated": {}, + "company": "Şirket", + "@company": {}, + "companyEdit": "Şirketi Düzenle", + "@companyEdit": {}, + "companyNoResults": "Sorguyla eşleşen şirket yok", + "@companyNoResults": {}, + "companyUpdated": "Firma bilgileri güncellendi", + "@companyUpdated": {}, + "companies": "Şirketler", + "@companies": {}, + "configureServer": "Sunucu ayarlarınızı yapılandırın", + "@configureServer": {}, + "connectionRefused": "Bağlantı reddedildi", + "@connectionRefused": {}, + "count": "Sayım", + "@count": { + "description": "Count" + }, + "countStock": "Stok sayımı", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Katkıda Bulunanlar", + "@credits": {}, + "customers": "Müşteriler", + "@customers": {}, + "damaged": "Hasarlı", + "@damaged": {}, + "delete": "Sil", + "@delete": {}, + "deletePart": "Parça Sil", + "@deletePart": {}, + "deletePartDetail": "Bu parçayı veritabanından kaldır", + "@deletePartDetail": {}, + "description": "Açıklama", + "@description": {}, + "destroyed": "Yok edildi", + "@destroyed": {}, + "details": "Detaylar", + "@details": { + "description": "details" + }, + "documentation": "Dökümantasyon", + "@documentation": {}, + "downloading": "Dosya indiriliyor", + "@downloading": {}, + "downloadError": "İndirme Hatası", + "@downloadError": {}, + "edit": "Düzenle", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategoriyi düzenle", + "@editCategory": {}, + "editLocation": "Konumu Düzenle", + "@editLocation": {}, + "editNotes": "Notları Düzenle", + "@editNotes": {}, + "editPart": "Parçayı Düzenle", + "@editPart": { + "description": "edit part" + }, + "editItem": "Parçayı Düzenle", + "@editItem": {}, + "enterPassword": "Şifrenizi girin", + "@enterPassword": {}, + "enterUsername": "Kullanıcı adını girin", + "@enterUsername": {}, + "error": "Hata", + "@error": { + "description": "Error" + }, + "errorCreate": "Veritabanı girdi oluşturma hatası", + "@errorCreate": {}, + "errorDelete": "Veritabanı girdisini silerken hata", + "@errorDelete": {}, + "errorDetails": "Hata Ayrıntıları", + "@errorDetails": {}, + "errorFetch": "Sunucudan veri alınırken hata oluştu", + "@errorFetch": {}, + "errorReporting": "Hata Raporlama", + "@errorReporting": {}, + "errorReportUpload": "Hata raporu yükle", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonim olarak hata ve log yükle", + "@errorReportUploadDetails": {}, + "feedback": "Geri Bildirim", + "@feedback": {}, + "feedbackError": "Geribildirim gönderme hatası", + "@feedbackError": {}, + "feedbackSuccess": "Geri bildirim gönderildi", + "@feedbackSuccess": {}, + "formatException": "Biçim İstisnası", + "@formatException": {}, + "formatExceptionJson": "JSON veri format istisnası", + "@formatExceptionJson": {}, + "formError": "Form hatası", + "@formError": {}, + "history": "Geçmiş", + "@history": { + "description": "history" + }, + "homeScreen": "Ana Ekran", + "@homeScreen": {}, + "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", + "@homeScreenSettings": {}, + "homeShowPo": "Satın Alma Siparişlerini Göster", + "@homeShowPo": {}, + "homeShowSubscribed": "Parça bildirimlerine abone ol", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Tedarikçileri Göster", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Üreticileri Göster", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Müşterileri Göster", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Fotoğraf yükleme başarısız", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Resim yüklendi", + "@imageUploadSuccess": {}, + "inactive": "Pasif", + "@inactive": {}, + "inactiveDetail": "Bu parça pasif olarak işaretlendi", + "@inactiveDetail": {}, + "includeSubcategories": "Alt kategorileri dahil et", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Alt kategori parçalarını liste görünümünde göster", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alt konumları dahil et", + "@includeSublocations": {}, + "includeSublocationsDetail": "Alt konum parçalarını liste görünümünde göster", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Tamamlanmamış profil detayları", + "@incompleteDetails": {}, + "internalPartNumber": "İç Parça Numarası", + "@internalPartNumber": {}, + "info": "Bilgi", + "@info": {}, + "inProduction": "Yapım Aşamasında", + "@inProduction": {}, + "inProductionDetail": "Bu ürün üretim aşamasında", + "@inProductionDetail": {}, + "invalidHost": "Geçersiz alan adı", + "@invalidHost": {}, + "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", + "@invalidHostDetails": {}, + "invalidPart": "Geçersiz Parça", + "@invalidPart": {}, + "invalidPartCategory": "Geçersiz Parça Kategorisi", + "@invalidPartCategory": {}, + "invalidStockLocation": "Geçersiz Stok Konumu", + "@invalidStockLocation": {}, + "invalidStockItem": "Geçersiz Stok Parçası", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", + "@invalidUsernamePassword": {}, + "issueDate": "Sorun Tarihi", + "@issueDate": {}, + "itemInLocation": "Parça zaten konumda", + "@itemInLocation": {}, + "keywords": "Anahtar kelimeler", + "@keywords": {}, + "lastStocktake": "Son stok tutma", + "@lastStocktake": {}, + "lastUpdated": "Son güncelleme", + "@lastUpdated": {}, + "lineItem": "Parça Sırası", + "@lineItem": {}, + "lineItems": "Parçalar Sırası", + "@lineItems": {}, + "locationCreate": "Yeni Konum", + "@locationCreate": {}, + "locationCreateDetail": "Yeni stok konumu oluştur", + "@locationCreateDetail": {}, + "locationNotSet": "Belirtilmiş konum yok", + "@locationNotSet": {}, + "locationUpdated": "Stok lokasyonu güncellendi", + "@locationUpdated": {}, + "link": "Bağlantı", + "@link": {}, + "lost": "Kayıp", + "@lost": {}, + "manufacturers": "Üreticiler", + "@manufacturers": {}, + "missingData": "Eksik Veri", + "@missingData": {}, + "name": "Adı", + "@name": {}, + "notConnected": "Bağlı değil", + "@notConnected": {}, + "notes": "Notlar", + "@notes": { + "description": "Notes" + }, + "noResponse": "Sunucudan yanıt yok", + "@noResponse": {}, + "noResults": "Sonuç Yok", + "@noResults": {}, + "noSubcategories": "Alt kategori yok", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Uygun alt kategori yok", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Geçersiz numara", + "@numberInvalid": {}, + "onOrder": "Siparişte", + "@onOrder": {}, + "onOrderDetails": "Parça şuan siparişte", + "@onOrderDetails": {}, + "packaging": "Paketleme", + "@packaging": {}, + "packageName": "Paket İsmi", + "@packageName": {}, + "parent": "Üst", + "@parent": {}, + "parentCategory": "Üst Kategori", + "@parentCategory": {}, + "parentLocation": "Bağlı lokasyon", + "@parentLocation": {}, + "part": "Parça", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Yeni Parça", + "@partCreate": {}, + "partCreateDetail": "Yeni parça kategorisi oluştur", + "@partCreateDetail": {}, + "partEdited": "Parça Güncellendi", + "@partEdited": {}, + "parts": "Parçalar", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Parça Yok", + "@partsNone": {}, + "partNoResults": "Sorguyla eşleşen parça yok", + "@partNoResults": {}, + "partsStarred": "Sürekli Gelen parçalar", + "@partsStarred": {}, + "partsStarredNone": "Yıldızlı parça yok", + "@partsStarredNone": {}, + "partSuppliers": "Parça Tedarikçileri", + "@partSuppliers": {}, + "partCategory": "Parça Kategorileri", + "@partCategory": {}, + "partCategoryTopLevel": "Üst seviye parça kategorisi", + "@partCategoryTopLevel": {}, + "partCategories": "Parça Kategorileri", + "@partCategories": {}, + "partDetails": "Parça detayları", + "@partDetails": {}, + "partNotes": "Parça notları", + "@partNotes": {}, + "partStock": "Parça stok", + "@partStock": { + "description": "part stock" + }, + "password": "Parola", + "@password": {}, + "passwordEmpty": "Parola boş bırakılamaz", + "@passwordEmpty": {}, + "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", + "@permissionAccountDenied": {}, + "permissionRequired": "İzin Gerekli", + "@permissionRequired": {}, + "printLabel": "Etiket Yazdır", + "@printLabel": {}, + "printLabelFailure": "Etiket yazdırılamadı", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiket yazıcıya gönderildi", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Yeni Sunucu Profili Ekle", + "@profileAdd": {}, + "profileConnect": "Sunucuya bağlan", + "@profileConnect": {}, + "profileEdit": "Sunucu Profilini düzenle", + "@profileEdit": {}, + "profileDelete": "Sunucu profilini sil", + "@profileDelete": {}, + "profileName": "Profil Adı", + "@profileName": {}, + "profileNone": "Kullanılabiir profil yok", + "@profileNone": {}, + "profileNotSelected": "Profil seçilmedi", + "@profileNotSelected": {}, + "profileSelect": "InvenTree sunucusu seç", + "@profileSelect": {}, + "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", + "@profileTapToCreate": {}, + "purchaseOrder": "Satınalma Siparişi", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Satın Alma siparişini düzenle", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Satınalma Siparişleri", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Alış Fiyatı", + "@purchasePrice": {}, + "quantity": "Adet", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Adet boş", + "@quantityEmpty": {}, + "quantityInvalid": "Adet geçersiz", + "@quantityInvalid": {}, + "quantityPositive": "Adet pozitif bir sayı olmalı", + "@quantityPositive": {}, + "queryNoResults": "Sorgu için sonuç yok", + "@queryNoResults": {}, + "received": "Alınan", + "@received": {}, + "receiveItem": "Alınan Öğeler", + "@receiveItem": {}, + "receivedItem": "Alınan stok parçaları", + "@receivedItem": {}, + "refresh": "Yenile", + "@refresh": {}, + "refreshing": "Yenileniyor", + "@refreshing": {}, + "rejected": "Reddedildi", + "@rejected": {}, + "releaseNotes": "Sürüm notları", + "@releaseNotes": {}, + "remove": "Kaldır", + "@remove": { + "description": "remove" + }, + "removeStock": "Stok Kaldır", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hata Bildir", + "@reportBug": {}, + "reportBugDescription": "Hata raporla ( github hesabı gerektirir)", + "@reportBugDescription": {}, + "results": "Sonuçlar", + "@results": {}, + "request": "Talep", + "@request": {}, + "requestingData": "Veri Talep Ediliyor", + "@requestingData": {}, + "required": "Gerekli", + "@required": { + "description": "This field is required" + }, + "response400": "Hatalı İstek", + "@response400": {}, + "response401": "Yetkisiz", + "@response401": {}, + "response403": "İzin Engellendi", + "@response403": {}, + "response404": "Kaynak bulunamadı", + "@response404": {}, + "response405": "İzin Verilmeyen Yöntem", + "@response405": {}, + "response429": "Çok Fazla İstek", + "@response429": {}, + "response500": "İç Sunucu Hatası", + "@response500": {}, + "response501": "Uygulanamadı", + "@response501": {}, + "response502": "Hatalı Ağ Geçidi", + "@response502": {}, + "response503": "Hizmet Kullanılamıyor", + "@response503": {}, + "response504": "Ağ Geçidi Zaman Aşımı", + "@response504": {}, + "response505": "HTTP Sürümü Desteklenmiyor", + "@response505": {}, + "responseData": "Yanıt verileri", + "@responseData": {}, + "responseInvalid": "Geçersiz yanıt kodu.", + "@responseInvalid": {}, + "responseUnknown": "Bilinmeyen yanıt", + "@responseUnknown": {}, + "result": "Sonuç", + "@result": { + "description": "" + }, + "returned": "Geri Dönen", + "@returned": {}, + "salesOrders": "Satış Siparişleri", + "@salesOrders": {}, + "save": "Kaydet", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barkod Tara", + "@scanBarcode": {}, + "scanIntoLocation": "Konuma Tara", + "@scanIntoLocation": {}, + "search": "Ara", + "@search": { + "description": "search" + }, + "searchLocation": "Konum için Ara", + "@searchLocation": {}, + "searchParts": "Parçaları Ara", + "@searchParts": {}, + "searchStock": "Stok Ara", + "@searchStock": {}, + "select": "Seç", + "@select": {}, + "selectFile": "Dosya Seç", + "@selectFile": {}, + "selectImage": "Resim Seç", + "@selectImage": {}, + "selectLocation": "Bir yer seçin", + "@selectLocation": {}, + "send": "Gönder", + "@send": {}, + "serialNumber": "Seri Numara", + "@serialNumber": {}, + "server": "Sunucu", + "@server": {}, + "serverAddress": "Sunucu Adresi", + "@serverAddress": {}, + "serverApiRequired": "Gerekli API Sürümü", + "@serverApiRequired": {}, + "serverApiVersion": "Sunucu API Sürümü", + "@serverApiVersion": {}, + "serverAuthenticationError": "Doğrulama Hatası", + "@serverAuthenticationError": {}, + "serverCertificateError": "Sertifika Hatası", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Sunucunun sertifikası geçersiz", + "@serverCertificateInvalid": {}, + "serverConnected": "Sunucuya bağlanıldı", + "@serverConnected": {}, + "serverConnecting": "Sunucuya bağlanıyor", + "@serverConnecting": {}, + "serverCouldNotConnect": "Sunucuya bağlanılamadı", + "@serverCouldNotConnect": {}, + "serverEmpty": "Sunucu boş olamaz", + "@serverEmpty": {}, + "serverError": "Sunucu Hatası", + "@serverError": {}, + "serverDetails": "Sunucu Detayları", + "@serverDetails": {}, + "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", + "@serverMissingData": {}, + "serverOld": "Eski Sunucu Sürümü", + "@serverOld": {}, + "serverSettings": "Sunucu Ayarları", + "@serverSettings": {}, + "serverStart": "Sunucu http(s) ile başlamalı", + "@serverStart": {}, + "settings": "Ayarlar", + "@settings": {}, + "serverInstance": "Sunucu örneği", + "@serverInstance": {}, + "serverNotConnected": "Sunucu bağlı değil", + "@serverNotConnected": {}, + "sounds": "Sesler", + "@sounds": {}, + "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Sunucu hatasında sesli ton çal", + "@soundOnServerError": {}, + "status": "Durum", + "@status": {}, + "statusCode": "Durum Kodu", + "@statusCode": {}, + "stock": "Stok", + "@stock": { + "description": "stock" + }, + "stockItem": "Stok Kalemi", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stok Kalemleri", + "@stockItems": {}, + "stockItemCreate": "Yeni Stok Kalemi", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Stok parçasını sil", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Stok parçası silinemedi", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stok parçası silindi", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stok Geçmişi", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Stok takip bilgisini göster", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stok kalemi transfer edildi", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stok kalemi güncellendi", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Uygun stok kalemi yok", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stok Kalemi Notları", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stok kalemi güncellendi", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stok kalemi güncelleme hatası", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stok Konumu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stok Konumları", + "@stockLocations": {}, + "stockTopLevel": "Üst seviye stok konumu", + "@stockTopLevel": {}, + "subcategory": "Alt kategori", + "@subcategory": {}, + "subcategories": "Alt kategoriler", + "@subcategories": {}, + "sublocation": "Alt konumlar", + "@sublocation": {}, + "sublocations": "Alt konumlar", + "@sublocations": {}, + "sublocationNone": "Alt konum yok", + "@sublocationNone": {}, + "sublocationNoneDetail": "Uygun alt kategori yok", + "@sublocationNoneDetail": {}, + "submitFeedback": "Geri Bildirim Gönder", + "@submitFeedback": {}, + "suppliedParts": "Sağlanan Parçalar", + "@suppliedParts": {}, + "supplier": "Tedarikçi", + "@supplier": {}, + "suppliers": "Tedarikçiler", + "@suppliers": {}, + "supplierReference": "Tedarikçi Referansı", + "@supplierReference": {}, + "takePicture": "Resim Çek", + "@takePicture": {}, + "targetDate": "Hedeflenen Tarih", + "@targetDate": {}, + "testName": "Test Adı", + "@testName": {}, + "testPassedOrFailed": "Test başarılı veya hatalı", + "@testPassedOrFailed": {}, + "testsRequired": "Gerekli Testler", + "@testsRequired": {}, + "testResults": "Test Sonuçları", + "@testResults": { + "description": "" + }, + "testResultAdd": "Test Sonucu Ekle", + "@testResultAdd": {}, + "testResultNone": "Test Sonucu Yok", + "@testResultNone": {}, + "testResultNoneDetail": "Uygun test sonucu yok", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hatalı yüklenen test sonucu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test sonucu yüklendi", + "@testResultUploadPass": {}, + "timeout": "Zaman Aşımı", + "@timeout": { + "description": "" + }, + "tokenError": "Token Hatası", + "@tokenError": {}, + "tokenMissing": "Eksik Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", + "@tokenMissingFromResponse": {}, + "transfer": "Aktarım", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Stok Aktar", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Çeviri", + "@translate": {}, + "translateHelp": "Çeviriye yardım et", + "@translateHelp": {}, + "units": "Birim", + "@units": {}, + "unknownResponse": "Bilinmeyen Yanıt", + "@unknownResponse": {}, + "upload": "Yükle", + "@upload": {}, + "uploadFailed": "Dosya yüklenemedi", + "@uploadFailed": {}, + "uploadSuccess": "Dosya yüklendi", + "@uploadSuccess": {}, + "usedIn": "Burada Kullanıldı", + "@usedIn": {}, + "usedInDetails": "Bu parçayı gerektiren montajlar", + "@usedInDetails": {}, + "username": "Kullanıcı Adı", + "@username": {}, + "usernameEmpty": "Kullanıcı adı boş bırakılamaz", + "@usernameEmpty": {}, + "value": "Değer", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Değer boş olamaz", + "@valueCannotBeEmpty": {}, + "valueRequired": "Değer gereklidir", + "@valueRequired": {}, + "version": "Sürüm", + "@version": {}, + "viewSupplierPart": "Tedarikçi Parçası Görüntüle", + "@viewSupplierPart": {}, + "website": "Web sitesi", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 36d80aa..08adba6 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "vi", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 36d80aa..a94ee5b 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,5 +1,341 @@ { - "@@locale": "en", + "@@locale": "zh", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "好", + "@ok": { + "description": "OK" + }, + "about": "关于", + "@about": {}, + "accountDetails": "账户详情", + "@accountDetails": {}, + "actions": "操作", + "@actions": { + "description": "" + }, + "add": "添加", + "@add": { + "description": "add" + }, + "addStock": "添加库存", + "@addStock": { + "description": "add stock" + }, + "address": "地址", + "@address": {}, + "appAbout": "关于 InventTree", + "@appAbout": {}, + "appDetails": "应用详情", + "@appDetails": {}, + "appSettings": "应用设置", + "@appSettings": {}, + "attention": "注意", + "@attention": {}, + "barcodeAssign": "分配条码", + "@barcodeAssign": {}, + "barcodeAssigned": "条码已分配", + "@barcodeAssigned": {}, + "barcodeError": "条形码扫描出错", + "@barcodeError": {}, + "barcodeInUse": "条码已经被分配", + "@barcodeInUse": {}, + "barcodeNoMatch": "无匹配条码", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "未分配条码", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "扫描以分配条码", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "扫描 InvenTree 条码", + "@barcodeScanGeneral": {}, + "barcodeScanLocation": "扫描库存地点", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "已扫描至位置", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "扫描库存项", + "@barcodeScanItem": {}, + "barcodeUnassign": "取消分配条码", + "@barcodeUnassign": {}, + "barcodeUnknown": "无法识别条码", + "@barcodeUnknown": {}, + "build": "生产", + "@build": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "category": "分类", + "@category": {}, + "categoryCreate": "新建分类", + "@categoryCreate": {}, + "categoryCreateDetail": "新建商品类别", + "@categoryCreateDetail": {}, + "company": "公司", + "@company": {}, + "companyEdit": "编辑公司信息", + "@companyEdit": {}, + "companies": "公司", + "@companies": {}, + "connectionRefused": "连接被拒绝", + "@connectionRefused": {}, + "count": "数量", + "@count": { + "description": "Count" + }, + "countStock": "库存数量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "致谢", + "@credits": {}, + "damaged": "破损", + "@damaged": {}, + "delete": "删除", + "@delete": {}, + "description": "描述", + "@description": {}, + "destroyed": "销毁", + "@destroyed": {}, + "details": "详细信息", + "@details": { + "description": "details" + }, + "documentation": "文档", + "@documentation": {}, + "edit": "编辑", + "@edit": { + "description": "edit" + }, + "editCategory": "编辑分类", + "@editCategory": {}, + "editLocation": "编辑位置", + "@editLocation": {}, + "editPart": "编辑部件", + "@editPart": { + "description": "edit part" + }, + "error": "错误", + "@error": { + "description": "Error" + }, + "errorDetails": "c w错误详情", + "@errorDetails": {}, + "history": "历史", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "internalPartNumber": "内部部件号", + "@internalPartNumber": {}, + "info": "信息", + "@info": {}, + "invalidPart": "无效部件", + "@invalidPart": {}, + "invalidPartCategory": "无效部件分类", + "@invalidPartCategory": {}, + "invalidStockLocation": "无效库存位置", + "@invalidStockLocation": {}, + "invalidStockItem": "无效库存项", + "@invalidStockItem": {}, + "keywords": "关键词", + "@keywords": {}, + "link": "链接", + "@link": {}, + "lost": "丢失", + "@lost": {}, + "name": "名称", + "@name": {}, + "notConnected": "未连接", + "@notConnected": {}, + "notes": "注释", + "@notes": { + "description": "Notes" + }, + "noResponse": "服务器未响应", + "@noResponse": {}, + "parent": "父级", + "@parent": {}, + "parentCategory": "父类别", + "@parentCategory": {}, + "part": "部件", + "@part": { + "description": "Part (single)" + }, + "parts": "部件", + "@parts": { + "description": "Part (multiple)" + }, + "partCategory": "部件分类", + "@partCategory": {}, + "partCategories": "部件分类", + "@partCategories": {}, + "partDetails": "部件详情", + "@partDetails": {}, + "partNotes": "部件注释", + "@partNotes": {}, + "partStock": "部件库存", + "@partStock": { + "description": "part stock" + }, + "password": "密码", + "@password": {}, + "profile": "档案", + "@profile": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "容量为空", + "@quantityEmpty": {}, + "quantityInvalid": "数量无效", + "@quantityInvalid": {}, + "quantityPositive": "数量必须大于0", + "@quantityPositive": {}, + "refresh": "刷新", + "@refresh": {}, + "refreshing": "正在刷新", + "@refreshing": {}, + "rejected": "已拒绝", + "@rejected": {}, + "releaseNotes": "更新日志", + "@releaseNotes": {}, + "remove": "移除", + "@remove": { + "description": "remove" + }, + "removeStock": "移除库存", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "反馈问题", + "@reportBug": {}, + "request": "请求", + "@request": {}, + "requestingData": "正在请求数据", + "@requestingData": {}, + "required": "必填", + "@required": { + "description": "This field is required" + }, + "responseInvalid": "无效响应码", + "@responseInvalid": {}, + "responseUnknown": "未知响应", + "@responseUnknown": {}, + "result": "结果", + "@result": { + "description": "" + }, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "扫描条码", + "@scanBarcode": {}, + "scanIntoLocation": "已扫描至位置", + "@scanIntoLocation": {}, + "search": "搜索", + "@search": { + "description": "search" + }, + "searchParts": "搜索部件", + "@searchParts": {}, + "searchStock": "搜索库存", + "@searchStock": {}, + "select": "选择", + "@select": {}, + "send": "发送", + "@send": {}, + "serialNumber": "序列号", + "@serialNumber": {}, + "server": "服务器", + "@server": {}, + "serverAddress": "服务器地址", + "@serverAddress": {}, + "serverConnected": "已连接至服务器", + "@serverConnected": {}, + "serverError": "服务器错误", + "@serverError": {}, + "serverDetails": "服务器详情", + "@serverDetails": {}, + "serverOld": "过时的服务器版本", + "@serverOld": {}, + "serverSettings": "服务器设置", + "@serverSettings": {}, + "settings": "设置", + "@settings": {}, + "serverInstance": "服务器实例", + "@serverInstance": {}, + "serverNotConnected": "未连接至服务器", + "@serverNotConnected": {}, + "status": "状态", + "@status": {}, + "statusCode": "状态码", + "@statusCode": {}, + "stock": "库存", + "@stock": { + "description": "stock" + }, + "stockItem": "库存项", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "库存项", + "@stockItems": {}, + "stockItemNotes": "库存项注释", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "库存项已更新", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "库存项更新失败", + "@stockItemUpdateFailure": {}, + "stockLocation": "库存位置", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "库存位置", + "@stockLocations": {}, + "subcategory": "子类别", + "@subcategory": {}, + "subcategories": "子类别", + "@subcategories": {}, + "sublocation": "次级位置", + "@sublocation": {}, + "sublocations": "次级位置", + "@sublocations": {}, + "testResults": "测试结果", + "@testResults": { + "description": "" + }, + "timeout": "超时", + "@timeout": { + "description": "" + }, + "tokenError": "令牌错误", + "@tokenError": {}, + "tokenMissing": "缺少令牌", + "@tokenMissing": {}, + "transfer": "转移", + "@transfer": { + "description": "transfer" + }, + "transferStock": "转移库存", + "@transferStock": { + "description": "transfer stock" + }, + "unknownResponse": "未知响应", + "@unknownResponse": {}, + "upload": "上传", + "@upload": {}, + "username": "用户名", + "@username": {}, + "value": "值", + "@value": { + "description": "value" + }, + "version": "版本", + "@version": {}, + "website": "网站", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py deleted file mode 100644 index f1987e3..0000000 --- a/lib/l10n/collect_translations.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -Collect translation files into a single directory, -where they can be accessed by the flutter i18n library. - -Translations provided from crowdin are located in subdirectories, -but we need the .arb files to appear in this top level directory -to be accessed by the app. - -So, simply copy them here! - -""" - -import os -import shutil -import re -import json - -def process_locale_file(filename): - """ - Process a locale file after copying - - - Ensure the 'locale' matches - """ - - # Extract the locale name from the filename - f = os.path.basename(filename) - locale = re.search(r"^app\_(\w+)\.arb$", f).groups()[0] - - # TODO: Use JSON processing instead of manual - # Need to work out unicode issues for this to work - - with open(filename, 'r', encoding='utf-8') as input_file: - - lines = input_file.readlines() - - with open(filename, 'w', encoding='utf-8') as output_file: - # Using JSON processing would be simpler here, - # but it does not preserve unicode data! - for line in lines: - if '@@locale' in line: - new_line = f' "@@locale": "{locale}"' - - if ',' in line: - new_line += ',' - - new_line += '\n' - - line = new_line - - output_file.write(line) - - -def copy_locale_file(path): - """ - Locate and copy the locale file from the provided directory - """ - - here = os.path.abspath(os.path.dirname(__file__)) - - for f in os.listdir(path): - - src = os.path.join(path, f) - dst = os.path.join(here, 'collected', f) - - if os.path.exists(src) and os.path.isfile(src) and f.endswith('.arb'): - - shutil.copyfile(src, dst) - print(f"Copied file '{f}'") - - process_locale_file(dst) - - -if __name__ == '__main__': - - here = os.path.abspath(os.path.dirname(__file__)) - - # Ensure the 'collected' output directory exists - output_dir = os.path.join(here, 'collected') - os.makedirs(output_dir, exist_ok=True) - - for item in os.listdir(here): - - # Ignore the output directory - if item == 'collected': - continue - - f = os.path.join(here, item) - - if os.path.exists(f) and os.path.isdir(item): - copy_locale_file(f) - - # Ensure the translation source file ('app_en.arb') is copied also - # Note that this does not require any further processing - src = os.path.join(here, 'app_en.arb') - dst = os.path.join(here, 'collected', 'app_en.arb') - - shutil.copyfile(src, dst) diff --git a/lib/l10n/crowdin.yml b/lib/l10n/crowdin.yml deleted file mode 100644 index dfa2384..0000000 --- a/lib/l10n/crowdin.yml +++ /dev/null @@ -1,3 +0,0 @@ -files: - - source: app_en.arb - translation: app_%two_letters_code%.arb diff --git a/lib/l10n/cs/app_cs.arb b/lib/l10n/cs/app_cs.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/cs/app_cs.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/de/app_de.arb b/lib/l10n/de/app_de.arb deleted file mode 100644 index 799c802..0000000 --- a/lib/l10n/de/app_de.arb +++ /dev/null @@ -1,745 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Über", - "@about": {}, - "accountDetails": "Konto Details", - "@accountDetails": {}, - "actions": "Aktionen", - "@actions": { - "description": "" - }, - "actionsNone": "Keine Aktionen verfügbar", - "@actionsNone": {}, - "add": "Hinzufügen", - "@add": { - "description": "add" - }, - "addStock": "Bestand hinzufügen", - "@addStock": { - "description": "add stock" - }, - "address": "Adresse", - "@address": {}, - "appAbout": "Über InvenTree", - "@appAbout": {}, - "appCredits": "Weitere App-Danksagungen", - "@appCredits": {}, - "appDetails": "App-Informationen", - "@appDetails": {}, - "appReleaseNotes": "App-Versionshinweise anzeigen", - "@appReleaseNotes": {}, - "appSettings": "App-Einstellungen", - "@appSettings": {}, - "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", - "@appSettingsDetails": {}, - "attachments": "Anhänge", - "@attachments": {}, - "attachImage": "Bild hinzufügen", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Keine Anhänge gefunden", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Anhang auswählen", - "@attachmentSelect": {}, - "attention": "Achtung", - "@attention": {}, - "availableStock": "Verfügbarer Lagerbestand", - "@availableStock": {}, - "barcodeAssign": "Barcode zuweisen", - "@barcodeAssign": {}, - "barcodeAssigned": "Barcode zugewiesen", - "@barcodeAssigned": {}, - "barcodeError": "Fehler beim Scannen des Barcodes", - "@barcodeError": {}, - "barcodeInUse": "Barcode wurde bereits zugewiesen", - "@barcodeInUse": {}, - "barcodeMissingHash": "Prüfsumme fehlt in Antwort", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Keine Übereinstimmung für den Barcode", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode nicht zugewiesen", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scannen um Barcode zuzuweisen", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Einen InvenTree Barcode scannen", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Artikel per Barcode-Scan zu Lagerort hinzufügen", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Lagerort scannen", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Artikel scannen", - "@barcodeScanItem": {}, - "barcodeTones": "Barcode-Ton", - "@barcodeTones": {}, - "barcodeUnassign": "Barcode entfernen", - "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode wurde nicht erkannt", - "@barcodeUnknown": {}, - "batchCode": "Losnummer", - "@batchCode": {}, - "billOfMaterials": "Stückliste", - "@billOfMaterials": {}, - "bom": "Stückliste", - "@bom": {}, - "build": "Bauauftrag", - "@build": {}, - "building": "Gebäude", - "@building": {}, - "cancel": "Abbrechen", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategorie", - "@category": {}, - "categoryCreate": "Neue Kategorie", - "@categoryCreate": {}, - "categoryCreateDetail": "Teile-Kategorie anlegen", - "@categoryCreateDetail": {}, - "categoryUpdated": "Kategorie aktualisiert", - "@categoryUpdated": {}, - "company": "Firma", - "@company": {}, - "companyEdit": "Firma bearbeiten", - "@companyEdit": {}, - "companyNoResults": "Keine Firmen entsprechen der Anfrage", - "@companyNoResults": {}, - "companyUpdated": "Firmendetails aktualisiert", - "@companyUpdated": {}, - "companies": "Firmen", - "@companies": {}, - "configureServer": "Server-Einstellungen konfigurieren", - "@configureServer": {}, - "connectionRefused": "Verbindung verweigert", - "@connectionRefused": {}, - "count": "Zählen", - "@count": { - "description": "Count" - }, - "countStock": "Bestand zählen", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Danksagungen", - "@credits": {}, - "customers": "Kunden", - "@customers": {}, - "damaged": "Beschädigt", - "@damaged": {}, - "delete": "Löschen", - "@delete": {}, - "deletePart": "Teil löschen", - "@deletePart": {}, - "deletePartDetail": "Dieses Teil aus der Datenbank löschen", - "@deletePartDetail": {}, - "description": "Beschreibung", - "@description": {}, - "destroyed": "Vernichtet", - "@destroyed": {}, - "details": "Details", - "@details": { - "description": "details" - }, - "documentation": "Dokumentation", - "@documentation": {}, - "downloading": "Datei wird heruntergeladen", - "@downloading": {}, - "downloadError": "Fehler beim Herunterladen", - "@downloadError": {}, - "edit": "Bearbeiten", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategorie bearbeiten", - "@editCategory": {}, - "editLocation": "Ort bearbeiten", - "@editLocation": {}, - "editNotes": "Notizen bearbeiten", - "@editNotes": {}, - "editPart": "Teil bearbeiten", - "@editPart": { - "description": "edit part" - }, - "editItem": "Artikel bearbeiten", - "@editItem": {}, - "enterPassword": "Passwort eingeben", - "@enterPassword": {}, - "enterUsername": "Benutzername eingeben", - "@enterUsername": {}, - "error": "Fehler", - "@error": { - "description": "Error" - }, - "errorCreate": "Fehler beim Erstellen des Datenbankeintrages", - "@errorCreate": {}, - "errorDelete": "Fehler beim Löschen von Datenbankeintrag", - "@errorDelete": {}, - "errorDetails": "Fehlerdetails", - "@errorDetails": {}, - "errorFetch": "Fehler beim Abrufen der Daten vom Server", - "@errorFetch": {}, - "errorReporting": "Fehlerberichterstattung", - "@errorReporting": {}, - "errorReportUpload": "Fehlerberichte hochladen", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", - "@errorReportUploadDetails": {}, - "feedback": "Feedback", - "@feedback": {}, - "feedbackError": "Fehler beim Senden des Feedbacks", - "@feedbackError": {}, - "feedbackSuccess": "Feedback gesendet", - "@feedbackSuccess": {}, - "formatException": "Formatfehler", - "@formatException": {}, - "formatExceptionJson": "Format-Fehler im JSON", - "@formatExceptionJson": {}, - "formError": "Formular-Fehler", - "@formError": {}, - "history": "Verlauf", - "@history": { - "description": "history" - }, - "homeScreen": "Startseite", - "@homeScreen": {}, - "homeScreenSettings": "Einstellungen für Startseite konfigurieren", - "@homeScreenSettings": {}, - "homeShowPo": "Bestellungen anzeigen", - "@homeShowPo": {}, - "homeShowSubscribed": "Abonnierte Teile", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Lieferanten anzeigen", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Hersteller anzeigen", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Hersteller auf Startseite anzeigen", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Kunden anzeigen", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Kunden auf Startseite anzeigen", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Das Bild konnte nicht hochgeladen werden", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Bild hochgeladen", - "@imageUploadSuccess": {}, - "inactive": "Inaktiv", - "@inactive": {}, - "inactiveDetail": "Teil als inaktiv gekennzeichnet", - "@inactiveDetail": {}, - "includeSubcategories": "Unter-Kategorien einschließen", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Teile aus Unter-Kategorien anzeigen", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Unter-Lagerorte einschließen", - "@includeSublocations": {}, - "includeSublocationsDetail": "Liste der Unter-Lagerorte anzeigen", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Profil unvollständig", - "@incompleteDetails": {}, - "internalPartNumber": "Interne Teilenummer", - "@internalPartNumber": {}, - "info": "Info", - "@info": {}, - "inProduction": "In Produktion", - "@inProduction": {}, - "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", - "@inProductionDetail": {}, - "invalidHost": "Ungültiger Hostname", - "@invalidHost": {}, - "invalidHostDetails": "Der angegebener Hostname ist ungültig", - "@invalidHostDetails": {}, - "invalidPart": "Ungültiges Teil", - "@invalidPart": {}, - "invalidPartCategory": "Ungültige Teil-Kategorie", - "@invalidPartCategory": {}, - "invalidStockLocation": "Ungültiger Lagerort", - "@invalidStockLocation": {}, - "invalidStockItem": "Ungültiger Artikel", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", - "@invalidUsernamePassword": {}, - "issueDate": "Ausstellungsdatum", - "@issueDate": {}, - "itemInLocation": "Artikel ist bereits in diesem Lagerort", - "@itemInLocation": {}, - "keywords": "Schlüsselwörter", - "@keywords": {}, - "lastStocktake": "Letzte Inventur", - "@lastStocktake": {}, - "lastUpdated": "Letzte Änderung", - "@lastUpdated": {}, - "lineItem": "Position", - "@lineItem": {}, - "lineItems": "Positionen", - "@lineItems": {}, - "locationCreate": "Neuer Lagerort", - "@locationCreate": {}, - "locationCreateDetail": "Neuen Lagerort erstellen", - "@locationCreateDetail": {}, - "locationNotSet": "Lagerort nicht angegeben", - "@locationNotSet": {}, - "locationUpdated": "Lagerort aktualisiert", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Verloren", - "@lost": {}, - "manufacturers": "Hersteller", - "@manufacturers": {}, - "missingData": "Fehlende Daten", - "@missingData": {}, - "name": "Name", - "@name": {}, - "notConnected": "Nicht verbunden", - "@notConnected": {}, - "notes": "Notizen", - "@notes": { - "description": "Notes" - }, - "noResponse": "Keine Antwort vom Server", - "@noResponse": {}, - "noResults": "Keine Ergebnisse", - "@noResults": {}, - "noSubcategories": "Keine Unter-Kategorien", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Keine gültige Zahl", - "@numberInvalid": {}, - "onOrder": "Bestellt", - "@onOrder": {}, - "onOrderDetails": "Artikel wurde bestellt", - "@onOrderDetails": {}, - "packaging": "Paket", - "@packaging": {}, - "packageName": "Paket-Name", - "@packageName": {}, - "parent": "Übergeordnetes", - "@parent": {}, - "parentCategory": "Übergeordnete Kategorie", - "@parentCategory": {}, - "parentLocation": "Übergeordneter Lagerort", - "@parentLocation": {}, - "part": "Teil", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Teil anlegen", - "@partCreate": {}, - "partCreateDetail": "Teil in dieser Kategorie anlegen", - "@partCreateDetail": {}, - "partEdited": "Teil aktualisiert", - "@partEdited": {}, - "parts": "Teile", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Keine Teile", - "@partsNone": {}, - "partNoResults": "Keine Teile entsprechen der Anfrage", - "@partNoResults": {}, - "partsStarred": "Abonnierte Teile", - "@partsStarred": {}, - "partsStarredNone": "Keine Teile abonniert", - "@partsStarredNone": {}, - "partSuppliers": "Teile-Lieferanten", - "@partSuppliers": {}, - "partCategory": "Teil-Kategorie", - "@partCategory": {}, - "partCategoryTopLevel": "Oberste Teile-Kategorie", - "@partCategoryTopLevel": {}, - "partCategories": "Teil-Kategorien", - "@partCategories": {}, - "partDetails": "Teil-Details", - "@partDetails": {}, - "partNotes": "Teil-Bemerkungen", - "@partNotes": {}, - "partStock": "Teilbestand", - "@partStock": { - "description": "part stock" - }, - "password": "Passwort", - "@password": {}, - "passwordEmpty": "Passwort darf nicht leer sein", - "@passwordEmpty": {}, - "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", - "@permissionAccountDenied": {}, - "permissionRequired": "Berechtigung erforderlich", - "@permissionRequired": {}, - "printLabel": "Label drucken", - "@printLabel": {}, - "printLabelFailure": "Labeldruck fehlgeschlagen", - "@printLabelFailure": {}, - "printLabelSuccess": "Label an den Drucker gesendet", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Server-Profil anlegen", - "@profileAdd": {}, - "profileConnect": "Mit Server verbinden", - "@profileConnect": {}, - "profileEdit": "Server-Profil bearbeiten", - "@profileEdit": {}, - "profileDelete": "Server-Profil löschen", - "@profileDelete": {}, - "profileName": "Profil-Name", - "@profileName": {}, - "profileNone": "Keine Profile angelegt", - "@profileNone": {}, - "profileNotSelected": "Kein Profil ausgewählt", - "@profileNotSelected": {}, - "profileSelect": "InvenTree-Server auswählen", - "@profileSelect": {}, - "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", - "@profileTapToCreate": {}, - "purchaseOrder": "Bestellung", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Bestellung bearbeiten", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Bestellungen", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Bestellung aktualisiert", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Einkaufspreis", - "@purchasePrice": {}, - "quantity": "Anzahl", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Menge ist leer", - "@quantityEmpty": {}, - "quantityInvalid": "Menge ist ungültig", - "@quantityInvalid": {}, - "quantityPositive": "Menge muss positiv sein", - "@quantityPositive": {}, - "queryNoResults": "Keine Ergebnisse für die Anfrage", - "@queryNoResults": {}, - "received": "Empfangen", - "@received": {}, - "receiveItem": "Artikel erhalten", - "@receiveItem": {}, - "receivedItem": "Artikel wurde erhalten", - "@receivedItem": {}, - "refresh": "Neu laden", - "@refresh": {}, - "refreshing": "Aktualisiere", - "@refreshing": {}, - "rejected": "Zurückgewiesen", - "@rejected": {}, - "releaseNotes": "Versionshinweise", - "@releaseNotes": {}, - "remove": "Entfernen", - "@remove": { - "description": "remove" - }, - "removeStock": "Bestand entfernen", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Fehler melden", - "@reportBug": {}, - "reportBugDescription": "Fehlerbericht senden (erfordert GitHub Konto)", - "@reportBugDescription": {}, - "results": "Ergebnisse", - "@results": {}, - "request": "Anfrage", - "@request": {}, - "requestingData": "Daten werden angefordert", - "@requestingData": {}, - "required": "Erforderlich", - "@required": { - "description": "This field is required" - }, - "response400": "Ungültige Anfrage", - "@response400": {}, - "response401": "Nicht autorisiert", - "@response401": {}, - "response403": "Zugriff verweigert", - "@response403": {}, - "response404": "Ressource nicht gefunden", - "@response404": {}, - "response405": "Methode nicht erlaubt", - "@response405": {}, - "response429": "Zu viele Anfragen", - "@response429": {}, - "response500": "Interner Serverfehler", - "@response500": {}, - "response501": "Nicht Implementiert", - "@response501": {}, - "response502": "Fehlerhaftes Gateway", - "@response502": {}, - "response503": "Dienst nicht verfügbar", - "@response503": {}, - "response504": "Gateway-Zeitüberschreitung", - "@response504": {}, - "response505": "HTTP-Version wird nicht unterstützt", - "@response505": {}, - "responseData": "Antwort-Daten", - "@responseData": {}, - "responseInvalid": "Ungültiger Antwort-Code", - "@responseInvalid": {}, - "responseUnknown": "Unbekannte Antwort", - "@responseUnknown": {}, - "result": "Ergebnis", - "@result": { - "description": "" - }, - "returned": "Retourniert", - "@returned": {}, - "salesOrders": "Kundenauftrag", - "@salesOrders": {}, - "save": "Speichern", - "@save": { - "description": "Save" - }, - "scanBarcode": "Barcode scannen", - "@scanBarcode": {}, - "scanIntoLocation": "In Lagerorten buchen", - "@scanIntoLocation": {}, - "search": "Suchen", - "@search": { - "description": "search" - }, - "searchLocation": "Lagerort suchen", - "@searchLocation": {}, - "searchParts": "Teile suchen", - "@searchParts": {}, - "searchStock": "Bestand durchsuchen", - "@searchStock": {}, - "select": "Auswählen", - "@select": {}, - "selectFile": "Datei auswählen", - "@selectFile": {}, - "selectImage": "Bild auswählen", - "@selectImage": {}, - "selectLocation": "Wähle einen Lagerort", - "@selectLocation": {}, - "send": "Senden", - "@send": {}, - "serialNumber": "Seriennummer", - "@serialNumber": {}, - "server": "Server", - "@server": {}, - "serverAddress": "Serveradresse", - "@serverAddress": {}, - "serverApiRequired": "Erforderliche API-Version", - "@serverApiRequired": {}, - "serverApiVersion": "API-Version des Servers", - "@serverApiVersion": {}, - "serverAuthenticationError": "Anmeldung fehlgeschlagen", - "@serverAuthenticationError": {}, - "serverCertificateError": "Zertifikatsfehler", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Zertifikat des Servers ist ungültig", - "@serverCertificateInvalid": {}, - "serverConnected": "Verbunden mit Server", - "@serverConnected": {}, - "serverConnecting": "Verbindung zum Server wird aufgebaut", - "@serverConnecting": {}, - "serverCouldNotConnect": "Verbindung zum Server nicht möglich", - "@serverCouldNotConnect": {}, - "serverEmpty": "Server darf nicht leer sein", - "@serverEmpty": {}, - "serverError": "Serverfehler", - "@serverError": {}, - "serverDetails": "Serverdetails", - "@serverDetails": {}, - "serverMissingData": "In der Server-Antwort fehlen erforderliche Felder", - "@serverMissingData": {}, - "serverOld": "Alte Server Version", - "@serverOld": {}, - "serverSettings": "Server Einstellungen", - "@serverSettings": {}, - "serverStart": "Server muss mit http[s] beginnen", - "@serverStart": {}, - "settings": "Einstellungen", - "@settings": {}, - "serverInstance": "Server Instanz", - "@serverInstance": {}, - "serverNotConnected": "Server nicht verbunden", - "@serverNotConnected": {}, - "sounds": "Töne", - "@sounds": {}, - "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Ton bei Serverfehler abspielen", - "@soundOnServerError": {}, - "status": "Status", - "@status": {}, - "statusCode": "Statuscode", - "@statusCode": {}, - "stock": "Bestand", - "@stock": { - "description": "stock" - }, - "stockDetails": "Aktuell verfügbare Lagermenge", - "@stockDetails": {}, - "stockItem": "Artikel", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Artikel", - "@stockItems": {}, - "stockItemCreate": "Neuen Artikel anlegen", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Neuen Artikel an diesem Lagerort erstellen", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Lagerartikel löschen", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Sind Sie sicher, dass Sie diesen Lagerartikel löschen wollen?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Lagerbestand konnte nicht gelöscht werden", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Lagerbestand gelöscht", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historie des Artikels", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Zeige historische Bestandsverfolgungsdaten", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Artikel umgezogen", - "@stockItemTransferred": {}, - "stockItemUpdated": "Artikel aktualisiert", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Keine Artikel verfügbar", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notizen zum Artikel", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Artikel aktualisiert", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Fehler bei Artikel-Aktualisierung", - "@stockItemUpdateFailure": {}, - "stockLocation": "Lagerort", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Lagerorte", - "@stockLocations": {}, - "stockTopLevel": "Oberster Lagerort", - "@stockTopLevel": {}, - "strictHttps": "Striktes HTTPS verwenden", - "@strictHttps": {}, - "strictHttpsDetails": "Erzwinge strenge Überprüfung von HTTPs-Zertifikaten", - "@strictHttpsDetails": {}, - "subcategory": "Unterkategorie", - "@subcategory": {}, - "subcategories": "Unterkategorien", - "@subcategories": {}, - "sublocation": "Unter-Lagerort", - "@sublocation": {}, - "sublocations": "Unter-Lagerorte", - "@sublocations": {}, - "sublocationNone": "Keine Unter-Lagerorte", - "@sublocationNone": {}, - "sublocationNoneDetail": "Keine Unter-Lagerorte verfügbar", - "@sublocationNoneDetail": {}, - "submitFeedback": "Feedback geben", - "@submitFeedback": {}, - "suppliedParts": "Gelieferte Teile", - "@suppliedParts": {}, - "supplier": "Lieferant", - "@supplier": {}, - "suppliers": "Lieferanten", - "@suppliers": {}, - "supplierReference": "Lieferanten-Referenz", - "@supplierReference": {}, - "takePicture": "Foto aufnehmen", - "@takePicture": {}, - "targetDate": "Zieldatum", - "@targetDate": {}, - "templatePart": "Übergeordnetes Vorlagenteil", - "@templatePart": {}, - "testName": "Test-Name", - "@testName": {}, - "testPassedOrFailed": "Test erfolgreich oder fehlgeschlagen", - "@testPassedOrFailed": {}, - "testsRequired": "Erforderliche Tests", - "@testsRequired": {}, - "testResults": "Testergebnisse", - "@testResults": { - "description": "" - }, - "testResultAdd": "Testergebnis hinzufügen", - "@testResultAdd": {}, - "testResultNone": "Keine Testergebnisse", - "@testResultNone": {}, - "testResultNoneDetail": "Keine Testergebnisse vorhanden", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Fehler beim Hochladen des Testergebnisses", - "@testResultUploadFail": {}, - "testResultUploadPass": "Testergebnis hochgeladen", - "@testResultUploadPass": {}, - "timeout": "Zeitüberschreitung", - "@timeout": { - "description": "" - }, - "tokenError": "Token-Fehler", - "@tokenError": {}, - "tokenMissing": "Token fehlt", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", - "@tokenMissingFromResponse": {}, - "transfer": "Verschieben", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Bestand verschieben", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Übersetzen", - "@translate": {}, - "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", - "@translateHelp": {}, - "units": "Einheiten", - "@units": {}, - "unknownResponse": "Unbekannte Antwort", - "@unknownResponse": {}, - "upload": "Hochladen", - "@upload": {}, - "uploadFailed": "Datei hochladen fehlgeschlagen", - "@uploadFailed": {}, - "uploadSuccess": "Datei hochgeladen", - "@uploadSuccess": {}, - "usedIn": "Verwendet in", - "@usedIn": {}, - "usedInDetails": "Baugruppen, die dieses Teil benötigen", - "@usedInDetails": {}, - "username": "Benutzername", - "@username": {}, - "usernameEmpty": "Der Benutzername darf nicht leer sein", - "@usernameEmpty": {}, - "value": "Wert", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Dieser Wert darf nicht leer sein", - "@valueCannotBeEmpty": {}, - "valueRequired": "Wert erforderlich", - "@valueRequired": {}, - "version": "Version", - "@version": {}, - "viewSupplierPart": "Zulieferer-Teil anzeigen", - "@viewSupplierPart": {}, - "website": "Website", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/el/app_el.arb b/lib/l10n/el/app_el.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/el/app_el.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/es-419/app_es.arb b/lib/l10n/es-419/app_es.arb deleted file mode 100644 index 9dae4a2..0000000 --- a/lib/l10n/es-419/app_es.arb +++ /dev/null @@ -1,3 +0,0 @@ -{ - "@@locale": "en" -} \ No newline at end of file diff --git a/lib/l10n/es-ES/app_es.arb b/lib/l10n/es-ES/app_es.arb deleted file mode 100644 index 03bfe46..0000000 --- a/lib/l10n/es-ES/app_es.arb +++ /dev/null @@ -1,635 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Acerca de", - "@about": {}, - "accountDetails": "Detalles de cuenta", - "@accountDetails": {}, - "actions": "Acciones", - "@actions": { - "description": "" - }, - "actionsNone": "No hay acciones disponibles", - "@actionsNone": {}, - "add": "Añadir", - "@add": { - "description": "add" - }, - "addStock": "Añadir stock", - "@addStock": { - "description": "add stock" - }, - "address": "Dirección", - "@address": {}, - "appAbout": "Acerca de InvenTree", - "@appAbout": {}, - "appCredits": "Créditos de aplicación adicionales", - "@appCredits": {}, - "appDetails": "Detalles de la aplicación", - "@appDetails": {}, - "appReleaseNotes": "Mostrar notas de versión de la aplicación", - "@appReleaseNotes": {}, - "appSettings": "Configuración de la aplicación", - "@appSettings": {}, - "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", - "@appSettingsDetails": {}, - "attachments": "Archivos adjuntos", - "@attachments": {}, - "attachImage": "Adjuntar imagen", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "No se encontraron archivos adjuntos", - "@attachmentNone": {}, - "attachmentNonePartDetail": "No se encontraron archivos adjuntos para esta parte", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Seleccionar archivo adjunto", - "@attachmentSelect": {}, - "attention": "Atención", - "@attention": {}, - "availableStock": "Stock Disponible", - "@availableStock": {}, - "barcodeAssign": "Asignar código de barras", - "@barcodeAssign": {}, - "barcodeAssigned": "Código de barras asignado", - "@barcodeAssigned": {}, - "barcodeError": "Error al escanear código de barras", - "@barcodeError": {}, - "barcodeInUse": "Código de barras ya asignado", - "@barcodeInUse": {}, - "barcodeMissingHash": "Faltan datos de código de barras en la respuesta", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "No hay coincidencia para código de barras", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Código de barras no asignado", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Escanear para asignar código de barras", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Escanear un código de barras de InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Escanear artículos de stock a la ubicación", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Escanear ubicación de stock", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Artículo no escaneado en", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Escanear artículo de stock", - "@barcodeScanItem": {}, - "barcodeTones": "Tonos de código de barras", - "@barcodeTones": {}, - "barcodeUnassign": "Desasignar código de barras", - "@barcodeUnassign": {}, - "barcodeUnknown": "El código de barras no reconocido", - "@barcodeUnknown": {}, - "batchCode": "Numero de lote", - "@batchCode": {}, - "billOfMaterials": "Lista de Materiales", - "@billOfMaterials": {}, - "build": "Construcción", - "@build": {}, - "building": "Construyendo", - "@building": {}, - "cancel": "Cancelar", - "@cancel": { - "description": "Cancel" - }, - "category": "Categoria", - "@category": {}, - "categoryCreate": "Nueva Categoría", - "@categoryCreate": {}, - "categoryCreateDetail": "Crear nueva categoría de partes", - "@categoryCreateDetail": {}, - "categoryUpdated": "Categoría actualizada", - "@categoryUpdated": {}, - "company": "Companía", - "@company": {}, - "companyEdit": "Editar compañía", - "@companyEdit": {}, - "companyNoResults": "No hay compañías que coincidan con la consulta", - "@companyNoResults": {}, - "companyUpdated": "Detalles de la compañía actualizados", - "@companyUpdated": {}, - "companies": "Compañías", - "@companies": {}, - "configureServer": "Configurar ajustes del servidor", - "@configureServer": {}, - "connectionRefused": "Conexión rechazada", - "@connectionRefused": {}, - "count": "Número", - "@count": { - "description": "Count" - }, - "countStock": "Cantidad de stock", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Créditos", - "@credits": {}, - "customers": "Clientes", - "@customers": {}, - "damaged": "Dañado", - "@damaged": {}, - "delete": "Eliminar", - "@delete": {}, - "deletePart": "Eliminar parte", - "@deletePart": {}, - "deletePartDetail": "Eliminar esta parte de la base de datos", - "@deletePartDetail": {}, - "description": "Descripción", - "@description": {}, - "destroyed": "Destruido", - "@destroyed": {}, - "details": "Detalles", - "@details": { - "description": "details" - }, - "documentation": "Documentación", - "@documentation": {}, - "downloading": "Descargando archivo", - "@downloading": {}, - "downloadError": "Error de descarga", - "@downloadError": {}, - "edit": "Editar", - "@edit": { - "description": "edit" - }, - "editCategory": "Editar categoría", - "@editCategory": {}, - "editLocation": "Editar ubicación", - "@editLocation": {}, - "editNotes": "Editar notas", - "@editNotes": {}, - "editPart": "Editar Parte", - "@editPart": { - "description": "edit part" - }, - "editItem": "Editar artículo de stock", - "@editItem": {}, - "enterPassword": "Introducir contraseña", - "@enterPassword": {}, - "enterUsername": "Introducir usuario", - "@enterUsername": {}, - "error": "Error", - "@error": { - "description": "Error" - }, - "errorCreate": "Error al crear entrada de base de datos", - "@errorCreate": {}, - "errorDelete": "Error al eliminar la entrada de base de datos", - "@errorDelete": {}, - "errorDetails": "Detalles del error", - "@errorDetails": {}, - "errorFetch": "Error obteniendo datos del servidor", - "@errorFetch": {}, - "errorReporting": "Error al reportar", - "@errorReporting": {}, - "errorReportUpload": "Subir informe de errores", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Subir informes de errores anónimos y registros de errores", - "@errorReportUploadDetails": {}, - "feedback": "Comentarios", - "@feedback": {}, - "feedbackError": "Error al enviar comentarios", - "@feedbackError": {}, - "feedbackSuccess": "Comentarios enviados", - "@feedbackSuccess": {}, - "formatException": "Excepción de formato", - "@formatException": {}, - "formatExceptionJson": "Excepción en formato de datos JSON", - "@formatExceptionJson": {}, - "formError": "Error de formulario", - "@formError": {}, - "history": "Historial", - "@history": { - "description": "history" - }, - "homeScreen": "Pantalla de Inicio", - "@homeScreen": {}, - "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", - "@homeScreenSettings": {}, - "homeShowPo": "Mostrar órdenes de compra", - "@homeShowPo": {}, - "homeShowSubscribed": "Partes Suscritas", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Mostrar las partes suscritas en la página principal", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Mostrar Proveedores", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Mostrar botón de proveedores en la pantalla de inicio", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Mostrar fabricantes", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Mostrar botón de fabricantes en la pantalla de inicio", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Mostrar clientes", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Mostrar botón de clientes en la pantalla de inicio", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Error al subir la imagen", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Imagen subida", - "@imageUploadSuccess": {}, - "inactive": "Inactivo", - "@inactive": {}, - "inactiveDetail": "Esta parte está marcada como inactiva", - "@inactiveDetail": {}, - "includeSubcategories": "Incluir subcategorías", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Mostrar partes de subcategorías en la vista de lista", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Incluir sub-localizaciones", - "@includeSublocations": {}, - "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Detalles del perfil incompletos", - "@incompleteDetails": {}, - "internalPartNumber": "Número de parte interno", - "@internalPartNumber": {}, - "info": "Información", - "@info": {}, - "inProduction": "En producción", - "@inProduction": {}, - "inProductionDetail": "El artículo de stock está en producción", - "@inProductionDetail": {}, - "invalidPart": "Parte inválida", - "@invalidPart": {}, - "invalidPartCategory": "Categoría de parte inválida", - "@invalidPartCategory": {}, - "invalidStockLocation": "Ubicación inválida", - "@invalidStockLocation": {}, - "invalidStockItem": "Artículo de stock inválido", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Nombre de usuario / contraseña no válido", - "@invalidUsernamePassword": {}, - "itemInLocation": "El artículo ya está en la ubicación", - "@itemInLocation": {}, - "keywords": "Palabras claves", - "@keywords": {}, - "lastUpdated": "Última actualización", - "@lastUpdated": {}, - "lineItems": "Elementos de línea", - "@lineItems": {}, - "locationCreate": "Nueva ubicación", - "@locationCreate": {}, - "locationCreateDetail": "Crear nueva ubicación de stock", - "@locationCreateDetail": {}, - "locationNotSet": "No se especificó ninguna ubicación", - "@locationNotSet": {}, - "locationUpdated": "Ubicación de stock actualizada", - "@locationUpdated": {}, - "link": "Vincular", - "@link": {}, - "lost": "Perdido", - "@lost": {}, - "manufacturers": "Fabricantes", - "@manufacturers": {}, - "name": "Nombre", - "@name": {}, - "notConnected": "No conectado", - "@notConnected": {}, - "notes": "Notas", - "@notes": { - "description": "Notes" - }, - "noResponse": "Sin respuesta del servidor", - "@noResponse": {}, - "noResults": "Sin resultados", - "@noResults": {}, - "noSubcategories": "No hay subcategorías", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "No hay subcategorías disponibles", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Número inválido", - "@numberInvalid": {}, - "onOrder": "En pedido", - "@onOrder": {}, - "onOrderDetails": "Artículos actualmente en pedido", - "@onOrderDetails": {}, - "packaging": "Paquete", - "@packaging": {}, - "packageName": "Nombre de Paquete", - "@packageName": {}, - "parent": "Principal", - "@parent": {}, - "parentCategory": "Categoría superior", - "@parentCategory": {}, - "parentLocation": "Ubicación superior", - "@parentLocation": {}, - "part": "Parte", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Nueva Parte", - "@partCreate": {}, - "partCreateDetail": "Crear nueva parte en esta categoría", - "@partCreateDetail": {}, - "partEdited": "Parte actualizada", - "@partEdited": {}, - "parts": "Partes", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Sin Partes", - "@partsNone": {}, - "partNoResults": "No hay partes que coincidan", - "@partNoResults": {}, - "partsStarred": "Parte suscrita", - "@partsStarred": {}, - "partsStarredNone": "No hay partes destacadas disponibles", - "@partsStarredNone": {}, - "partSuppliers": "Proveedores de partes", - "@partSuppliers": {}, - "partCategory": "Categoría de parte", - "@partCategory": {}, - "partCategoryTopLevel": "Categoría de partes de nivel superior", - "@partCategoryTopLevel": {}, - "partCategories": "Categorías de parte", - "@partCategories": {}, - "partDetails": "Detalles de Parte", - "@partDetails": {}, - "partNotes": "Notas de parte", - "@partNotes": {}, - "partStock": "Stock de parte", - "@partStock": { - "description": "part stock" - }, - "password": "Contraseña", - "@password": {}, - "passwordEmpty": "La contraseña no puede estar vacía", - "@passwordEmpty": {}, - "permissionAccountDenied": "Tu usuario no cuenta con los permisos necesarios para realizar esta acción", - "@permissionAccountDenied": {}, - "permissionRequired": "Se requiere autorización", - "@permissionRequired": {}, - "printLabel": "Imprimir etiqueta", - "@printLabel": {}, - "printLabelFailure": "Impresión de etiquetas fallida", - "@printLabelFailure": {}, - "printLabelSuccess": "Etiqueta enviada a la impresora", - "@printLabelSuccess": {}, - "profile": "Perfil", - "@profile": {}, - "profileAdd": "Añadir perfil de servidor", - "@profileAdd": {}, - "profileConnect": "Conectar a Servidor", - "@profileConnect": {}, - "profileEdit": "Editar perfil de servidor", - "@profileEdit": {}, - "profileDelete": "Eliminar perfil del servidor", - "@profileDelete": {}, - "profileName": "Nombre de perfil", - "@profileName": {}, - "profileNone": "No hay perfiles disponibles", - "@profileNone": {}, - "profileNotSelected": "Ningún perfil seleccionado", - "@profileNotSelected": {}, - "profileSelect": "Seleccionar servidor de InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Toca para crear o seleccionar un perfil", - "@profileTapToCreate": {}, - "purchaseOrder": "Orden de compra", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Modificar orden de compra", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Ordenes de compra", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Orden de compra actualizada", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Precio de compra", - "@purchasePrice": {}, - "quantity": "Cantidad", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Cantidad está vacía", - "@quantityEmpty": {}, - "quantityInvalid": "La cantidad no es válida", - "@quantityInvalid": {}, - "quantityPositive": "La cantidad debe ser positiva", - "@quantityPositive": {}, - "queryNoResults": "No hay resultados para la consulta", - "@queryNoResults": {}, - "received": "Recibido", - "@received": {}, - "receiveItem": "Recibir artículo", - "@receiveItem": {}, - "receivedItem": "Articulo de stock recibido", - "@receivedItem": {}, - "refresh": "Actualizar", - "@refresh": {}, - "refreshing": "Actualizando", - "@refreshing": {}, - "rejected": "Rechazado", - "@rejected": {}, - "releaseNotes": "Notas informativas", - "@releaseNotes": {}, - "remove": "Eliminar", - "@remove": { - "description": "remove" - }, - "removeStock": "Eliminar Stock", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Reportar un error", - "@reportBug": {}, - "reportBugDescription": "Enviar informe de error (requiere cuenta de GitHub)", - "@reportBugDescription": {}, - "results": "Resultados", - "@results": {}, - "required": "Requerido", - "@required": { - "description": "This field is required" - }, - "response400": "Petición incorrecta", - "@response400": {}, - "response401": "No autorizado (Unauthorized)", - "@response401": {}, - "response403": "Permiso denegado", - "@response403": {}, - "response404": "Recurso no encontrado", - "@response404": {}, - "response405": "Método no permitido", - "@response405": {}, - "response429": "Demasiadas peticiones", - "@response429": {}, - "response500": "Error interno del servidor", - "@response500": {}, - "response501": "No implementado", - "@response501": {}, - "response502": "Puerta de enlace incorrecta (Bad Gateway)", - "@response502": {}, - "response503": "Servicio no disponible", - "@response503": {}, - "response504": "Tiempo de espera de puerta de enlace (Gateway Timeout)", - "@response504": {}, - "response505": "Versión de HTTP no compatible", - "@response505": {}, - "responseData": "Datos de respuesta", - "@responseData": {}, - "responseInvalid": "Código de respuesta inválido", - "@responseInvalid": {}, - "responseUnknown": "Respuesta desconocida", - "@responseUnknown": {}, - "result": "Resultado", - "@result": { - "description": "" - }, - "returned": "Devuelto", - "@returned": {}, - "salesOrders": "Órdenes de venta", - "@salesOrders": {}, - "save": "Guardar", - "@save": { - "description": "Save" - }, - "scanBarcode": "Escanear código de barras", - "@scanBarcode": {}, - "scanIntoLocation": "Escanear a la ubicación", - "@scanIntoLocation": {}, - "search": "Buscar", - "@search": { - "description": "search" - }, - "searchLocation": "Buscar ubicaciones", - "@searchLocation": {}, - "searchParts": "Buscar partes", - "@searchParts": {}, - "searchStock": "Buscar Stock", - "@searchStock": {}, - "select": "Seleccionar", - "@select": {}, - "selectFile": "Seleccionar archivo", - "@selectFile": {}, - "selectImage": "Seleccionar imagen", - "@selectImage": {}, - "selectLocation": "Seleccione una ubicación", - "@selectLocation": {}, - "send": "Enviar", - "@send": {}, - "serialNumber": "Número de serie", - "@serialNumber": {}, - "server": "Servidor", - "@server": {}, - "serverApiRequired": "Versión de API requerida", - "@serverApiRequired": {}, - "serverApiVersion": "Versión de la API del servidor", - "@serverApiVersion": {}, - "serverAuthenticationError": "Error de autenticación", - "@serverAuthenticationError": {}, - "serverCertificateError": "Error de certificado", - "@serverCertificateError": {}, - "serverCertificateInvalid": "El certificado del servidor no es válido", - "@serverCertificateInvalid": {}, - "serverConnected": "Conectado al servidor", - "@serverConnected": {}, - "serverConnecting": "Conectando a servidor", - "@serverConnecting": {}, - "serverCouldNotConnect": "No se pudo conectar al servidor", - "@serverCouldNotConnect": {}, - "serverEmpty": "El servidor no puede estar vacío", - "@serverEmpty": {}, - "serverError": "Error del servidor", - "@serverError": {}, - "serverDetails": "Detalles del Servidor", - "@serverDetails": {}, - "serverMissingData": "Faltan campos requeridos de respuesta del servidor", - "@serverMissingData": {}, - "serverOld": "Versión del servidor anterior", - "@serverOld": {}, - "serverSettings": "Configuración del Servidor", - "@serverSettings": {}, - "serverStart": "El servidor debe comenzar con http[s]", - "@serverStart": {}, - "settings": "Configuración", - "@settings": {}, - "serverInstance": "Instancia del servidor", - "@serverInstance": {}, - "serverNotConnected": "Servidor no conectado", - "@serverNotConnected": {}, - "sounds": "Sonidos", - "@sounds": {}, - "soundOnBarcodeAction": "Reproducir tono audible en la acción de código de barras", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Reproducir tono audible en error del servidor", - "@soundOnServerError": {}, - "status": "Estado", - "@status": {}, - "statusCode": "Código de estado", - "@statusCode": {}, - "stock": "Stock", - "@stock": { - "description": "stock" - }, - "stockDetails": "Cantidad actual de stock disponible", - "@stockDetails": {}, - "stockItem": "Artículo de stock", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Elementos de Stock", - "@stockItems": {}, - "stockItemCreate": "Nuevo artículo de stock", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Crear nuevo artículo de stock en esta ubicación", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Eliminar elemento de stock", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "¿Está seguro que desea eliminar este elemento de stock?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "No se pudo eliminar el elemento de stock", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Elemento de stock eliminado", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historial de Stock", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Mostrar información de seguimiento de stock histórico", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Artículo de stock transferido", - "@stockItemTransferred": {}, - "stockItemUpdated": "Artículo de stock actualizado", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No hay artículos de stock disponibles", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notas del artículo de stock", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Artículo de stock actualizado", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Error al actualizar el artículo de stock", - "@stockItemUpdateFailure": {}, - "stockLocation": "Ubicaciones de stock", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Ubicaciones de Stock", - "@stockLocations": {}, - "stockTopLevel": "Ubicación de stock superior", - "@stockTopLevel": {}, - "strictHttps": "Usar HTTPS estricto", - "@strictHttps": {}, - "strictHttpsDetails": "Forzar un control estricto de los certificados HTTPs", - "@strictHttpsDetails": {}, - "subcategory": "Subcategoría", - "@subcategory": {}, - "subcategories": "Subcategorías", - "@subcategories": {}, - "sublocation": "Sublocalización", - "@sublocation": {}, - "sublocations": "Sublocalizaciones", - "@sublocations": {}, - "sublocationNone": "Sin sublocalizaciones", - "@sublocationNone": {}, - "sublocationNoneDetail": "No hay sublocalizaciones disponibles", - "@sublocationNoneDetail": {} -} \ No newline at end of file diff --git a/lib/l10n/es-MX/app_es.arb b/lib/l10n/es-MX/app_es.arb deleted file mode 100644 index 91793f1..0000000 --- a/lib/l10n/es-MX/app_es.arb +++ /dev/null @@ -1,17 +0,0 @@ -{ - "@@locale": "en", - "barcodeScanInItems": "Escanear artículos de stock en su ubicación", - "@barcodeScanInItems": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", - "@includeSublocationsDetail": {}, - "lineItems": "Ítems de línea", - "@lineItems": {}, - "onOrderDetails": "Artículos actualmente en pedido", - "@onOrderDetails": {}, - "stockItems": "Elementos de stock", - "@stockItems": {}, - "stockItemsNotAvailable": "No hay artículos de stock disponibles", - "@stockItemsNotAvailable": {} -} \ No newline at end of file diff --git a/lib/l10n/fa/app_fa.arb b/lib/l10n/fa/app_fa.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/fa/app_fa.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/fr/app_fr.arb b/lib/l10n/fr/app_fr.arb deleted file mode 100644 index f5434c0..0000000 --- a/lib/l10n/fr/app_fr.arb +++ /dev/null @@ -1,743 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "À propos", - "@about": {}, - "accountDetails": "Détails du compte", - "@accountDetails": {}, - "actions": "Actions", - "@actions": { - "description": "" - }, - "actionsNone": "Aucune action disponible", - "@actionsNone": {}, - "add": "Ajouter", - "@add": { - "description": "add" - }, - "addStock": "Ajouter un stock", - "@addStock": { - "description": "add stock" - }, - "address": "Adresse", - "@address": {}, - "appAbout": "À propos d'InvenTree", - "@appAbout": {}, - "appCredits": "Crédits d'application supplémentaires", - "@appCredits": {}, - "appDetails": "Détails de l'application", - "@appDetails": {}, - "appReleaseNotes": "Afficher les notes de version de l'application", - "@appReleaseNotes": {}, - "appSettings": "Réglages de l'application", - "@appSettings": {}, - "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", - "@appSettingsDetails": {}, - "attachments": "Pieces jointes", - "@attachments": {}, - "attachImage": "Ajouter une image", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Aucune pièce jointe trouvée", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Sélectionner une pièce jointe", - "@attachmentSelect": {}, - "attention": "Attention", - "@attention": {}, - "availableStock": "Stock disponible", - "@availableStock": {}, - "barcodeAssign": "Affecter un code-barres", - "@barcodeAssign": {}, - "barcodeAssigned": "Code-barres affecté", - "@barcodeAssigned": {}, - "barcodeError": "Erreur lors du scan du code-barres", - "@barcodeError": {}, - "barcodeInUse": "Le code-barres est déjà en cours d’utilisation", - "@barcodeInUse": {}, - "barcodeMissingHash": "Les données de hachage du code-barres sont manquantes dans la réponse", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Pas de correspondance pour ce code-barres", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Code-barres non assigné", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scanner pour attribuer un code-barres", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Scanner un code-barres InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scannez les items de stock à l'emplacement", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scanner la localisation du stock", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item non scanné dans", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scanner l'article en stock", - "@barcodeScanItem": {}, - "barcodeTones": "Types de code-barre", - "@barcodeTones": {}, - "barcodeUnassign": "Désaffecter le code-barres", - "@barcodeUnassign": {}, - "barcodeUnknown": "Code-barres non reconnu", - "@barcodeUnknown": {}, - "batchCode": "Code de lot", - "@batchCode": {}, - "billOfMaterials": "Liste des matériaux", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Assemblage", - "@build": {}, - "building": "Assemblage en cours", - "@building": {}, - "cancel": "Annuler", - "@cancel": { - "description": "Cancel" - }, - "category": "Catégorie", - "@category": {}, - "categoryCreate": "Nouvelle catégorie", - "@categoryCreate": {}, - "categoryCreateDetail": "Créer une nouvelle catégorie de pièce", - "@categoryCreateDetail": {}, - "categoryUpdated": "Catégorie de pièce mise à jour", - "@categoryUpdated": {}, - "company": "Société", - "@company": {}, - "companyEdit": "Modifier la société", - "@companyEdit": {}, - "companyNoResults": "Aucune société ne correspond à la requête", - "@companyNoResults": {}, - "companyUpdated": "Détails de la société mis à jour", - "@companyUpdated": {}, - "companies": "Sociétés", - "@companies": {}, - "configureServer": "Configurer les paramètres serveur", - "@configureServer": {}, - "connectionRefused": "Connexion refusée", - "@connectionRefused": {}, - "count": "Nombre", - "@count": { - "description": "Count" - }, - "countStock": "Nombre de stock", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Crédits", - "@credits": {}, - "customers": "Clients", - "@customers": {}, - "damaged": "Endommagé", - "@damaged": {}, - "delete": "Supprimer", - "@delete": {}, - "deletePart": "Supprimer la pièce", - "@deletePart": {}, - "deletePartDetail": "Supprimer cette pièce de la base de données", - "@deletePartDetail": {}, - "description": "Description", - "@description": {}, - "destroyed": "Détruit", - "@destroyed": {}, - "details": "Détails", - "@details": { - "description": "details" - }, - "documentation": "Documentation", - "@documentation": {}, - "downloading": "Téléchargement du fichier", - "@downloading": {}, - "downloadError": "Erreur lors du téléchargement", - "@downloadError": {}, - "edit": "Modifier", - "@edit": { - "description": "edit" - }, - "editCategory": "Modifier la catégorie", - "@editCategory": {}, - "editLocation": "Modifier l’emplacement", - "@editLocation": {}, - "editNotes": "Modifier les notes", - "@editNotes": {}, - "editPart": "Modifier la pièce", - "@editPart": { - "description": "edit part" - }, - "editItem": "Editer l'article en stock", - "@editItem": {}, - "enterPassword": "Saisissez le mot de passe", - "@enterPassword": {}, - "enterUsername": "Saisissez le nom d'utilisateur", - "@enterUsername": {}, - "error": "Erreur", - "@error": { - "description": "Error" - }, - "errorCreate": "Erreur lors de la création de l'entrée de la base de données", - "@errorCreate": {}, - "errorDelete": "Erreur lors de la suppression de l'entrée de la base de données", - "@errorDelete": {}, - "errorDetails": "Détails de l'erreur", - "@errorDetails": {}, - "errorFetch": "Erreur de récupération des données du serveur", - "@errorFetch": {}, - "errorReporting": "Rapport d'erreur", - "@errorReporting": {}, - "errorReportUpload": "Envoyer le rapport d 'erreur", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", - "@errorReportUploadDetails": {}, - "feedback": "Donner votre avis", - "@feedback": {}, - "feedbackError": "Erreur lors de l'envoi du commentaire", - "@feedbackError": {}, - "feedbackSuccess": "Commentaire envoyé", - "@feedbackSuccess": {}, - "formatException": "Exception de format", - "@formatException": {}, - "formatExceptionJson": "Exception de format de données JSON", - "@formatExceptionJson": {}, - "formError": "Erreur de formulaire", - "@formError": {}, - "history": "Historique", - "@history": { - "description": "history" - }, - "homeScreen": "Ecran d'accueil", - "@homeScreen": {}, - "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", - "@homeScreenSettings": {}, - "homeShowPo": "Afficher les commandes d'achat", - "@homeShowPo": {}, - "homeShowSubscribed": "Pièces suivies", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Afficher les fournisseurs", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Afficher les fabriquants", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Afficher le bouton fabriquant sur l'écran d'accueil", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Afficher les clients", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Afficher le bouton clients sur l'écran d'accueil", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Échec de l'envoi de l'image", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Image transférée", - "@imageUploadSuccess": {}, - "inactive": "Inactif", - "@inactive": {}, - "inactiveDetail": "Cette pièce est marquée comme inactive", - "@inactiveDetail": {}, - "includeSubcategories": "Inclure les sous-catégories", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Afficher les sous-catégories dans la vue liste", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Inclure les sous-emplacements", - "@includeSublocations": {}, - "includeSublocationsDetail": "Afficher les sous-emplacements des articles dans la vue liste", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Profil incomplet", - "@incompleteDetails": {}, - "internalPartNumber": "Numéro de pièce interne", - "@internalPartNumber": {}, - "info": "Information", - "@info": {}, - "inProduction": "En production", - "@inProduction": {}, - "inProductionDetail": "Cet article de stock est en production", - "@inProductionDetail": {}, - "invalidHost": "Nom d’hôte invalide", - "@invalidHost": {}, - "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", - "@invalidHostDetails": {}, - "invalidPart": "Article non valide", - "@invalidPart": {}, - "invalidPartCategory": "Catégorie d'article invalide", - "@invalidPartCategory": {}, - "invalidStockLocation": "Emplacement invalide", - "@invalidStockLocation": {}, - "invalidStockItem": "Article en stock non valide", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", - "@invalidUsernamePassword": {}, - "issueDate": "Date d'émission", - "@issueDate": {}, - "itemInLocation": "Article déjà dans l'emplacement", - "@itemInLocation": {}, - "keywords": "Mots clés", - "@keywords": {}, - "lastStocktake": "Dernier inventaire", - "@lastStocktake": {}, - "lastUpdated": "Dernière mise à jour", - "@lastUpdated": {}, - "lineItem": "Position", - "@lineItem": {}, - "lineItems": "Position", - "@lineItems": {}, - "locationCreate": "Nouvel emplacement", - "@locationCreate": {}, - "locationCreateDetail": "Créer un nouvel emplacement de stock", - "@locationCreateDetail": {}, - "locationNotSet": "Aucun emplacement spécifié", - "@locationNotSet": {}, - "locationUpdated": "Emplacement du stock mis à jour", - "@locationUpdated": {}, - "link": "Lien", - "@link": {}, - "lost": "Perdu", - "@lost": {}, - "manufacturers": "Fabricants", - "@manufacturers": {}, - "missingData": "Données manquantes", - "@missingData": {}, - "name": "Nom", - "@name": {}, - "notConnected": "Non connecté", - "@notConnected": {}, - "notes": "Notes", - "@notes": { - "description": "Notes" - }, - "noResponse": "Aucune réponse du serveur", - "@noResponse": {}, - "noResults": "Aucun résultat", - "@noResults": {}, - "noSubcategories": "Pas de sous-catégorie", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Nombre invalide", - "@numberInvalid": {}, - "onOrder": "Sur Commande", - "@onOrder": {}, - "onOrderDetails": "Articles en cours de commande", - "@onOrderDetails": {}, - "packaging": "Emballage", - "@packaging": {}, - "packageName": "Nom du package", - "@packageName": {}, - "parent": "Parent", - "@parent": {}, - "parentCategory": "Catégorie parent", - "@parentCategory": {}, - "parentLocation": "Emplacement parent", - "@parentLocation": {}, - "part": "Pièce", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Nouvelle pièce", - "@partCreate": {}, - "partCreateDetail": "Créer une nouvelle pièce dans cette catégorie", - "@partCreateDetail": {}, - "partEdited": "Pièce mise à jour", - "@partEdited": {}, - "parts": "Pièces", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Aucune pièces", - "@partsNone": {}, - "partNoResults": "Pas de pièces correspondant à la requête", - "@partNoResults": {}, - "partsStarred": "Pièces suivies", - "@partsStarred": {}, - "partsStarredNone": "Aucune pièce favorite disponible", - "@partsStarredNone": {}, - "partSuppliers": "Fournisseurs de pièces", - "@partSuppliers": {}, - "partCategory": "Catégorie de la pièce", - "@partCategory": {}, - "partCategoryTopLevel": "Catégorie de pièce parente", - "@partCategoryTopLevel": {}, - "partCategories": "Catégories de pièce", - "@partCategories": {}, - "partDetails": "Détails de la pièce", - "@partDetails": {}, - "partNotes": "Notes de la pièce", - "@partNotes": {}, - "partStock": "Stock de la pièce", - "@partStock": { - "description": "part stock" - }, - "password": "Mot de passe", - "@password": {}, - "passwordEmpty": "Le mot de passe peut pas être vide", - "@passwordEmpty": {}, - "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", - "@permissionAccountDenied": {}, - "permissionRequired": "Autorisation requise", - "@permissionRequired": {}, - "printLabel": "Imprimer l'étiquette", - "@printLabel": {}, - "printLabelFailure": "Echec de l'impression", - "@printLabelFailure": {}, - "printLabelSuccess": "Etiquette envoyée à l'imprimante", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Ajouter un profil serveur", - "@profileAdd": {}, - "profileConnect": "Se connecter au serveur", - "@profileConnect": {}, - "profileEdit": "Editer le profil du serveur", - "@profileEdit": {}, - "profileDelete": "Supprimer le profil du serveur", - "@profileDelete": {}, - "profileName": "Nom du profil", - "@profileName": {}, - "profileNone": "Aucun profil disponible", - "@profileNone": {}, - "profileNotSelected": "Aucun profil sélectionné", - "@profileNotSelected": {}, - "profileSelect": "Sélectionner le serveur InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", - "@profileTapToCreate": {}, - "purchaseOrder": "Commande d’achat", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Modifier la commande d'achat", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Commandes d'achat", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Bon de commande mis à jour", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Prix d'achat", - "@purchasePrice": {}, - "quantity": "Quantité", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "La quantité est vide", - "@quantityEmpty": {}, - "quantityInvalid": "La quantité n'est pas valide", - "@quantityInvalid": {}, - "quantityPositive": "La quantité doit être positive", - "@quantityPositive": {}, - "queryNoResults": "Pas de résultat pour votre requête", - "@queryNoResults": {}, - "received": "Reçu", - "@received": {}, - "receiveItem": "Articles reçus", - "@receiveItem": {}, - "receivedItem": "Article de stock reçu", - "@receivedItem": {}, - "refresh": "Actualiser", - "@refresh": {}, - "refreshing": "Actualisation en cours", - "@refreshing": {}, - "rejected": "Rejeté", - "@rejected": {}, - "releaseNotes": "Notes de Version", - "@releaseNotes": {}, - "remove": "Supprimer", - "@remove": { - "description": "remove" - }, - "removeStock": "Supprimer le stock", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Signaler un bug", - "@reportBug": {}, - "reportBugDescription": "Envoyer un rapport de bug (nécessite un compte GitHub)", - "@reportBugDescription": {}, - "results": "Résultats", - "@results": {}, - "request": "Requête", - "@request": {}, - "requestingData": "Demande de données", - "@requestingData": {}, - "required": "Requis", - "@required": { - "description": "This field is required" - }, - "response400": "Mauvaise requête", - "@response400": {}, - "response401": "Non autorisé", - "@response401": {}, - "response403": "Autorisation refusée", - "@response403": {}, - "response404": "Ressource non trouvée", - "@response404": {}, - "response405": "Méthode non autorisé", - "@response405": {}, - "response429": "Trop de requêtes", - "@response429": {}, - "response500": "Erreur interne du serveur", - "@response500": {}, - "response501": "Non implémenté", - "@response501": {}, - "response502": "Mauvaise passerelle", - "@response502": {}, - "response503": "Service indisponible", - "@response503": {}, - "response504": "Délai d'attente de la passerelle expiré", - "@response504": {}, - "response505": "Version HTTP non prise en charge", - "@response505": {}, - "responseData": "Données de la réponse", - "@responseData": {}, - "responseInvalid": "Code de réponse invalide", - "@responseInvalid": {}, - "responseUnknown": "Réponse inconnue", - "@responseUnknown": {}, - "result": "Résultat ", - "@result": { - "description": "" - }, - "returned": "Retourné", - "@returned": {}, - "salesOrders": "Ventes", - "@salesOrders": {}, - "save": "Enregistrer", - "@save": { - "description": "Save" - }, - "scanBarcode": "Scanner un code-barres", - "@scanBarcode": {}, - "scanIntoLocation": "Scanner vers l'emplacement", - "@scanIntoLocation": {}, - "search": "Rechercher", - "@search": { - "description": "search" - }, - "searchLocation": "Rechercher un emplacement", - "@searchLocation": {}, - "searchParts": "Rechercher de pièces", - "@searchParts": {}, - "searchStock": "Rechercher un stock", - "@searchStock": {}, - "select": "Sélectionner", - "@select": {}, - "selectFile": "Sélectionner un fichier", - "@selectFile": {}, - "selectImage": "Sélectionner une image", - "@selectImage": {}, - "selectLocation": "Sélectionnez un emplacement", - "@selectLocation": {}, - "send": "Envoyer", - "@send": {}, - "serialNumber": "Numéro de série", - "@serialNumber": {}, - "server": "Serveur", - "@server": {}, - "serverAddress": "Adresse du serveur", - "@serverAddress": {}, - "serverApiRequired": "Version de l'API requise", - "@serverApiRequired": {}, - "serverApiVersion": "Version de l'API du serveur", - "@serverApiVersion": {}, - "serverAuthenticationError": "Erreur lors de l'authentification", - "@serverAuthenticationError": {}, - "serverCertificateError": "Erreur de certificat", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Le certificat HTTPS du serveur n'est pas valide", - "@serverCertificateInvalid": {}, - "serverConnected": "Connecté au serveur", - "@serverConnected": {}, - "serverConnecting": "Connexion au serveur", - "@serverConnecting": {}, - "serverCouldNotConnect": "Connexion au serveur impossible", - "@serverCouldNotConnect": {}, - "serverEmpty": "Le serveur ne peut pas être vide", - "@serverEmpty": {}, - "serverError": "Erreur serveur", - "@serverError": {}, - "serverDetails": "Détails du serveur", - "@serverDetails": {}, - "serverMissingData": "La réponse du serveur ne possède pas les champs obligatoires", - "@serverMissingData": {}, - "serverOld": "Ancienne version du serveur", - "@serverOld": {}, - "serverSettings": "Paramètres du serveur", - "@serverSettings": {}, - "serverStart": "Le serveur doit débuter par http[s]", - "@serverStart": {}, - "settings": "Réglages", - "@settings": {}, - "serverInstance": "Instance du serveur", - "@serverInstance": {}, - "serverNotConnected": "Le serveur n'est pas connecté", - "@serverNotConnected": {}, - "sounds": "Sons", - "@sounds": {}, - "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Jouer une tonalité sonore en cas d'erreur du serveur", - "@soundOnServerError": {}, - "status": "État", - "@status": {}, - "statusCode": "Code d'état", - "@statusCode": {}, - "stock": "Stock", - "@stock": { - "description": "stock" - }, - "stockDetails": "Quantité actuelle de stock disponible", - "@stockDetails": {}, - "stockItem": "Article en stock", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Articles en stock", - "@stockItems": {}, - "stockItemCreate": "Nouvel article en stock", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Créer un nouvel article en stock dans cet emplacement", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Supprimer l'article du stock", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Êtes-vous certain de vouloir supprimer cet article ?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Impossible de supprmer cet article", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Article supprimé", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historique du stock", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Afficher les informations de suivi de stock", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Article en stock transféré", - "@stockItemTransferred": {}, - "stockItemUpdated": "Article en stock mis à jour", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Aucun article en stock", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notes de l'article en stock", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Article en stock mis à jour", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Echec de la mise à jour de l'article en stock", - "@stockItemUpdateFailure": {}, - "stockLocation": "Emplacement du stock", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Emplacements du stock", - "@stockLocations": {}, - "stockTopLevel": "Emplacement de stock de premier niveau", - "@stockTopLevel": {}, - "strictHttps": "Utiliser HTTPS strict", - "@strictHttps": {}, - "strictHttpsDetails": "Obliger une vérification stricte des certificats HTTP", - "@strictHttpsDetails": {}, - "subcategory": "Sous-catégorie", - "@subcategory": {}, - "subcategories": "Sous-catégories", - "@subcategories": {}, - "sublocation": "Sous-emplacement", - "@sublocation": {}, - "sublocations": "Sous-emplacements", - "@sublocations": {}, - "sublocationNone": "Aucun sous-emplacement", - "@sublocationNone": {}, - "sublocationNoneDetail": "Aucun sous-emplacement disponible", - "@sublocationNoneDetail": {}, - "submitFeedback": "Soumettre le commentaire", - "@submitFeedback": {}, - "suppliedParts": "Composants fournis", - "@suppliedParts": {}, - "supplier": "Fournisseur", - "@supplier": {}, - "suppliers": "Fournisseurs", - "@suppliers": {}, - "supplierReference": "Référence du fournisseur", - "@supplierReference": {}, - "takePicture": "Prendre une photo", - "@takePicture": {}, - "targetDate": "Date Cible", - "@targetDate": {}, - "testName": "Nom de test", - "@testName": {}, - "testPassedOrFailed": "Test réussi ou échoué", - "@testPassedOrFailed": {}, - "testsRequired": "Tests requis", - "@testsRequired": {}, - "testResults": "Résultats du test", - "@testResults": { - "description": "" - }, - "testResultAdd": "Ajouter un résultat de test", - "@testResultAdd": {}, - "testResultNone": "Aucun résultat de test", - "@testResultNone": {}, - "testResultNoneDetail": "Aucun résultat de test disponible", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Erreur lors de l'envoi du résultat du test", - "@testResultUploadFail": {}, - "testResultUploadPass": "Résultats du test chargés", - "@testResultUploadPass": {}, - "timeout": "Délai dépassé", - "@timeout": { - "description": "" - }, - "tokenError": "Erreur du jeton", - "@tokenError": {}, - "tokenMissing": "Jeton manquant", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", - "@tokenMissingFromResponse": {}, - "transfer": "Transfert", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Transférer le stock", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Traduire", - "@translate": {}, - "translateHelp": "Aidez à traduire l'application InvenTree", - "@translateHelp": {}, - "units": "Unités", - "@units": {}, - "unknownResponse": "Réponse inconnue", - "@unknownResponse": {}, - "upload": "Importer le fichier", - "@upload": {}, - "uploadFailed": "Échec du chargement du fichier", - "@uploadFailed": {}, - "uploadSuccess": "Fichier transféré", - "@uploadSuccess": {}, - "usedIn": "Utilisé dans", - "@usedIn": {}, - "usedInDetails": "Assemblages qui requièrent ce composant", - "@usedInDetails": {}, - "username": "Nom d'utilisateur", - "@username": {}, - "usernameEmpty": "Le nom d'utilisateur peut pas être vide", - "@usernameEmpty": {}, - "value": "Valeur", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "La valeur ne peut pas être vide", - "@valueCannotBeEmpty": {}, - "valueRequired": "La valeur est requise", - "@valueRequired": {}, - "version": "Version", - "@version": {}, - "viewSupplierPart": "Voir la pièce du fournisseur", - "@viewSupplierPart": {}, - "website": "Site web", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/he/app_he.arb b/lib/l10n/he/app_he.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/he/app_he.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/hu/app_hu.arb b/lib/l10n/hu/app_hu.arb deleted file mode 100644 index b4624dc..0000000 --- a/lib/l10n/hu/app_hu.arb +++ /dev/null @@ -1,745 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Névjegy", - "@about": {}, - "accountDetails": "Felhasználó adatok", - "@accountDetails": {}, - "actions": "Műveletek", - "@actions": { - "description": "" - }, - "actionsNone": "Nincsenek műveletek", - "@actionsNone": {}, - "add": "Hozzáadás", - "@add": { - "description": "add" - }, - "addStock": "Készlet növelése", - "@addStock": { - "description": "add stock" - }, - "address": "Cím", - "@address": {}, - "appAbout": "InvenTree névjegy", - "@appAbout": {}, - "appCredits": "További közreműködők", - "@appCredits": {}, - "appDetails": "App részletek", - "@appDetails": {}, - "appReleaseNotes": "Kiadási közlemények", - "@appReleaseNotes": {}, - "appSettings": "Alkalmazásbeállítások", - "@appSettings": {}, - "appSettingsDetails": "Inventree alkalmazás beállításai", - "@appSettingsDetails": {}, - "attachments": "Mellékletek", - "@attachments": {}, - "attachImage": "Kép csatolása", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nem találhatók mellékletek", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Melléklet kiválasztása", - "@attachmentSelect": {}, - "attention": "Figyelem", - "@attention": {}, - "availableStock": "Elérhető készlet", - "@availableStock": {}, - "barcodeAssign": "Vonalkód hozzárendelése", - "@barcodeAssign": {}, - "barcodeAssigned": "Vonalkód hozzárendelve", - "@barcodeAssigned": {}, - "barcodeError": "Vonalkód olvasási hiba", - "@barcodeError": {}, - "barcodeInUse": "Vonalkód már hozzárendelve", - "@barcodeInUse": {}, - "barcodeMissingHash": "Vonalkód hash hiányzik a válaszból", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Nincs egyezés vonalkódra", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Készlet bevételezése az adott helyre", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Hely beolvasása", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Készlet tétel beolvasása", - "@barcodeScanItem": {}, - "barcodeTones": "Vonalkód hangszín", - "@barcodeTones": {}, - "barcodeUnassign": "Vonalkód leválasztása", - "@barcodeUnassign": {}, - "barcodeUnknown": "Vonalkód nem ismerhető fel", - "@barcodeUnknown": {}, - "batchCode": "Batch kód", - "@batchCode": {}, - "billOfMaterials": "Alkatrészjegyzék", - "@billOfMaterials": {}, - "bom": "Alkatrészjegyzék", - "@bom": {}, - "build": "Gyártás", - "@build": {}, - "building": "Gyártásban", - "@building": {}, - "cancel": "Mégsem", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategória", - "@category": {}, - "categoryCreate": "Új kategória", - "@categoryCreate": {}, - "categoryCreateDetail": "Alkatrész kategória létrehozása", - "@categoryCreateDetail": {}, - "categoryUpdated": "Alkatrész kategória módosítva", - "@categoryUpdated": {}, - "company": "Cég", - "@company": {}, - "companyEdit": "Cég szerkesztése", - "@companyEdit": {}, - "companyNoResults": "Nincs a lekérdezésnek megfelelő cég", - "@companyNoResults": {}, - "companyUpdated": "Cég adatai frissítve", - "@companyUpdated": {}, - "companies": "Cégek", - "@companies": {}, - "configureServer": "Kiszolgáló beállítások konfigurálása", - "@configureServer": {}, - "connectionRefused": "A kapcsolat visszautasítva", - "@connectionRefused": {}, - "count": "Mennyiség", - "@count": { - "description": "Count" - }, - "countStock": "Leltározás", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Közreműködők", - "@credits": {}, - "customers": "Vevők", - "@customers": {}, - "damaged": "Sérült", - "@damaged": {}, - "delete": "Törlés", - "@delete": {}, - "deletePart": "Alkatrész törlése", - "@deletePart": {}, - "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", - "@deletePartDetail": {}, - "description": "Leírás", - "@description": {}, - "destroyed": "Megsemmisült", - "@destroyed": {}, - "details": "Részletek", - "@details": { - "description": "details" - }, - "documentation": "Dokumentáció", - "@documentation": {}, - "downloading": "Fájl letöltése", - "@downloading": {}, - "downloadError": "Letöltési hiba", - "@downloadError": {}, - "edit": "Szerkesztés", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategória szerkesztése", - "@editCategory": {}, - "editLocation": "Hely szerkesztése", - "@editLocation": {}, - "editNotes": "Megjegyzések szerkesztése", - "@editNotes": {}, - "editPart": "Alkatrész szerkesztése", - "@editPart": { - "description": "edit part" - }, - "editItem": "Készlet tétel szerkesztése", - "@editItem": {}, - "enterPassword": "Jelszó megadása", - "@enterPassword": {}, - "enterUsername": "Felhasználó megadása", - "@enterUsername": {}, - "error": "Hiba", - "@error": { - "description": "Error" - }, - "errorCreate": "Hiba az adatbázis bejegyzés létrehozása közben", - "@errorCreate": {}, - "errorDelete": "Hiba az adatbázis bejegyzés törlése közben", - "@errorDelete": {}, - "errorDetails": "Hiba részletei", - "@errorDetails": {}, - "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", - "@errorFetch": {}, - "errorReporting": "Hibajelentés", - "@errorReporting": {}, - "errorReportUpload": "Hibajelentések feltöltése", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", - "@errorReportUploadDetails": {}, - "feedback": "Visszajelzés", - "@feedback": {}, - "feedbackError": "Visszajelzés küldése sikertelen", - "@feedbackError": {}, - "feedbackSuccess": "Visszajelzés elküldve", - "@feedbackSuccess": {}, - "formatException": "Formátum hiba", - "@formatException": {}, - "formatExceptionJson": "JSON adatformátum hiba", - "@formatExceptionJson": {}, - "formError": "Form hiba", - "@formError": {}, - "history": "Előzmények", - "@history": { - "description": "history" - }, - "homeScreen": "Főképernyő", - "@homeScreen": {}, - "homeScreenSettings": "Főképernyő beállítások konfigurálása", - "@homeScreenSettings": {}, - "homeShowPo": "Beszerzési rendelések megjelenítése", - "@homeShowPo": {}, - "homeShowSubscribed": "Értesítésre beállított alkatrészek", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Beszállítók megjelenítése", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Gyártók megjelenítése", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Gyártók gomb megjelenítése a főoldalon", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Vevők megjelenítése", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Vevők gomb megjelenítése a főoldalon", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Kép feltöltése sikertelen", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Kép feltöltve", - "@imageUploadSuccess": {}, - "inactive": "Inaktív", - "@inactive": {}, - "inactiveDetail": "Ez az alkatrész inaktív lett", - "@inactiveDetail": {}, - "includeSubcategories": "Alkategóriákkal együtt", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Al-kategóriájú alkatrészek megjelenítése a lista nézetben", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Alhelyekkel együtt", - "@includeSublocations": {}, - "includeSublocationsDetail": "Al-helyen lévő alkatrészek megjelenítése a lista nézetben", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Nem teljes profil adatok", - "@incompleteDetails": {}, - "internalPartNumber": "Belső alkatrész azonosító", - "@internalPartNumber": {}, - "info": "Infó", - "@info": {}, - "inProduction": "Gyártásban", - "@inProduction": {}, - "inProductionDetail": "Ez a készlet tétel gyártásban van", - "@inProductionDetail": {}, - "invalidHost": "Érvénytelen hostnév", - "@invalidHost": {}, - "invalidHostDetails": "A megadott hostnév nem érvényes", - "@invalidHostDetails": {}, - "invalidPart": "Érvénytelen alkatrész", - "@invalidPart": {}, - "invalidPartCategory": "Érvénytelen kategória", - "@invalidPartCategory": {}, - "invalidStockLocation": "Érvénytelen készlet hely", - "@invalidStockLocation": {}, - "invalidStockItem": "Érvénytelen készlet tétel", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", - "@invalidUsernamePassword": {}, - "issueDate": "Kiállítás dátuma", - "@issueDate": {}, - "itemInLocation": "A tétel már a megadott helyen van", - "@itemInLocation": {}, - "keywords": "Kulcsszavak", - "@keywords": {}, - "lastStocktake": "Utolsó leltár", - "@lastStocktake": {}, - "lastUpdated": "Utoljára módosítva", - "@lastUpdated": {}, - "lineItem": "Sortétel", - "@lineItem": {}, - "lineItems": "Sortételek", - "@lineItems": {}, - "locationCreate": "Új hely", - "@locationCreate": {}, - "locationCreateDetail": "Új készlet hely létrehozása", - "@locationCreateDetail": {}, - "locationNotSet": "Nincs megadva hely", - "@locationNotSet": {}, - "locationUpdated": "Készlet hely adatai frissítve", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Elveszett", - "@lost": {}, - "manufacturers": "Gyártók", - "@manufacturers": {}, - "missingData": "Hiányzó adatok", - "@missingData": {}, - "name": "Név", - "@name": {}, - "notConnected": "Nincs kapcsolódva", - "@notConnected": {}, - "notes": "Megjegyzések", - "@notes": { - "description": "Notes" - }, - "noResponse": "Nincs válasz a kiszolgálótól", - "@noResponse": {}, - "noResults": "Nincs találat", - "@noResults": {}, - "noSubcategories": "Nincsenek alkategóriák", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Nincsenek alkategóriák", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Érvénytelen szám", - "@numberInvalid": {}, - "onOrder": "Beszállítás alatt", - "@onOrder": {}, - "onOrderDetails": "Alaktrészek beszállítás alatt", - "@onOrderDetails": {}, - "packaging": "Csomagolás", - "@packaging": {}, - "packageName": "Csomag neve", - "@packageName": {}, - "parent": "Szülő", - "@parent": {}, - "parentCategory": "Szülő kategória", - "@parentCategory": {}, - "parentLocation": "Szülő hely", - "@parentLocation": {}, - "part": "Alkatrész", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Új alkatrész", - "@partCreate": {}, - "partCreateDetail": "Alkatrész létrehozása ebben a kategóriában", - "@partCreateDetail": {}, - "partEdited": "Alkatrész frissítve", - "@partEdited": {}, - "parts": "Alkatrészek", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Nincsenek alkatrészek", - "@partsNone": {}, - "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", - "@partNoResults": {}, - "partsStarred": "Értesítésre beállított alkatrészek", - "@partsStarred": {}, - "partsStarredNone": "Nincsenek csillagozott alkatrészek", - "@partsStarredNone": {}, - "partSuppliers": "Alkatrész beszállítók", - "@partSuppliers": {}, - "partCategory": "Alkatrész kategória", - "@partCategory": {}, - "partCategoryTopLevel": "Legfelső szintű alkatrész kategória", - "@partCategoryTopLevel": {}, - "partCategories": "Alkatrész kategóriák", - "@partCategories": {}, - "partDetails": "Alkatrész részletei", - "@partDetails": {}, - "partNotes": "Alkatrész megjegyzések", - "@partNotes": {}, - "partStock": "Alkatrész készlet", - "@partStock": { - "description": "part stock" - }, - "password": "Jelszó", - "@password": {}, - "passwordEmpty": "Jelszó nem lehet üres", - "@passwordEmpty": {}, - "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", - "@permissionAccountDenied": {}, - "permissionRequired": "Engedély szükséges", - "@permissionRequired": {}, - "printLabel": "Címke nyomtatása", - "@printLabel": {}, - "printLabelFailure": "Címkenyomtatás sikertelen", - "@printLabelFailure": {}, - "printLabelSuccess": "Címke nyomtatónak elküldve", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Kiszolgáló profil hozzáadása", - "@profileAdd": {}, - "profileConnect": "Kapcsolódás a kiszolgálóhoz", - "@profileConnect": {}, - "profileEdit": "Kiszolgáló profil szerkesztése", - "@profileEdit": {}, - "profileDelete": "Kiszolgáló profil törlése", - "@profileDelete": {}, - "profileName": "Profil neve", - "@profileName": {}, - "profileNone": "Nincsenek profilok", - "@profileNone": {}, - "profileNotSelected": "Nincs kiválasztva profil", - "@profileNotSelected": {}, - "profileSelect": "Válassz InvenTree kiszolgálót", - "@profileSelect": {}, - "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", - "@profileTapToCreate": {}, - "purchaseOrder": "Beszerzési rendelés", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Beszerzési rendelések", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Beszerzési rendelés frissítve", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Beszerzési ár", - "@purchasePrice": {}, - "quantity": "Mennyiség", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Mennyiség üres", - "@quantityEmpty": {}, - "quantityInvalid": "Mennyiség érvénytelen", - "@quantityInvalid": {}, - "quantityPositive": "Mennyiség pozitív kell legyen", - "@quantityPositive": {}, - "queryNoResults": "Nincs találat", - "@queryNoResults": {}, - "received": "Beérkezett", - "@received": {}, - "receiveItem": "Bevételezés", - "@receiveItem": {}, - "receivedItem": "Beérkezett készlet", - "@receivedItem": {}, - "refresh": "Frissítés", - "@refresh": {}, - "refreshing": "Frissítés...", - "@refreshing": {}, - "rejected": "Elutasított", - "@rejected": {}, - "releaseNotes": "Kiadási közlemények", - "@releaseNotes": {}, - "remove": "Törlés", - "@remove": { - "description": "remove" - }, - "removeStock": "Készlet csökkentése", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Hibabejelentés", - "@reportBug": {}, - "reportBugDescription": "Hibabejelentés küldése (GitHub fiók szükséges)", - "@reportBugDescription": {}, - "results": "Eredmények", - "@results": {}, - "request": "Kérés", - "@request": {}, - "requestingData": "Adatok lekérése", - "@requestingData": {}, - "required": "Kötelező", - "@required": { - "description": "This field is required" - }, - "response400": "Rossz kérés", - "@response400": {}, - "response401": "Jogosulatlan", - "@response401": {}, - "response403": "Hozzáférés megtagadva", - "@response403": {}, - "response404": "Erőforrás nem található", - "@response404": {}, - "response405": "Metódus nincs engedélyezve", - "@response405": {}, - "response429": "Túl sok kérés", - "@response429": {}, - "response500": "Belső kiszolgáló hiba", - "@response500": {}, - "response501": "Nincs implementálva", - "@response501": {}, - "response502": "Rossz átjáró", - "@response502": {}, - "response503": "A szolgáltatás nem érhető el", - "@response503": {}, - "response504": "Átjáró időtúllépés", - "@response504": {}, - "response505": "HTTP verzió nem támogatott", - "@response505": {}, - "responseData": "Válasz adatok", - "@responseData": {}, - "responseInvalid": "Érvénytelen válasz kód", - "@responseInvalid": {}, - "responseUnknown": "Ismeretlen válasz", - "@responseUnknown": {}, - "result": "Eredmény", - "@result": { - "description": "" - }, - "returned": "Visszaküldve", - "@returned": {}, - "salesOrders": "Vevői rendelések", - "@salesOrders": {}, - "save": "Mentés", - "@save": { - "description": "Save" - }, - "scanBarcode": "Vonalkód beolvasása", - "@scanBarcode": {}, - "scanIntoLocation": "Beolvasás helyre", - "@scanIntoLocation": {}, - "search": "Keresés", - "@search": { - "description": "search" - }, - "searchLocation": "Hely keresése", - "@searchLocation": {}, - "searchParts": "Alkatrészek keresése", - "@searchParts": {}, - "searchStock": "Készlet keresése", - "@searchStock": {}, - "select": "Kiválaszt", - "@select": {}, - "selectFile": "Fájl kiválasztása", - "@selectFile": {}, - "selectImage": "Válassz képet", - "@selectImage": {}, - "selectLocation": "Válassz helyet", - "@selectLocation": {}, - "send": "Küldés", - "@send": {}, - "serialNumber": "Sorozatszám", - "@serialNumber": {}, - "server": "Kiszolgáló", - "@server": {}, - "serverAddress": "Kiszolgáló címe", - "@serverAddress": {}, - "serverApiRequired": "Szükséges API verzió", - "@serverApiRequired": {}, - "serverApiVersion": "Szerver API verzió", - "@serverApiVersion": {}, - "serverAuthenticationError": "Hitelesítési hiba", - "@serverAuthenticationError": {}, - "serverCertificateError": "Tanúsítvány hiba", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Érvénytelen kiszolgáló HTTPS tanúsítvány", - "@serverCertificateInvalid": {}, - "serverConnected": "Kapcsolódva a kiszolgálóhoz", - "@serverConnected": {}, - "serverConnecting": "Kapcsolódás a kiszolgálóhoz", - "@serverConnecting": {}, - "serverCouldNotConnect": "Nem sikerült kapcsolódni a kiszolgálóhoz", - "@serverCouldNotConnect": {}, - "serverEmpty": "A kiszolgálónév nem lehet üres", - "@serverEmpty": {}, - "serverError": "Kiszolgálóhiba", - "@serverError": {}, - "serverDetails": "Kiszolgáló részletei", - "@serverDetails": {}, - "serverMissingData": "A kiszolgáló válaszából szükséges mezők hiányoznak", - "@serverMissingData": {}, - "serverOld": "Régi kiszolgáló verzió", - "@serverOld": {}, - "serverSettings": "Kiszolgáló beállítások", - "@serverSettings": {}, - "serverStart": "A kiszolgálónak http(s) kezdetűnek kell lennie", - "@serverStart": {}, - "settings": "Beállítások", - "@settings": {}, - "serverInstance": "Kiszolgáló példány", - "@serverInstance": {}, - "serverNotConnected": "Kiszolgáló nem csatlakozik", - "@serverNotConnected": {}, - "sounds": "Hangok", - "@sounds": {}, - "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", - "@soundOnServerError": {}, - "status": "Állapot", - "@status": {}, - "statusCode": "Állapot kód", - "@statusCode": {}, - "stock": "Készlet", - "@stock": { - "description": "stock" - }, - "stockDetails": "Jelenleg elérhető készlet mennyiség", - "@stockDetails": {}, - "stockItem": "Készlet tétel", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Készlet tételek", - "@stockItems": {}, - "stockItemCreate": "Új készlet tétel", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Új készlet tétel létrehozása ezen a helyen", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Készlet tétel törlése", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Biztosan törölni szeretnéd ezt a készlet tételt?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Készlet tétel nem törölhető", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Készlet tétel törölve", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Készlettörténet", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Készlettörténet megjelenítése", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Készlet áthelyezve", - "@stockItemTransferred": {}, - "stockItemUpdated": "Készlet tétel feltöltve", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Nincs elérhető készlet", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Készlet tétel megjegyzések", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Készlet tétel feltöltve", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Készlet tétel módosítása sikertelen", - "@stockItemUpdateFailure": {}, - "stockLocation": "Készlet hely", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Készlethelyek", - "@stockLocations": {}, - "stockTopLevel": "Legfelső szintű készlet hely", - "@stockTopLevel": {}, - "strictHttps": "Kizárólag HTTPS használata", - "@strictHttps": {}, - "strictHttpsDetails": "HTTPS tanúsítványok szigorú ellenőrzése", - "@strictHttpsDetails": {}, - "subcategory": "Alkategória", - "@subcategory": {}, - "subcategories": "Alkategóriák", - "@subcategories": {}, - "sublocation": "Alhely", - "@sublocation": {}, - "sublocations": "Alhelyek", - "@sublocations": {}, - "sublocationNone": "Nincsenek alhelyek", - "@sublocationNone": {}, - "sublocationNoneDetail": "Nincsenek elérhető alhelyek", - "@sublocationNoneDetail": {}, - "submitFeedback": "Visszajelzés Küldése", - "@submitFeedback": {}, - "suppliedParts": "Szállított alkatrészek", - "@suppliedParts": {}, - "supplier": "Beszállító", - "@supplier": {}, - "suppliers": "Beszállítók", - "@suppliers": {}, - "supplierReference": "Beszállítói azonosító", - "@supplierReference": {}, - "takePicture": "Fotó készítése", - "@takePicture": {}, - "targetDate": "Cél dátum", - "@targetDate": {}, - "templatePart": "Szülő sablon alkatrész", - "@templatePart": {}, - "testName": "Teszt neve", - "@testName": {}, - "testPassedOrFailed": "Teszt sikeres vagy sikertelen", - "@testPassedOrFailed": {}, - "testsRequired": "Szükséges tesztek", - "@testsRequired": {}, - "testResults": "Teszt eredmények", - "@testResults": { - "description": "" - }, - "testResultAdd": "Teszt eredmény hozzáadása", - "@testResultAdd": {}, - "testResultNone": "Nincsenek teszt eredmények", - "@testResultNone": {}, - "testResultNoneDetail": "Teszt eredmény nem áll rendelkezésre", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Hiba a teszt eredmény feltöltése közben", - "@testResultUploadFail": {}, - "testResultUploadPass": "Teszt eredmény feltöltve", - "@testResultUploadPass": {}, - "timeout": "Időtúllépés", - "@timeout": { - "description": "" - }, - "tokenError": "Token hiba", - "@tokenError": {}, - "tokenMissing": "Hiányzó token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", - "@tokenMissingFromResponse": {}, - "transfer": "Áthelyezés", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Készlet áthelyezése", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Fordítás", - "@translate": {}, - "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", - "@translateHelp": {}, - "units": "Mértékegységek", - "@units": {}, - "unknownResponse": "Ismeretlen válasz", - "@unknownResponse": {}, - "upload": "Feltöltés", - "@upload": {}, - "uploadFailed": "Fájl feltöltése sikertelen", - "@uploadFailed": {}, - "uploadSuccess": "Fájl feltöltve", - "@uploadSuccess": {}, - "usedIn": "Felhasználva ebben", - "@usedIn": {}, - "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", - "@usedInDetails": {}, - "username": "Felhasználónév", - "@username": {}, - "usernameEmpty": "Felhasználónév nem lehet üres", - "@usernameEmpty": {}, - "value": "Érték", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Az érték nem lehet üres", - "@valueCannotBeEmpty": {}, - "valueRequired": "Érték megadása szükséges", - "@valueRequired": {}, - "version": "Verzió", - "@version": {}, - "viewSupplierPart": "Beszállítói alkatrész megtekintése", - "@viewSupplierPart": {}, - "website": "Weboldal", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/id/app_id.arb b/lib/l10n/id/app_id.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/id/app_id.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/it/app_it.arb b/lib/l10n/it/app_it.arb deleted file mode 100644 index b5f5571..0000000 --- a/lib/l10n/it/app_it.arb +++ /dev/null @@ -1,505 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Info", - "@about": {}, - "accountDetails": "Dettagli account", - "@accountDetails": {}, - "actions": "Azioni", - "@actions": { - "description": "" - }, - "actionsNone": "Nessuna azione disponibile", - "@actionsNone": {}, - "add": "Aggiungi", - "@add": { - "description": "add" - }, - "address": "Indirizzo", - "@address": {}, - "appAbout": "Info su InvenTree", - "@appAbout": {}, - "appCredits": "Riconoscimenti addizionali", - "@appCredits": {}, - "appDetails": "Dettagli App", - "@appDetails": {}, - "appReleaseNotes": "Mostra le note di rilascio dell'app", - "@appReleaseNotes": {}, - "appSettings": "Impostazioni App", - "@appSettings": {}, - "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", - "@appSettingsDetails": {}, - "attachments": "Allegati", - "@attachments": {}, - "attachImage": "Allega Immagine", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nessun allegato trovato", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Seleziona allegato", - "@attachmentSelect": {}, - "attention": "Attenzione", - "@attention": {}, - "barcodeAssign": "Assegna Codice A Barre", - "@barcodeAssign": {}, - "barcodeAssigned": "Codice a barre assegnato", - "@barcodeAssigned": {}, - "barcodeError": "Errore scansione codice a barre", - "@barcodeError": {}, - "barcodeInUse": "Codice a barre già in uso", - "@barcodeInUse": {}, - "barcodeMissingHash": "Dati hash codice a barre mancanti dalla risposta", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Nessuna corrispondenza per il codice a barre", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Codice a barre non assegnato", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scansiona per assegnare codice a barre", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", - "@barcodeScanIntoLocationFailure": {}, - "barcodeTones": "Toni Codice a Barre", - "@barcodeTones": {}, - "barcodeUnassign": "Deseleziona Il Barcode", - "@barcodeUnassign": {}, - "barcodeUnknown": "Codice a barre non leggibile", - "@barcodeUnknown": {}, - "batchCode": "Codice Lotto", - "@batchCode": {}, - "billOfMaterials": "Distinta materiali", - "@billOfMaterials": {}, - "bom": "Distinta materiali", - "@bom": {}, - "build": "Crea", - "@build": {}, - "cancel": "Annulla", - "@cancel": { - "description": "Cancel" - }, - "category": "Categoria", - "@category": {}, - "categoryCreate": "Nuova categoria", - "@categoryCreate": {}, - "company": "Azienda", - "@company": {}, - "companyEdit": "Modifica azienda", - "@companyEdit": {}, - "companyNoResults": "Nessuna azienda corrispondente alla query", - "@companyNoResults": {}, - "companies": "Aziende", - "@companies": {}, - "connectionRefused": "Connessione rifiutata", - "@connectionRefused": {}, - "count": "Quantità", - "@count": { - "description": "Count" - }, - "credits": "Riconoscimenti", - "@credits": {}, - "customers": "Clienti", - "@customers": {}, - "damaged": "Danneggiato", - "@damaged": {}, - "delete": "Cancella", - "@delete": {}, - "description": "Descrizione", - "@description": {}, - "destroyed": "Distrutto", - "@destroyed": {}, - "details": "Dettagli", - "@details": { - "description": "details" - }, - "documentation": "Documentazione", - "@documentation": {}, - "downloading": "File in download", - "@downloading": {}, - "downloadError": "Errore download", - "@downloadError": {}, - "edit": "Modifica", - "@edit": { - "description": "edit" - }, - "editCategory": "Modifica Categoria", - "@editCategory": {}, - "enterPassword": "Inserire la password", - "@enterPassword": {}, - "enterUsername": "Inserisci nome utente", - "@enterUsername": {}, - "error": "Errore", - "@error": { - "description": "Error" - }, - "errorCreate": "Errore nella creazione della voce del database", - "@errorCreate": {}, - "errorDetails": "Dettagli errore", - "@errorDetails": {}, - "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", - "@errorFetch": {}, - "feedback": "Commenti e suggerimenti", - "@feedback": {}, - "feedbackError": "Errore nell'invio del feedback", - "@feedbackError": {}, - "feedbackSuccess": "Feedback inviato", - "@feedbackSuccess": {}, - "formatException": "Eccezione Formato", - "@formatException": {}, - "formatExceptionJson": "Eccezione formato dati JSON", - "@formatExceptionJson": {}, - "formError": "Errore Modulo", - "@formError": {}, - "history": "Cronologia", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "imageUploadFailure": "Il caricamento della foto è fallito", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Immagine caricata", - "@imageUploadSuccess": {}, - "inactive": "Inattivo", - "@inactive": {}, - "includeSubcategories": "Includi sottocategorie", - "@includeSubcategories": {}, - "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", - "@incompleteDetails": {}, - "info": "Info", - "@info": {}, - "invalidHost": "Nome host non valido", - "@invalidHost": {}, - "invalidHostDetails": "Il nome host fornito non è valido", - "@invalidHostDetails": {}, - "invalidUsernamePassword": "Combinazione nome utente e password non valida", - "@invalidUsernamePassword": {}, - "issueDate": "Data di emissione", - "@issueDate": {}, - "itemInLocation": "Elemento già in posizione", - "@itemInLocation": {}, - "keywords": "Parole Chiave", - "@keywords": {}, - "lastUpdated": "Ultimo aggiornamento", - "@lastUpdated": {}, - "lost": "Perso", - "@lost": {}, - "manufacturers": "Produttori", - "@manufacturers": {}, - "missingData": "Dati mancanti", - "@missingData": {}, - "name": "Nome", - "@name": {}, - "notConnected": "Non connesso", - "@notConnected": {}, - "notes": "Note", - "@notes": { - "description": "Notes" - }, - "noResponse": "Nessuna risposta dal server", - "@noResponse": {}, - "noResults": "Nessun risultato", - "@noResults": {}, - "noSubcategories": "Nessuna sotto categoria", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Numero non valido", - "@numberInvalid": {}, - "onOrderDetails": "Articoli attualmente in ordine", - "@onOrderDetails": {}, - "packaging": "Confezionamento", - "@packaging": {}, - "packageName": "Nome pacchetto", - "@packageName": {}, - "parent": "Superiore", - "@parent": {}, - "parentCategory": "Categoria Superiore", - "@parentCategory": {}, - "parts": "Articoli", - "@parts": { - "description": "Part (multiple)" - }, - "partSuppliers": "Fornitori articoli", - "@partSuppliers": {}, - "password": "Password", - "@password": {}, - "passwordEmpty": "La password non può essere vuota", - "@passwordEmpty": {}, - "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", - "@permissionAccountDenied": {}, - "permissionRequired": "Autorizzazione necessaria", - "@permissionRequired": {}, - "profile": "Profilo", - "@profile": {}, - "profileAdd": "Aggiungi Profilo Server", - "@profileAdd": {}, - "profileConnect": "Connetti al Server", - "@profileConnect": {}, - "profileEdit": "Modifica il profilo del Server", - "@profileEdit": {}, - "profileDelete": "Elimina Profilo Del Server", - "@profileDelete": {}, - "profileName": "Nome Profilo", - "@profileName": {}, - "profileNone": "Nessun profilo disponibile", - "@profileNone": {}, - "profileNotSelected": "Nessun profilo selezionato", - "@profileNotSelected": {}, - "profileSelect": "Seleziona Server InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Tocca per creare o selezionare un profilo", - "@profileTapToCreate": {}, - "purchaseOrder": "Ordine d'acquisto", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Modifica ordine d'acquisto", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Ordini d'acquisto", - "@purchaseOrders": {}, - "purchasePrice": "Prezzo d'acquisto", - "@purchasePrice": {}, - "quantity": "Quantità", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Quantità vuota", - "@quantityEmpty": {}, - "quantityInvalid": "La quantità non è valida", - "@quantityInvalid": {}, - "quantityPositive": "La quantità deve essere positiva", - "@quantityPositive": {}, - "queryNoResults": "Nessun risultato per la tua ricerca", - "@queryNoResults": {}, - "received": "Ricevuto", - "@received": {}, - "receiveItem": "Ricevi Articolo", - "@receiveItem": {}, - "refresh": "Aggiorna", - "@refresh": {}, - "refreshing": "In aggiornamento", - "@refreshing": {}, - "rejected": "Respinto", - "@rejected": {}, - "releaseNotes": "Note di Rilascio", - "@releaseNotes": {}, - "remove": "Rimuovi", - "@remove": { - "description": "remove" - }, - "reportBug": "Segnala un bug", - "@reportBug": {}, - "results": "Risultati", - "@results": {}, - "request": "Richiesta", - "@request": {}, - "requestingData": "Dati in richiesta", - "@requestingData": {}, - "required": "Richiesto", - "@required": { - "description": "This field is required" - }, - "response400": "Richiesta non valida", - "@response400": {}, - "response401": "Non Autorizzato", - "@response401": {}, - "response403": "Permesso negato", - "@response403": {}, - "response404": "Risorsa non trovata", - "@response404": {}, - "response405": "Metodo non consentito", - "@response405": {}, - "response429": "Troppe richieste", - "@response429": {}, - "response500": "Errore Interno del Server", - "@response500": {}, - "response501": "Non implementato", - "@response501": {}, - "response502": "Gateway Errato", - "@response502": {}, - "response503": "Servizio Non Disponibile", - "@response503": {}, - "response504": "Timeout del gateway", - "@response504": {}, - "response505": "Versione HTTP non supportata", - "@response505": {}, - "responseData": "Dati risposta", - "@responseData": {}, - "responseInvalid": "Codice Risposta Non Valido", - "@responseInvalid": {}, - "responseUnknown": "Risposta Sconosciuta", - "@responseUnknown": {}, - "result": "Risultato", - "@result": { - "description": "" - }, - "returned": "Restituito", - "@returned": {}, - "salesOrders": "Ordini di vendita", - "@salesOrders": {}, - "save": "Salva", - "@save": { - "description": "Save" - }, - "scanBarcode": "Scansiona codice a barre", - "@scanBarcode": {}, - "search": "Cerca", - "@search": { - "description": "search" - }, - "select": "Seleziona", - "@select": {}, - "selectFile": "Seleziona file", - "@selectFile": {}, - "selectImage": "Seleziona un'immagine", - "@selectImage": {}, - "send": "Invia", - "@send": {}, - "serialNumber": "Numero seriale", - "@serialNumber": {}, - "server": "Server", - "@server": {}, - "serverAddress": "Indirizzo del server", - "@serverAddress": {}, - "serverApiRequired": "Versione API Richiesta", - "@serverApiRequired": {}, - "serverApiVersion": "Versione API Server", - "@serverApiVersion": {}, - "serverAuthenticationError": "Errore di autenticazione", - "@serverAuthenticationError": {}, - "serverCertificateError": "Errore certificato", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Il certificato del server non è valido", - "@serverCertificateInvalid": {}, - "serverConnected": "Connesso al Server", - "@serverConnected": {}, - "serverConnecting": "Connessione al server", - "@serverConnecting": {}, - "serverCouldNotConnect": "Impossibile connettersi al server", - "@serverCouldNotConnect": {}, - "serverEmpty": "Nome server non può essere vuoto", - "@serverEmpty": {}, - "serverError": "Errore del server", - "@serverError": {}, - "serverDetails": "Dettagli del server", - "@serverDetails": {}, - "serverMissingData": "Dati mancanti nella risposta del server", - "@serverMissingData": {}, - "serverOld": "Versione Vecchia Del Server", - "@serverOld": {}, - "serverSettings": "Impostazioni Server", - "@serverSettings": {}, - "serverStart": "Il server deve iniziare con http[s]", - "@serverStart": {}, - "settings": "Impostazioni", - "@settings": {}, - "serverInstance": "Istanza Del Server", - "@serverInstance": {}, - "serverNotConnected": "Server non connesso", - "@serverNotConnected": {}, - "sounds": "Audio", - "@sounds": {}, - "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Riproduci il tono sonoro su un errore del server", - "@soundOnServerError": {}, - "status": "Stato", - "@status": {}, - "statusCode": "Codice di stato", - "@statusCode": {}, - "stock": "Magazzino", - "@stock": { - "description": "stock" - }, - "subcategory": "Sottocategoria", - "@subcategory": {}, - "subcategories": "Sottocategorie", - "@subcategories": {}, - "submitFeedback": "Invia feedback", - "@submitFeedback": {}, - "supplier": "Fornitore", - "@supplier": {}, - "suppliers": "Fornitori", - "@suppliers": {}, - "supplierReference": "Riferimento fornitore", - "@supplierReference": {}, - "takePicture": "Scatta Foto", - "@takePicture": {}, - "testName": "Nome del test", - "@testName": {}, - "testPassedOrFailed": "Test superato o fallito", - "@testPassedOrFailed": {}, - "testsRequired": "Test Richiesti", - "@testsRequired": {}, - "testResults": "Risultati del test", - "@testResults": { - "description": "" - }, - "testResultAdd": "Aggiungi Risultato Test", - "@testResultAdd": {}, - "testResultNone": "Nessun Risultato Del Test", - "@testResultNone": {}, - "testResultNoneDetail": "Nessun risultato del test disponibile", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Errore nel caricamento del risultato del test", - "@testResultUploadFail": {}, - "testResultUploadPass": "Risultato del test caricato", - "@testResultUploadPass": {}, - "timeout": "Tempo Scaduto", - "@timeout": { - "description": "" - }, - "tokenError": "Errore Token", - "@tokenError": {}, - "tokenMissing": "Token Mancante", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", - "@tokenMissingFromResponse": {}, - "transfer": "Trasferisci", - "@transfer": { - "description": "transfer" - }, - "translate": "Traduci", - "@translate": {}, - "translateHelp": "Aiuta a tradurre l'app InvenTree", - "@translateHelp": {}, - "units": "Unità", - "@units": {}, - "unknownResponse": "Risposta Sconosciuta", - "@unknownResponse": {}, - "upload": "Carica", - "@upload": {}, - "uploadFailed": "Caricamento di file non riuscito", - "@uploadFailed": {}, - "uploadSuccess": "File caricato", - "@uploadSuccess": {}, - "usedIn": "Viene utilizzato in", - "@usedIn": {}, - "username": "Nome utente", - "@username": {}, - "usernameEmpty": "Il nome utente non può essere vuoto", - "@usernameEmpty": {}, - "value": "Valore", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Il valore non può essere vuoto", - "@valueCannotBeEmpty": {}, - "valueRequired": "È richiesto un valore", - "@valueRequired": {}, - "version": "Versione", - "@version": {}, - "viewSupplierPart": "Visualizza Fornitore", - "@viewSupplierPart": {}, - "website": "Sito Web", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/ja/app_ja.arb b/lib/l10n/ja/app_ja.arb deleted file mode 100644 index 36bf7fc..0000000 --- a/lib/l10n/ja/app_ja.arb +++ /dev/null @@ -1,682 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "概要", - "@about": {}, - "accountDetails": "アカウントの詳細", - "@accountDetails": {}, - "actions": "アクション", - "@actions": { - "description": "" - }, - "actionsNone": "利用可能なアクションはありません", - "@actionsNone": {}, - "add": "追加", - "@add": { - "description": "add" - }, - "addStock": "在庫を追加", - "@addStock": { - "description": "add stock" - }, - "address": "アドレス", - "@address": {}, - "appAbout": "InvenTree について", - "@appAbout": {}, - "appCredits": "すぺしゃる★さんくす!", - "@appCredits": {}, - "appDetails": "アプリ詳細", - "@appDetails": {}, - "appReleaseNotes": "アプリのリリースノートを表示", - "@appReleaseNotes": {}, - "appSettings": "アプリ設定", - "@appSettings": {}, - "appSettingsDetails": "アプリ設定を構成します", - "@appSettingsDetails": {}, - "attachments": "添付ファイル", - "@attachments": {}, - "attachImage": "画像を添付", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "添付ファイルが見つかりません。", - "@attachmentNone": {}, - "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "添付ファイルを選択", - "@attachmentSelect": {}, - "attention": "注意", - "@attention": {}, - "availableStock": "在庫あり", - "@availableStock": {}, - "barcodeAssign": "バーコードを割り当てる", - "@barcodeAssign": {}, - "barcodeAssigned": "バーコードが割り当てられました", - "@barcodeAssigned": {}, - "barcodeError": "バーコードのスキャンエラー", - "@barcodeError": {}, - "barcodeInUse": "バーコードは既に割り当てられています", - "@barcodeInUse": {}, - "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "バーコードが一致しません", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "バーコードが割り当てられていません", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "スキャンしてバーコードを割り当てます", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "InvenTree バーコードをスキャンする", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "在庫アイテムを在庫場所にスキャン", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "在庫場所をスキャン", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "在庫アイテムをスキャン", - "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", - "@barcodeTones": {}, - "barcodeUnassign": "バーコードの割り当てを解除", - "@barcodeUnassign": {}, - "barcodeUnknown": "バーコードが認識されません", - "@barcodeUnknown": {}, - "billOfMaterials": "Bill of Materials", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "ビルド", - "@build": {}, - "building": "ビルド", - "@building": {}, - "cancel": "キャンセル", - "@cancel": { - "description": "Cancel" - }, - "category": "カテゴリ", - "@category": {}, - "categoryCreate": "新規カテゴリ", - "@categoryCreate": {}, - "categoryCreateDetail": "新しい部品カテゴリを作成", - "@categoryCreateDetail": {}, - "categoryUpdated": "部品カテゴリを更新しました", - "@categoryUpdated": {}, - "company": "会社", - "@company": {}, - "companyEdit": "会社を編集", - "@companyEdit": {}, - "companyNoResults": "検索条件に一致する会社はありません", - "@companyNoResults": {}, - "companyUpdated": "会社の詳細を更新しました", - "@companyUpdated": {}, - "companies": "会社", - "@companies": {}, - "configureServer": "サーバー設定", - "@configureServer": {}, - "connectionRefused": "接続を拒否しました", - "@connectionRefused": {}, - "count": "カウント", - "@count": { - "description": "Count" - }, - "countStock": "在庫数", - "@countStock": { - "description": "Count Stock" - }, - "credits": "謝辞", - "@credits": {}, - "customers": "顧客", - "@customers": {}, - "damaged": "破損", - "@damaged": {}, - "delete": "削除", - "@delete": {}, - "deletePart": "部品を削除", - "@deletePart": {}, - "deletePartDetail": "データベースからこの部品を削除します", - "@deletePartDetail": {}, - "description": "説明", - "@description": {}, - "destroyed": "破壊", - "@destroyed": {}, - "details": "詳細", - "@details": { - "description": "details" - }, - "documentation": "ドキュメント", - "@documentation": {}, - "downloading": "ファイルをダウンロード中", - "@downloading": {}, - "downloadError": "ダウンロードエラー", - "@downloadError": {}, - "edit": "編集", - "@edit": { - "description": "edit" - }, - "editCategory": "カテゴリの編集", - "@editCategory": {}, - "editLocation": "在庫場所を編集", - "@editLocation": {}, - "editNotes": "メモを編集", - "@editNotes": {}, - "editPart": "パートの編集", - "@editPart": { - "description": "edit part" - }, - "editItem": "在庫商品を編集", - "@editItem": {}, - "enterPassword": "パスワードを入力してください", - "@enterPassword": {}, - "enterUsername": "ユーザー名を入力してください", - "@enterUsername": {}, - "error": "エラー", - "@error": { - "description": "Error" - }, - "errorCreate": "データベースの作成中にエラーが発生しました", - "@errorCreate": {}, - "errorDelete": "データベースの削除中にエラーが発生しました", - "@errorDelete": {}, - "errorDetails": "エラーの詳細", - "@errorDetails": {}, - "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", - "@errorFetch": {}, - "errorReporting": "エラー報告", - "@errorReporting": {}, - "errorReportUpload": "エラー報告をアップロード", - "@errorReportUpload": {}, - "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", - "@errorReportUploadDetails": {}, - "feedback": "フィードバック", - "@feedback": {}, - "feedbackError": "フィードバックの送信エラー", - "@feedbackError": {}, - "feedbackSuccess": "フィードバックが送信されました", - "@feedbackSuccess": {}, - "formatException": "フォーマットの例外エラー", - "@formatException": {}, - "formatExceptionJson": "JSONデータフォーマット例外エラー", - "@formatExceptionJson": {}, - "formError": "フォームエラー", - "@formError": {}, - "history": "履歴", - "@history": { - "description": "history" - }, - "homeScreen": "ホーム画面", - "@homeScreen": {}, - "homeScreenSettings": "ホーム画面の設定", - "@homeScreenSettings": {}, - "homeShowPo": "注文書を表示", - "@homeShowPo": {}, - "homeShowSubscribed": "購読済みのパーツ", - "@homeShowSubscribed": {}, - "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "仕入先を表示", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "メーカーを表示", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "顧客を表示", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "画像のアップロードに失敗しました", - "@imageUploadFailure": {}, - "imageUploadSuccess": "アップロードされた画像", - "@imageUploadSuccess": {}, - "inactive": "無効", - "@inactive": {}, - "inactiveDetail": "この部品は無効としてマークされています", - "@inactiveDetail": {}, - "includeSubcategories": "サブカテゴリを含む", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "サブカテゴリをリストビューに表示します", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "サブ在庫場所を含める", - "@includeSublocations": {}, - "includeSublocationsDetail": "サブ在庫場所を表示します", - "@includeSublocationsDetail": {}, - "incompleteDetails": "不完全なプロフィールの詳細", - "@incompleteDetails": {}, - "internalPartNumber": "内部パーツ番号", - "@internalPartNumber": {}, - "info": "情報", - "@info": {}, - "inProduction": "生産中", - "@inProduction": {}, - "inProductionDetail": "この在庫品は生産中です", - "@inProductionDetail": {}, - "invalidHost": "無効なホスト名", - "@invalidHost": {}, - "invalidHostDetails": "このホスト名は無効です。", - "@invalidHostDetails": {}, - "invalidPart": "無効なパーツ", - "@invalidPart": {}, - "invalidPartCategory": "無効なパーツカテゴリー", - "@invalidPartCategory": {}, - "invalidStockLocation": "無効な在庫場所", - "@invalidStockLocation": {}, - "invalidStockItem": "無効な在庫アイテム", - "@invalidStockItem": {}, - "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", - "@invalidUsernamePassword": {}, - "issueDate": "発行日", - "@issueDate": {}, - "itemInLocation": "アイテムは既に在庫場所にあります", - "@itemInLocation": {}, - "keywords": "キーワード", - "@keywords": {}, - "lastUpdated": "最終更新", - "@lastUpdated": {}, - "locationCreate": "新しい場所", - "@locationCreate": {}, - "locationCreateDetail": "新しい在庫場所を作成", - "@locationCreateDetail": {}, - "locationNotSet": "在庫場所が指定されていません", - "@locationNotSet": {}, - "locationUpdated": "在庫場所を更新しました", - "@locationUpdated": {}, - "link": "リンク", - "@link": {}, - "lost": "損失", - "@lost": {}, - "missingData": "データ消失", - "@missingData": {}, - "name": "名前", - "@name": {}, - "notConnected": "接続されていません", - "@notConnected": {}, - "notes": "メモ", - "@notes": { - "description": "Notes" - }, - "noResponse": "サーバーからの応答がありません", - "@noResponse": {}, - "noResults": "一致する結果なし", - "@noResults": {}, - "noSubcategories": "サブカテゴリはありません", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "無効な値", - "@numberInvalid": {}, - "onOrder": "注文中", - "@onOrder": {}, - "packaging": "梱包中", - "@packaging": {}, - "packageName": "パッケージ名", - "@packageName": {}, - "parent": "親", - "@parent": {}, - "parentCategory": "親カテゴリ", - "@parentCategory": {}, - "parentLocation": "上位の場所", - "@parentLocation": {}, - "part": "パーツ", - "@part": { - "description": "Part (single)" - }, - "parts": "パーツ", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "パーツがありません", - "@partsNone": {}, - "partsStarredNone": "お気に入りのパーツはありません", - "@partsStarredNone": {}, - "partCategory": "パーツカテゴリー", - "@partCategory": {}, - "partCategoryTopLevel": "トップレベルのパーツカテゴリ", - "@partCategoryTopLevel": {}, - "partCategories": "パーツカテゴリー", - "@partCategories": {}, - "partDetails": "パーツ詳細", - "@partDetails": {}, - "partNotes": "パーツメモ", - "@partNotes": {}, - "partStock": "パーツ在庫:", - "@partStock": { - "description": "part stock" - }, - "password": "パスワード", - "@password": {}, - "passwordEmpty": "パスワードは空欄にできません。", - "@passwordEmpty": {}, - "permissionAccountDenied": "操作を行う権限がありません", - "@permissionAccountDenied": {}, - "permissionRequired": "権限が必要です", - "@permissionRequired": {}, - "printLabel": "ラベルを印刷", - "@printLabel": {}, - "printLabelFailure": "ラベルの印刷に失敗しました", - "@printLabelFailure": {}, - "printLabelSuccess": "ラベルをプリンタに送信しました", - "@printLabelSuccess": {}, - "profile": "プロフィール", - "@profile": {}, - "profileAdd": "サーバープロファイルを追加", - "@profileAdd": {}, - "profileConnect": "サーバーに接続", - "@profileConnect": {}, - "profileEdit": "サーバープロファイルを編集", - "@profileEdit": {}, - "profileDelete": "サーバープロファイルの削除", - "@profileDelete": {}, - "profileName": "プロファイル名", - "@profileName": {}, - "profileNone": "利用可能なプロファイルがありません", - "@profileNone": {}, - "profileNotSelected": "プロフィールが選択されていません", - "@profileNotSelected": {}, - "profileSelect": "InvenTreeサーバーを選択", - "@profileSelect": {}, - "profileTapToCreate": "タップしてプロフィールを作成または選択します", - "@profileTapToCreate": {}, - "purchaseOrder": "発注書", - "@purchaseOrder": {}, - "purchaseOrderEdit": "発注書の更新", - "@purchaseOrderEdit": {}, - "purchaseOrders": "発注書", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "発注書が更新されました", - "@purchaseOrderUpdated": {}, - "purchasePrice": "購入金額", - "@purchasePrice": {}, - "quantity": "数量", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "数量が空です", - "@quantityEmpty": {}, - "quantityInvalid": "数量が無効です", - "@quantityInvalid": {}, - "quantityPositive": "数量は1以上", - "@quantityPositive": {}, - "queryNoResults": "検索結果はありません", - "@queryNoResults": {}, - "refresh": "更新", - "@refresh": {}, - "refreshing": "更新中", - "@refreshing": {}, - "rejected": "却下済み", - "@rejected": {}, - "releaseNotes": "リリースノート", - "@releaseNotes": {}, - "remove": "削除", - "@remove": { - "description": "remove" - }, - "removeStock": "在庫を削除", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "不具合の報告", - "@reportBug": {}, - "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", - "@reportBugDescription": {}, - "results": "結果", - "@results": {}, - "request": "リクエスト", - "@request": {}, - "requestingData": "データをリクエスト中", - "@requestingData": {}, - "required": "必須", - "@required": { - "description": "This field is required" - }, - "response400": "不正なリクエスト", - "@response400": {}, - "response401": "認証されていません", - "@response401": {}, - "response403": "権限がありません", - "@response403": {}, - "response404": "リソースが見つかりません", - "@response404": {}, - "response405": "メソッドが許可されていません", - "@response405": {}, - "response429": "リクエストが多すぎます", - "@response429": {}, - "response501": "未実装", - "@response501": {}, - "response503": "サービスは利用できません", - "@response503": {}, - "response505": "このHTTP バージョンはサポートされていません", - "@response505": {}, - "responseData": "応答データ", - "@responseData": {}, - "responseInvalid": "無効な応答", - "@responseInvalid": {}, - "responseUnknown": "不明な応答コード", - "@responseUnknown": {}, - "result": "結果", - "@result": { - "description": "" - }, - "returned": "返品済", - "@returned": {}, - "save": "保存", - "@save": { - "description": "Save" - }, - "scanBarcode": "バーコードをスキャン", - "@scanBarcode": {}, - "scanIntoLocation": "スキャンされた在庫場所", - "@scanIntoLocation": {}, - "search": "検索", - "@search": { - "description": "search" - }, - "searchLocation": "在庫場所場所を検索", - "@searchLocation": {}, - "searchParts": "パーツの検索", - "@searchParts": {}, - "searchStock": "在庫を検索", - "@searchStock": {}, - "select": "選択", - "@select": {}, - "selectFile": "ファイルを選択", - "@selectFile": {}, - "selectImage": "画像を選択", - "@selectImage": {}, - "selectLocation": "在庫場所を選択", - "@selectLocation": {}, - "send": "送信", - "@send": {}, - "serialNumber": "シリアルナンバー", - "@serialNumber": {}, - "server": "サーバー", - "@server": {}, - "serverAddress": "サーバーアドレス:", - "@serverAddress": {}, - "serverApiRequired": "必要なAPIバージョン", - "@serverApiRequired": {}, - "serverApiVersion": "サーバー API バージョン", - "@serverApiVersion": {}, - "serverAuthenticationError": "認証エラー", - "@serverAuthenticationError": {}, - "serverCertificateError": "認証エラー", - "@serverCertificateError": {}, - "serverCertificateInvalid": "サーバー HTTPS 証明書が無効です", - "@serverCertificateInvalid": {}, - "serverConnected": "サーバへ接続しました\n", - "@serverConnected": {}, - "serverConnecting": "サーバに接続中", - "@serverConnecting": {}, - "serverCouldNotConnect": "サーバーに接続できませんでした", - "@serverCouldNotConnect": {}, - "serverError": "サーバーエラー", - "@serverError": {}, - "serverDetails": "サーバの詳細", - "@serverDetails": {}, - "serverOld": "旧サーバーのバージョン", - "@serverOld": {}, - "serverSettings": "サーバー設定:", - "@serverSettings": {}, - "serverStart": "サーバーは http[s] で開始する必要があります", - "@serverStart": {}, - "settings": "設定", - "@settings": {}, - "serverInstance": "サーバインスタンス", - "@serverInstance": {}, - "serverNotConnected": "サーバーに接続されていません", - "@serverNotConnected": {}, - "sounds": "サウンド", - "@sounds": {}, - "soundOnBarcodeAction": "バーコード動作で音を鳴らす", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "サーバーのエラー時に音を鳴らす", - "@soundOnServerError": {}, - "status": "ステータス", - "@status": {}, - "statusCode": "ステータスコード", - "@statusCode": {}, - "stock": "在庫", - "@stock": { - "description": "stock" - }, - "stockItem": "在庫アイテム", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "在庫アイテム", - "@stockItems": {}, - "stockItemCreate": "新しい在庫アイテム", - "@stockItemCreate": {}, - "stockItemCreateDetail": "この場所に新しい在庫アイテムを作成", - "@stockItemCreateDetail": {}, - "stockItemDelete": "在庫アイテムを削除", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "この在庫アイテムを削除しますか?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "在庫アイテムを削除できませんでした。", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "在庫アイテムを削除しました", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "在庫履歴", - "@stockItemHistory": {}, - "stockItemTransferred": "在庫アイテムが転送されました", - "@stockItemTransferred": {}, - "stockItemUpdated": "在庫アイテムが更新されました", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "在庫アイテムがありません", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "在庫アイテムメモ", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "在庫アイテムが更新されました", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", - "@stockItemUpdateFailure": {}, - "stockLocation": "在庫場所", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "在庫場所", - "@stockLocations": {}, - "stockTopLevel": "トップレベルの在庫場所", - "@stockTopLevel": {}, - "strictHttps": "厳格なHTTPSを使用", - "@strictHttps": {}, - "subcategory": "サブカテゴリー", - "@subcategory": {}, - "subcategories": "サブカテゴリー", - "@subcategories": {}, - "sublocation": "サブ在庫場所", - "@sublocation": {}, - "sublocations": "サブ在庫場所", - "@sublocations": {}, - "sublocationNone": "サブ在庫場所がありません", - "@sublocationNone": {}, - "sublocationNoneDetail": "利用可能なサブ在庫場所がありません", - "@sublocationNoneDetail": {}, - "submitFeedback": "フィードバックを送信", - "@submitFeedback": {}, - "supplier": "サプライヤー", - "@supplier": {}, - "suppliers": "サプライヤー", - "@suppliers": {}, - "takePicture": "画像を撮影", - "@takePicture": {}, - "templatePart": "上位テンプレートパーツ", - "@templatePart": {}, - "testName": "テスト名", - "@testName": {}, - "testPassedOrFailed": "テストの合格または失敗", - "@testPassedOrFailed": {}, - "testsRequired": "必須テスト", - "@testsRequired": {}, - "testResults": "テスト結果", - "@testResults": { - "description": "" - }, - "testResultAdd": "テスト結果を追加", - "@testResultAdd": {}, - "testResultNone": "テスト結果がありません", - "@testResultNone": {}, - "testResultNoneDetail": "利用可能なテスト結果がありません", - "@testResultNoneDetail": {}, - "testResultUploadFail": "テスト結果のアップロードエラー", - "@testResultUploadFail": {}, - "testResultUploadPass": "テスト結果がアップロードされました", - "@testResultUploadPass": {}, - "timeout": "タイムアウト", - "@timeout": { - "description": "" - }, - "tokenError": "トークンエラー", - "@tokenError": {}, - "tokenMissing": "トークンがありません", - "@tokenMissing": {}, - "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", - "@tokenMissingFromResponse": {}, - "transfer": "転送", - "@transfer": { - "description": "transfer" - }, - "transferStock": "在庫の転送", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "翻訳", - "@translate": {}, - "translateHelp": "InvenTree アプリの翻訳に協力する", - "@translateHelp": {}, - "units": "単位", - "@units": {}, - "unknownResponse": "不明な応答", - "@unknownResponse": {}, - "upload": "アップロード", - "@upload": {}, - "uploadFailed": "ファイルのアップロードに失敗しました。", - "@uploadFailed": {}, - "uploadSuccess": "アップロードされたファイル", - "@uploadSuccess": {}, - "username": "ユーザー名", - "@username": {}, - "usernameEmpty": "ユーザー名は空にできません。", - "@usernameEmpty": {}, - "value": "設定値", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "値を空にすることはできません。", - "@valueCannotBeEmpty": {}, - "valueRequired": "値が必要です", - "@valueRequired": {}, - "version": "バージョン", - "@version": {}, - "website": "Webサイト", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/ko/app_ko.arb b/lib/l10n/ko/app_ko.arb deleted file mode 100644 index 6dd3712..0000000 --- a/lib/l10n/ko/app_ko.arb +++ /dev/null @@ -1,105 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "add": "추가", - "@add": { - "description": "add" - }, - "address": "주소", - "@address": {}, - "appAbout": "InvenTree 소개", - "@appAbout": {}, - "appReleaseNotes": "앱 릴리즈 노트 표시", - "@appReleaseNotes": {}, - "appSettings": "앱 설정", - "@appSettings": {}, - "billOfMaterials": "부품 명세서", - "@billOfMaterials": {}, - "cancel": "취소", - "@cancel": { - "description": "Cancel" - }, - "company": "회사", - "@company": {}, - "companyEdit": "회사 수정", - "@companyEdit": {}, - "error": "오류", - "@error": { - "description": "Error" - }, - "errorDetails": "오류 세부 정보", - "@errorDetails": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "keywords": "키워드", - "@keywords": {}, - "noResults": "결과 없음", - "@noResults": {}, - "password": "비밀번호", - "@password": {}, - "passwordEmpty": "비밀번호는 비워둘 수 없습니다", - "@passwordEmpty": {}, - "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", - "@permissionAccountDenied": {}, - "profileConnect": "서버에 연결", - "@profileConnect": {}, - "quantity": "수량", - "@quantity": { - "description": "Quantity" - }, - "reportBug": "버그 신고", - "@reportBug": {}, - "response505": "지원되지 않는 HTTP 버전", - "@response505": {}, - "save": "저장", - "@save": { - "description": "Save" - }, - "select": "선택", - "@select": {}, - "selectFile": "파일 선택", - "@selectFile": {}, - "server": "서버", - "@server": {}, - "serverAddress": "서버 주소", - "@serverAddress": {}, - "serverApiRequired": "필요한 API 버전", - "@serverApiRequired": {}, - "serverApiVersion": "서버 API 버전", - "@serverApiVersion": {}, - "serverAuthenticationError": "인증 오류", - "@serverAuthenticationError": {}, - "serverConnecting": "서버에 연결하는 중", - "@serverConnecting": {}, - "serverError": "서버 오류", - "@serverError": {}, - "serverOld": "오래된 서버 버전", - "@serverOld": {}, - "serverSettings": "서버 설정", - "@serverSettings": {}, - "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", - "@serverStart": {}, - "status": "상태", - "@status": {}, - "statusCode": "상태 코드", - "@statusCode": {}, - "targetDate": "목표 날짜", - "@targetDate": {}, - "timeout": "시간 초과", - "@timeout": { - "description": "" - }, - "tokenError": "토큰 오류", - "@tokenError": {}, - "translate": "번역", - "@translate": {}, - "translateHelp": "InvenTree 앱의 번역을 도와주세요", - "@translateHelp": {}, - "version": "버전", - "@version": {}, - "website": "웹사이트", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/nl/app_nl.arb b/lib/l10n/nl/app_nl.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/nl/app_nl.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/no/app_no.arb b/lib/l10n/no/app_no.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/no/app_no.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/pl/app_pl.arb b/lib/l10n/pl/app_pl.arb deleted file mode 100644 index af617ea..0000000 --- a/lib/l10n/pl/app_pl.arb +++ /dev/null @@ -1,739 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "O nas", - "@about": {}, - "accountDetails": "Szczegóły konta", - "@accountDetails": {}, - "actions": "Działania", - "@actions": { - "description": "" - }, - "actionsNone": "Brak dostępnych działań", - "@actionsNone": {}, - "add": "Dodaj", - "@add": { - "description": "add" - }, - "addStock": "Dodaj stan", - "@addStock": { - "description": "add stock" - }, - "address": "Adresy", - "@address": {}, - "appAbout": "O InvenTree", - "@appAbout": {}, - "appCredits": "Dodatkowe podziękowania autorskie", - "@appCredits": {}, - "appDetails": "Szczegóły aplikacji", - "@appDetails": {}, - "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", - "@appReleaseNotes": {}, - "appSettings": "Ustawienia aplikacji", - "@appSettings": {}, - "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", - "@appSettingsDetails": {}, - "attachments": "Załączniki", - "@attachments": {}, - "attachImage": "Dodaj zdjęcie", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nie znaleziono załączników", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Brak załączników dla tego komponentu", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Wybierz załącznik", - "@attachmentSelect": {}, - "attention": "Uwaga", - "@attention": {}, - "barcodeAssign": "Przypisz kod kreskowy", - "@barcodeAssign": {}, - "barcodeAssigned": "Kod kreskowy przypisany", - "@barcodeAssigned": {}, - "barcodeError": "Błąd czytnika kodów kreskowych", - "@barcodeError": {}, - "barcodeInUse": "Kod kreskowy jest już przypisany", - "@barcodeInUse": {}, - "barcodeMissingHash": "Brak danych haszujących w odpowiedzi kodu kreskowego", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Brak dopasowania dla kodu kreskowego", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Kod kreskowy nieprzypisany", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Zeskanuj przedmioty do lokalizacji", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Skanuj lokalizację zapasów", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Skanuj element magazynowy", - "@barcodeScanItem": {}, - "barcodeTones": "Dźwięki kodów kreskowych", - "@barcodeTones": {}, - "barcodeUnassign": "Nieprzydzielony kod kreskowy", - "@barcodeUnassign": {}, - "barcodeUnknown": "Nie rozpoznano kodu kreskowego", - "@barcodeUnknown": {}, - "batchCode": "Kod partii", - "@batchCode": {}, - "billOfMaterials": "Zestawienie materiałów", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Budowa", - "@build": {}, - "building": "Budowanie", - "@building": {}, - "cancel": "Anuluj", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategoria", - "@category": {}, - "categoryCreate": "Nowa Kategoria", - "@categoryCreate": {}, - "categoryCreateDetail": "Utwórz nową kategorię komponentu", - "@categoryCreateDetail": {}, - "categoryUpdated": "Kategoria części została zmieniona", - "@categoryUpdated": {}, - "company": "Firma", - "@company": {}, - "companyEdit": "Edytuj Firmę", - "@companyEdit": {}, - "companyNoResults": "Brak firm pasujących do zapytania", - "@companyNoResults": {}, - "companyUpdated": "Szczegóły firmy zostały zaktualizowane", - "@companyUpdated": {}, - "companies": "Firmy", - "@companies": {}, - "configureServer": "Konfiguruj ustawienia serwera", - "@configureServer": {}, - "connectionRefused": "Połączenie odrzucone", - "@connectionRefused": {}, - "count": "Ilość", - "@count": { - "description": "Count" - }, - "countStock": "Przelicz stan", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Podziękowania", - "@credits": {}, - "customers": "Klienci", - "@customers": {}, - "damaged": "Uszkodzone", - "@damaged": {}, - "delete": "Usuń", - "@delete": {}, - "deletePart": "Usuń Komponent", - "@deletePart": {}, - "deletePartDetail": "Usuń ten komponent z bazy danych", - "@deletePartDetail": {}, - "description": "Opis", - "@description": {}, - "destroyed": "Zniszczony", - "@destroyed": {}, - "details": "Szczegóły", - "@details": { - "description": "details" - }, - "documentation": "Dokumentacja", - "@documentation": {}, - "downloading": "Pobieranie Pliku", - "@downloading": {}, - "downloadError": "Błąd Pobierania", - "@downloadError": {}, - "edit": "Edytuj", - "@edit": { - "description": "edit" - }, - "editCategory": "Edytuj kategorię", - "@editCategory": {}, - "editLocation": "Edytuj lokację", - "@editLocation": {}, - "editNotes": "Edytuj Notatki", - "@editNotes": {}, - "editPart": "Edytuj część", - "@editPart": { - "description": "edit part" - }, - "editItem": "Edytuj Pozycję Magazynową", - "@editItem": {}, - "enterPassword": "Wprowadź hasło", - "@enterPassword": {}, - "enterUsername": "Wprowadź nazwę użytkownika", - "@enterUsername": {}, - "error": "Błąd", - "@error": { - "description": "Error" - }, - "errorCreate": "Błąd tworzenia wpisu w bazie danych", - "@errorCreate": {}, - "errorDelete": "Błąd podczas usuwania wpisu bazy danych", - "@errorDelete": {}, - "errorDetails": "Szczegóły błędu", - "@errorDetails": {}, - "errorFetch": "Błąd pobierania danych z serwea", - "@errorFetch": {}, - "errorReporting": "Raportowanie błędów", - "@errorReporting": {}, - "errorReportUpload": "Prześlij raport o błędach", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", - "@errorReportUploadDetails": {}, - "feedback": "Opinie", - "@feedback": {}, - "feedbackError": "Błąd dodawania opinii", - "@feedbackError": {}, - "feedbackSuccess": "Opinia przesłana", - "@feedbackSuccess": {}, - "formatException": "Wyjątek formatowania", - "@formatException": {}, - "formatExceptionJson": "Wyjątek formatu danych JSON", - "@formatExceptionJson": {}, - "formError": "Błąd Formularza", - "@formError": {}, - "history": "Historia", - "@history": { - "description": "history" - }, - "homeScreen": "Ekran główny", - "@homeScreen": {}, - "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", - "@homeScreenSettings": {}, - "homeShowPo": "Pokaż zamówienia zakupu", - "@homeShowPo": {}, - "homeShowSubscribed": "Obserwowane części", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Pokaż dostawców", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Pokaż producentów", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Pokaż przycisk producentów na ekranie głównym", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Pokaż klientów", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Pokaż przycisk klientów na ekranie głównym", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Przesyłanie zdjęcia nie powiodło się", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Obraz przesłany", - "@imageUploadSuccess": {}, - "inactive": "Nieaktywny", - "@inactive": {}, - "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", - "@inactiveDetail": {}, - "includeSubcategories": "Zawieraj podkategorie", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Wyświetl części z podkategorii w widoku listy", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Zawieraj sublokacje", - "@includeSublocations": {}, - "includeSublocationsDetail": "Wyświetl części z sublokacji w widoku listy", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Niekompletne szczegóły profilu", - "@incompleteDetails": {}, - "internalPartNumber": "Wewnętrzny numer części", - "@internalPartNumber": {}, - "info": "Info", - "@info": {}, - "inProduction": "W produkcji", - "@inProduction": {}, - "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", - "@inProductionDetail": {}, - "invalidHost": "Nieprawidłowa nazwa hosta", - "@invalidHost": {}, - "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", - "@invalidHostDetails": {}, - "invalidPart": "Nieprawidłowa część", - "@invalidPart": {}, - "invalidPartCategory": "Nieprawidłowa kategoria części", - "@invalidPartCategory": {}, - "invalidStockLocation": "Nieprawidłowa lokacja magazynowa", - "@invalidStockLocation": {}, - "invalidStockItem": "Nieprawidłowa część magazynowa", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Nieprawidłowy login lub hasło", - "@invalidUsernamePassword": {}, - "issueDate": "Data Wystawienia", - "@issueDate": {}, - "itemInLocation": "Część jest już w lokacji", - "@itemInLocation": {}, - "keywords": "Słowa kluczowe", - "@keywords": {}, - "lastStocktake": "Ostatnia inwentaryzacja", - "@lastStocktake": {}, - "lastUpdated": "Ostatnia aktualizacja", - "@lastUpdated": {}, - "lineItem": "Pozycja", - "@lineItem": {}, - "lineItems": "Pozycje", - "@lineItems": {}, - "locationCreate": "Nowa Lokalizacja", - "@locationCreate": {}, - "locationCreateDetail": "Utwórz nową pozycję magazynową", - "@locationCreateDetail": {}, - "locationNotSet": "Nie określono lokacji", - "@locationNotSet": {}, - "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Zagubiono", - "@lost": {}, - "manufacturers": "Producenci", - "@manufacturers": {}, - "missingData": "Brakujące dane", - "@missingData": {}, - "name": "Nazwa", - "@name": {}, - "notConnected": "Nie połączony", - "@notConnected": {}, - "notes": "Notatki", - "@notes": { - "description": "Notes" - }, - "noResponse": "Brak odpowiedzi od serwera", - "@noResponse": {}, - "noResults": "Brak wyników", - "@noResults": {}, - "noSubcategories": "Brak podkategorii", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Brak dostępnych podkategorii", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Błędny numer", - "@numberInvalid": {}, - "onOrder": "W Zamówieniu", - "@onOrder": {}, - "onOrderDetails": "Pozycje obecnie w zamówieniu", - "@onOrderDetails": {}, - "packaging": "Opakowanie", - "@packaging": {}, - "packageName": "Nazwa pakietu", - "@packageName": {}, - "parent": "Nadrzędny", - "@parent": {}, - "parentCategory": "Kategoria nadrzędna", - "@parentCategory": {}, - "parentLocation": "Lokalizacja Nadrzędna", - "@parentLocation": {}, - "part": "Część", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Nowy Komponent", - "@partCreate": {}, - "partCreateDetail": "Utwórz nowy komponent w tej kategorii", - "@partCreateDetail": {}, - "partEdited": "Część zaktualizowana", - "@partEdited": {}, - "parts": "Części", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Brak części", - "@partsNone": {}, - "partNoResults": "Brak komponentów pasujących do zapytania", - "@partNoResults": {}, - "partsStarred": "Obserwowane części", - "@partsStarred": {}, - "partsStarredNone": "Brak części oznaczonych gwiazdką", - "@partsStarredNone": {}, - "partSuppliers": "Dostawcy Części", - "@partSuppliers": {}, - "partCategory": "Kategoria części", - "@partCategory": {}, - "partCategoryTopLevel": "Kategoria części najwyższego poziomu", - "@partCategoryTopLevel": {}, - "partCategories": "Kategorie części", - "@partCategories": {}, - "partDetails": "Szczegóły części", - "@partDetails": {}, - "partNotes": "Notatki do części", - "@partNotes": {}, - "partStock": "Zapasy cześci", - "@partStock": { - "description": "part stock" - }, - "password": "Hasło", - "@password": {}, - "passwordEmpty": "Hasło nie może być puste", - "@passwordEmpty": {}, - "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", - "@permissionAccountDenied": {}, - "permissionRequired": "Wymagane uprawnienia", - "@permissionRequired": {}, - "printLabel": "Drukuj etykietę", - "@printLabel": {}, - "printLabelFailure": "Drukowanie etykiet nie powiodło się", - "@printLabelFailure": {}, - "printLabelSuccess": "Etykieta wysłana do drukarki", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Dodaj profil serwera", - "@profileAdd": {}, - "profileConnect": "Połącz się z serwerem", - "@profileConnect": {}, - "profileEdit": "Edytuj profil serwera", - "@profileEdit": {}, - "profileDelete": "Usuń profil serwera", - "@profileDelete": {}, - "profileName": "Nazwa Profilu", - "@profileName": {}, - "profileNone": "Brak dostępnych profili", - "@profileNone": {}, - "profileNotSelected": "Nie wybrano profilu", - "@profileNotSelected": {}, - "profileSelect": "Wybierz serwer InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", - "@profileTapToCreate": {}, - "purchaseOrder": "Zlecenie Zakupu", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Zlecenia zakupu", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Cena Zakupu", - "@purchasePrice": {}, - "quantity": "Ilość", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Ilość jest pusta", - "@quantityEmpty": {}, - "quantityInvalid": "Ilość jest nieprawidłowa", - "@quantityInvalid": {}, - "quantityPositive": "Ilość musi być dodatnia", - "@quantityPositive": {}, - "queryNoResults": "Nie znaleziono wyników dla zapytania", - "@queryNoResults": {}, - "received": "Odebrane", - "@received": {}, - "receiveItem": "Przyjmij artykuły", - "@receiveItem": {}, - "receivedItem": "Przyjęta Pozycja Magazynowa", - "@receivedItem": {}, - "refresh": "Odśwież", - "@refresh": {}, - "refreshing": "Odświeżanie", - "@refreshing": {}, - "rejected": "Odrzucono", - "@rejected": {}, - "releaseNotes": "Lista zmian", - "@releaseNotes": {}, - "remove": "Usuń", - "@remove": { - "description": "remove" - }, - "removeStock": "Usuń stan", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Zgłoś błąd", - "@reportBug": {}, - "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", - "@reportBugDescription": {}, - "results": "Wyniki", - "@results": {}, - "request": "Żądanie", - "@request": {}, - "requestingData": "Żądanie danych", - "@requestingData": {}, - "required": "Wymagane", - "@required": { - "description": "This field is required" - }, - "response400": "Błędne żądanie", - "@response400": {}, - "response401": "Nieautoryzowany", - "@response401": {}, - "response403": "Odmowa dostępu", - "@response403": {}, - "response404": "Nie znaleziono", - "@response404": {}, - "response405": "Metoda niedozwolona", - "@response405": {}, - "response429": "Zbyt wiele żądań", - "@response429": {}, - "response500": "Wewnętrzny błąd serwera", - "@response500": {}, - "response501": "Nie zaimplementowano", - "@response501": {}, - "response502": "Zła brama", - "@response502": {}, - "response503": "Usługa niedostępna", - "@response503": {}, - "response504": "Przekroczono limit czasu", - "@response504": {}, - "response505": "Wersja HTTP nie obsługiwana", - "@response505": {}, - "responseData": "Dane odpowiedzi", - "@responseData": {}, - "responseInvalid": "Nieprawidłowy kod odpowiedzi", - "@responseInvalid": {}, - "responseUnknown": "Nieznana odpowiedź", - "@responseUnknown": {}, - "result": "Wynik", - "@result": { - "description": "" - }, - "returned": "Zwrócono", - "@returned": {}, - "salesOrders": "Zlecenia Sprzedaży", - "@salesOrders": {}, - "save": "Zapisz", - "@save": { - "description": "Save" - }, - "scanBarcode": "Skanuj kod kreskowy", - "@scanBarcode": {}, - "scanIntoLocation": "Skanuj do lokacji", - "@scanIntoLocation": {}, - "search": "Szukaj", - "@search": { - "description": "search" - }, - "searchLocation": "Wyszukaj lokalizację", - "@searchLocation": {}, - "searchParts": "Szukaj części", - "@searchParts": {}, - "searchStock": "Szukaj zapasów", - "@searchStock": {}, - "select": "Wybierz", - "@select": {}, - "selectFile": "Wybierz Plik", - "@selectFile": {}, - "selectImage": "Wybierz obraz", - "@selectImage": {}, - "selectLocation": "Wybierz lokację", - "@selectLocation": {}, - "send": "Wyślij", - "@send": {}, - "serialNumber": "Numer seryjny", - "@serialNumber": {}, - "server": "Serwer", - "@server": {}, - "serverAddress": "Adres serwera", - "@serverAddress": {}, - "serverApiRequired": "Wymagana wersja API", - "@serverApiRequired": {}, - "serverApiVersion": "Wersja API serwera", - "@serverApiVersion": {}, - "serverAuthenticationError": "Błąd uwierzytelniania", - "@serverAuthenticationError": {}, - "serverCertificateError": "Błąd certyfikatu", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Certyfikat serwera HTTPS jest nieprawidłowy", - "@serverCertificateInvalid": {}, - "serverConnected": "Połączony z serwerem", - "@serverConnected": {}, - "serverConnecting": "Łączenie z serwerem", - "@serverConnecting": {}, - "serverCouldNotConnect": "Nie można połączyć się z serwerem", - "@serverCouldNotConnect": {}, - "serverEmpty": "Serwer nie może być pusty", - "@serverEmpty": {}, - "serverError": "Błąd serwera", - "@serverError": {}, - "serverDetails": "Szczegóły serwera", - "@serverDetails": {}, - "serverMissingData": "Odpowiedź serwera nie ma wymaganych pól", - "@serverMissingData": {}, - "serverOld": "Stara wersja serwera", - "@serverOld": {}, - "serverSettings": "Ustawienia Serwera", - "@serverSettings": {}, - "serverStart": "Serwer musi zaczynać się od http[s]", - "@serverStart": {}, - "settings": "Ustawienia", - "@settings": {}, - "serverInstance": "Instancja serwera", - "@serverInstance": {}, - "serverNotConnected": "Serwer nie podłączony", - "@serverNotConnected": {}, - "sounds": "Dźwięki", - "@sounds": {}, - "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", - "@soundOnServerError": {}, - "status": "Status", - "@status": {}, - "statusCode": "Kod statusu", - "@statusCode": {}, - "stock": "Stan", - "@stock": { - "description": "stock" - }, - "stockItem": "Element magazynowy", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Elementy magazynowe", - "@stockItems": {}, - "stockItemCreate": "Nowa Pozycja Magazynowa", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Utwórz nową pozycję magazynową w tej lokalizacji", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Usuń przedmiot magazynowy", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Czy jesteś pewien, że chcesz usunąć ten przedmiot magazynowy?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Nie można usunąć przedmiotu magazynowego", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Przedmiot magazynowy usunięty", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historia zapasów", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Wyświetl historyczne informacje o śledzeniu stanów magazynowych", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Element magazynowy przeniesiony", - "@stockItemTransferred": {}, - "stockItemUpdated": "Zaktualizowano element magazynowy", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Brak dostępnych elementów", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notatki przedmiotu magazynowego", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Zaktualizowano element magazynowy", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Nie zaktualizowano elementu magazynowego", - "@stockItemUpdateFailure": {}, - "stockLocation": "Lokacja stanu", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Lokacje stanów", - "@stockLocations": {}, - "stockTopLevel": "Najwyższy poziom lokalizacji magazynu", - "@stockTopLevel": {}, - "strictHttps": "Ścisły HTTPS", - "@strictHttps": {}, - "strictHttpsDetails": "Wymuś ścisłe sprawdzanie certyfikatów HTTPS", - "@strictHttpsDetails": {}, - "subcategory": "Podkategoria", - "@subcategory": {}, - "subcategories": "Podkategorie", - "@subcategories": {}, - "sublocation": "Sublokacja", - "@sublocation": {}, - "sublocations": "Subblokacje", - "@sublocations": {}, - "sublocationNone": "Brak subblokacji", - "@sublocationNone": {}, - "sublocationNoneDetail": "Brak dostępnych podlokalizacji", - "@sublocationNoneDetail": {}, - "submitFeedback": "Prześlij opinię", - "@submitFeedback": {}, - "suppliedParts": "Dostarczone Części", - "@suppliedParts": {}, - "supplier": "Dostawca", - "@supplier": {}, - "suppliers": "Dostawcy", - "@suppliers": {}, - "supplierReference": "Identyfikator Dostawcy", - "@supplierReference": {}, - "takePicture": "Zrób zdjęcie", - "@takePicture": {}, - "targetDate": "Data Docelowa", - "@targetDate": {}, - "testName": "Nazwa testu", - "@testName": {}, - "testPassedOrFailed": "Test zaliczony lub nieudany", - "@testPassedOrFailed": {}, - "testsRequired": "Wymagane testy", - "@testsRequired": {}, - "testResults": "Wyniki testu", - "@testResults": { - "description": "" - }, - "testResultAdd": "Dodaj wynik testu", - "@testResultAdd": {}, - "testResultNone": "Brak wyników testu", - "@testResultNone": {}, - "testResultNoneDetail": "Brak dostępnych wyników testu", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Błąd przesyłania wyniku testu", - "@testResultUploadFail": {}, - "testResultUploadPass": "Wynik testu przesłany", - "@testResultUploadPass": {}, - "timeout": "Upłynął limit czasu", - "@timeout": { - "description": "" - }, - "tokenError": "Błąd tokenu", - "@tokenError": {}, - "tokenMissing": "Brakujący token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", - "@tokenMissingFromResponse": {}, - "transfer": "Przenieś", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Przenieś stan", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Przetłumacz", - "@translate": {}, - "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", - "@translateHelp": {}, - "units": "Jednostki", - "@units": {}, - "unknownResponse": "Nieznana odpowiedź", - "@unknownResponse": {}, - "upload": "Wyślij", - "@upload": {}, - "uploadFailed": "Błąd wysyłania pliku", - "@uploadFailed": {}, - "uploadSuccess": "Plik przesłany", - "@uploadSuccess": {}, - "usedIn": "Użyte w", - "@usedIn": {}, - "usedInDetails": "Złożenie, które wymagają tego komponentu", - "@usedInDetails": {}, - "username": "Nazwa użytkownika", - "@username": {}, - "usernameEmpty": "Nazwa użytkownika nie może być pusta", - "@usernameEmpty": {}, - "value": "Wartość", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Wartość nie może być pusta", - "@valueCannotBeEmpty": {}, - "valueRequired": "Wartość jest wymagana", - "@valueRequired": {}, - "version": "Wersja", - "@version": {}, - "viewSupplierPart": "Zobacz Dostawcę Części", - "@viewSupplierPart": {}, - "website": "Strona WWW", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/pt-BR/app_pt.arb b/lib/l10n/pt-BR/app_pt.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/pt-BR/app_pt.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/pt-PT/app_pt.arb b/lib/l10n/pt-PT/app_pt.arb deleted file mode 100644 index 4e4e56b..0000000 --- a/lib/l10n/pt-PT/app_pt.arb +++ /dev/null @@ -1,193 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Sobre", - "@about": {}, - "accountDetails": "Detalhes da Conta", - "@accountDetails": {}, - "actions": "Ações", - "@actions": { - "description": "" - }, - "actionsNone": "Nenhuma ação disponível", - "@actionsNone": {}, - "add": "Adicionar", - "@add": { - "description": "add" - }, - "addStock": "Adicionar ao estoque", - "@addStock": { - "description": "add stock" - }, - "address": "Endereço", - "@address": {}, - "appAbout": "Sobre o InvenTree", - "@appAbout": {}, - "appCredits": "Créditos adicionais do aplicativo", - "@appCredits": {}, - "appDetails": "Detalhes do App", - "@appDetails": {}, - "appReleaseNotes": "Exibir notas de versão do aplicativo", - "@appReleaseNotes": {}, - "appSettings": "Configurações do App", - "@appSettings": {}, - "appSettingsDetails": "Configurar os parâmetros do InvenTree", - "@appSettingsDetails": {}, - "attachments": "Anexos", - "@attachments": {}, - "attachImage": "Anexar Imagem", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Não foram encontrados quaisquer anexos", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Selecionar anexo", - "@attachmentSelect": {}, - "attention": "Aviso", - "@attention": {}, - "barcodeAssign": "Atribuir Código de Barras", - "@barcodeAssign": {}, - "barcodeAssigned": "Código de barras atribuído", - "@barcodeAssigned": {}, - "barcodeError": "Erro ao escanear código de barras", - "@barcodeError": {}, - "barcodeInUse": "Código de barras já atribuído", - "@barcodeInUse": {}, - "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Não corresponde a nenhum código de barras", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Código de barras não atribuído", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Escaneie para atribuir código de barras", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Escaneie itens de estoque no local", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Escanear Localização", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Escaneado no local", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanItem": "Escanear ítem", - "@barcodeScanItem": {}, - "barcodeTones": "Tons do código de barras", - "@barcodeTones": {}, - "barcodeUnassign": "Remover código de barras pre-designado", - "@barcodeUnassign": {}, - "barcodeUnknown": "Código de barras não reconhecido", - "@barcodeUnknown": {}, - "batchCode": "Código de lote", - "@batchCode": {}, - "billOfMaterials": "Lista de Materiais", - "@billOfMaterials": {}, - "bom": "Lista de Materiais", - "@bom": {}, - "build": "Compilar", - "@build": {}, - "building": "Compilando", - "@building": {}, - "cancel": "Cancelar", - "@cancel": { - "description": "Cancel" - }, - "category": "Categoria", - "@category": {}, - "categoryCreate": "Nova Categoria", - "@categoryCreate": {}, - "categoryCreateDetail": "Criar nova categoria de peças", - "@categoryCreateDetail": {}, - "categoryUpdated": "Categoria de peça atualizada", - "@categoryUpdated": {}, - "company": "Empresa", - "@company": {}, - "companyEdit": "Editar empresa", - "@companyEdit": {}, - "companyNoResults": "Nenhuma empresa corresponde a consulta", - "@companyNoResults": {}, - "companyUpdated": "Dados da empresa atualizados", - "@companyUpdated": {}, - "companies": "Empresas", - "@companies": {}, - "configureServer": "Configurar os parâmetros do servidor de email", - "@configureServer": {}, - "connectionRefused": "Conexão recusada", - "@connectionRefused": {}, - "count": "Contagem", - "@count": { - "description": "Count" - }, - "countStock": "Contagem de Estoque", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Créditos", - "@credits": {}, - "customers": "Clientes", - "@customers": {}, - "damaged": "Danificado", - "@damaged": {}, - "delete": "Excluir", - "@delete": {}, - "deletePart": "Excluir esta parte", - "@deletePart": {}, - "deletePartDetail": "Remover esta peça da base de dados", - "@deletePartDetail": {}, - "description": "Descrição", - "@description": {}, - "destroyed": "Destruído", - "@destroyed": {}, - "details": "Detalhes", - "@details": { - "description": "details" - }, - "documentation": "Documentação", - "@documentation": {}, - "downloading": "Baixando arquivo", - "@downloading": {}, - "downloadError": "Erro de download", - "@downloadError": {}, - "edit": "Editar", - "@edit": { - "description": "edit" - }, - "editCategory": "Editar categoria", - "@editCategory": {}, - "editLocation": "Editar Localização", - "@editLocation": {}, - "editNotes": "Editar notas", - "@editNotes": {}, - "editPart": "Editar a peça", - "@editPart": { - "description": "edit part" - }, - "editItem": "Editar Item do Estoque", - "@editItem": {}, - "enterPassword": "Digite a senha", - "@enterPassword": {}, - "enterUsername": "Inserir usuário", - "@enterUsername": {}, - "error": "Erro", - "@error": { - "description": "Error" - }, - "errorCreate": "Erro ao criar entrada de banco de dados", - "@errorCreate": {}, - "errorDelete": "Erro ao excluir entrada no banco de dados", - "@errorDelete": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "lastUpdated": "Ultima atualização", - "@lastUpdated": {}, - "lineItems": "Itens de linha", - "@lineItems": {} -} \ No newline at end of file diff --git a/lib/l10n/ru/app_ru.arb b/lib/l10n/ru/app_ru.arb deleted file mode 100644 index 7a7dbef..0000000 --- a/lib/l10n/ru/app_ru.arb +++ /dev/null @@ -1,263 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "ОК", - "@ok": { - "description": "OK" - }, - "about": "О проекте", - "@about": {}, - "accountDetails": "Данные аккаунта", - "@accountDetails": {}, - "actions": "Действия", - "@actions": { - "description": "" - }, - "actionsNone": "Действия недоступны", - "@actionsNone": {}, - "add": "Добавить", - "@add": { - "description": "add" - }, - "addStock": "Добавить запасы", - "@addStock": { - "description": "add stock" - }, - "address": "Адрес", - "@address": {}, - "appAbout": "О InvenTree", - "@appAbout": {}, - "appCredits": "Благодарности за помощь и поддержку", - "@appCredits": {}, - "appDetails": "Информация о приложении", - "@appDetails": {}, - "appReleaseNotes": "Показать заметки о выпуске приложения", - "@appReleaseNotes": {}, - "appSettings": "Настройки приложения", - "@appSettings": {}, - "companyNoResults": "Нет организаций, соответствующих запросу", - "@companyNoResults": {}, - "downloading": "Загрузка файла", - "@downloading": {}, - "downloadError": "Ошибка загрузки", - "@downloadError": {}, - "edit": "Изменить", - "@edit": { - "description": "edit" - }, - "editCategory": "Редактировать категорию", - "@editCategory": {}, - "editLocation": "Редактировать местонахождение", - "@editLocation": {}, - "editNotes": "Редактировать примечания", - "@editNotes": {}, - "editPart": "Ред. эту часть", - "@editPart": { - "description": "edit part" - }, - "editItem": "Отредактированный товар", - "@editItem": {}, - "enterPassword": "Введите пароль", - "@enterPassword": {}, - "enterUsername": "Введите имя пользователя", - "@enterUsername": {}, - "error": "Ошибка", - "@error": { - "description": "Error" - }, - "errorCreate": "Ошибка создания записи базы данных", - "@errorCreate": {}, - "errorDetails": "Подробнее об ошибке", - "@errorDetails": {}, - "errorFetch": "Ошибка при получении данных с сервера", - "@errorFetch": {}, - "feedback": "Обратная Связь", - "@feedback": {}, - "feedbackError": "Ошибка отправки отзыва", - "@feedbackError": {}, - "feedbackSuccess": "Отзыв отправлен", - "@feedbackSuccess": {}, - "formatException": "Формат исключения", - "@formatException": {}, - "formatExceptionJson": "Ошибка формата JSON", - "@formatExceptionJson": {}, - "formError": "Ошибка в форме", - "@formError": {}, - "history": "История", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "imageUploadFailure": "Не удалось загрузить изображение", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Изображение загружено", - "@imageUploadSuccess": {}, - "inactive": "Неактивный", - "@inactive": {}, - "inactiveDetail": "Эта часть помечена как неактивная", - "@inactiveDetail": {}, - "includeSubcategories": "Включить подкатегории", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Отображать подкатегории в виде списка", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Добавить доп. местоположения", - "@includeSublocations": {}, - "includeSublocationsDetail": "Отображать доп. местоположения в виде списка", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Неполные данные профиля", - "@incompleteDetails": {}, - "internalPartNumber": "Внутренний номер", - "@internalPartNumber": {}, - "info": "Информация", - "@info": {}, - "invalidHost": "Неверное имя хоста", - "@invalidHost": {}, - "invalidHostDetails": "Недопустимый пароль", - "@invalidHostDetails": {}, - "invalidPart": "Недопустимый элемент", - "@invalidPart": {}, - "invalidPartCategory": "Неверная категория элемента", - "@invalidPartCategory": {}, - "invalidStockLocation": "Неверное расположение склада", - "@invalidStockLocation": {}, - "invalidStockItem": "Недопустимый товарный пункт", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", - "@invalidUsernamePassword": {}, - "issueDate": "Дата проблемы", - "@issueDate": {}, - "itemInLocation": "Элемент уже находится на месте", - "@itemInLocation": {}, - "keywords": "Ключевые слова", - "@keywords": {}, - "lastStocktake": "Последняя инвентаризация", - "@lastStocktake": {}, - "lastUpdated": "Последние обновлённые", - "@lastUpdated": {}, - "lineItem": "Элемент строки", - "@lineItem": {}, - "lineItems": "Элементы строки", - "@lineItems": {}, - "locationCreate": "Новое местоположение", - "@locationCreate": {}, - "locationCreateDetail": "Создать новое расположение склада", - "@locationCreateDetail": {}, - "locationNotSet": "Не указано месторасположение", - "@locationNotSet": {}, - "link": "Ссылка", - "@link": {}, - "lost": "Потерян", - "@lost": {}, - "manufacturers": "Производители", - "@manufacturers": {}, - "missingData": "Отсутствующие данные", - "@missingData": {}, - "name": "Название", - "@name": {}, - "notConnected": "Соединение не установлено", - "@notConnected": {}, - "notes": "Заметки", - "@notes": { - "description": "Notes" - }, - "noResponse": "Нет ответа от сервера", - "@noResponse": {}, - "noResults": "Нет результатов", - "@noResults": {}, - "noSubcategories": "Нет подкатегории", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Нет доступных подкатегорий", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Неправильный номер", - "@numberInvalid": {}, - "onOrder": "Под заказ", - "@onOrder": {}, - "onOrderDetails": "Заказаные элементы", - "@onOrderDetails": {}, - "packaging": "Упаковка", - "@packaging": {}, - "packageName": "Название упаковки", - "@packageName": {}, - "parent": "Родитель", - "@parent": {}, - "parentCategory": "Родительская категория", - "@parentCategory": {}, - "parentLocation": "Родительское местоположение", - "@parentLocation": {}, - "part": "Компонент", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Новый компонент", - "@partCreate": {}, - "partCreateDetail": "Создать компонент в данной категории", - "@partCreateDetail": {}, - "parts": "Номенклатура", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Нет компонентов", - "@partsNone": {}, - "partNoResults": "Нет компонентов, соответствующих запросу", - "@partNoResults": {}, - "response405": "405 Метод не разрешен", - "@response405": {}, - "response429": "Слишком много запросов", - "@response429": {}, - "response500": "Внутренняя ошибка сервера", - "@response500": {}, - "response501": "Не реализовано", - "@response501": {}, - "response502": "Недопустимый шлюз", - "@response502": {}, - "response503": "Сервис недоступен", - "@response503": {}, - "response504": "504: тайм-аут шлюза", - "@response504": {}, - "response505": "505: версия не поддерживается", - "@response505": {}, - "responseData": "Информация об ответе", - "@responseData": {}, - "responseInvalid": "Неверный код ответа", - "@responseInvalid": {}, - "responseUnknown": "Неизвестный ответ", - "@responseUnknown": {}, - "result": "Результат", - "@result": { - "description": "" - }, - "returned": "Возвращено", - "@returned": {}, - "salesOrders": "Заказы на продажу", - "@salesOrders": {}, - "save": "Сохранить", - "@save": { - "description": "Save" - }, - "scanBarcode": "Сканировать штрихкод", - "@scanBarcode": {}, - "scanIntoLocation": "Сканировать в местоположение", - "@scanIntoLocation": {}, - "search": "Поиск", - "@search": { - "description": "search" - }, - "searchLocation": "Искать по месту", - "@searchLocation": {}, - "searchParts": "Найти номенклатуру", - "@searchParts": {}, - "searchStock": "Поиск в наличии", - "@searchStock": {}, - "select": "Выбрать", - "@select": {}, - "selectFile": "Выбрать файл", - "@selectFile": {}, - "selectImage": "Выбрать изображение", - "@selectImage": {}, - "website": "Сайт", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/sv-SE/app_sv.arb b/lib/l10n/sv-SE/app_sv.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/sv-SE/app_sv.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/th/app_th.arb b/lib/l10n/th/app_th.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/th/app_th.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/tr/app_tr.arb b/lib/l10n/tr/app_tr.arb deleted file mode 100644 index e069fbf..0000000 --- a/lib/l10n/tr/app_tr.arb +++ /dev/null @@ -1,735 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "TAMAM", - "@ok": { - "description": "OK" - }, - "about": "Hakkında", - "@about": {}, - "accountDetails": "Hesap Detayları", - "@accountDetails": {}, - "actions": "Eylemler", - "@actions": { - "description": "" - }, - "actionsNone": "Kullanılabilir eylem yok", - "@actionsNone": {}, - "add": "Ekle", - "@add": { - "description": "add" - }, - "addStock": "Stok ekle", - "@addStock": { - "description": "add stock" - }, - "address": "Adres", - "@address": {}, - "appAbout": "InvenTree Hakkında", - "@appAbout": {}, - "appCredits": "Uygulama kredisi ekle", - "@appCredits": {}, - "appDetails": "Uygulama Detayları", - "@appDetails": {}, - "appReleaseNotes": "Uygulama yayınlama notları", - "@appReleaseNotes": {}, - "appSettings": "Uygulama Ayarları", - "@appSettings": {}, - "appSettingsDetails": "Uygulama ayarlarından yapılandır", - "@appSettingsDetails": {}, - "attachments": "Ekler", - "@attachments": {}, - "attachImage": "Resim ekle", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Hiçbir ek bulunamadı", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Ek seçin", - "@attachmentSelect": {}, - "attention": "Dikkat", - "@attention": {}, - "barcodeAssign": "Barkod Ata", - "@barcodeAssign": {}, - "barcodeAssigned": "Barkod atandı", - "@barcodeAssigned": {}, - "barcodeError": "Barkod tarama hatası", - "@barcodeError": {}, - "barcodeInUse": "Barkod zaten kullanımda", - "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash verisi alınamadı", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Barkod için eşleşme yok", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barkod atanmış değil", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Atanmış barkodu tara", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Bir Iventree barkodu tara", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Stok öğelerini konum içine tara", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Stok konumu tara", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Konuma tarandı", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Madde taranmış değil", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Stok öğesi tara", - "@barcodeScanItem": {}, - "barcodeTones": "Barkod Tonları", - "@barcodeTones": {}, - "barcodeUnassign": "Atanmamış barkod", - "@barcodeUnassign": {}, - "barcodeUnknown": "Barkod tanınmadı", - "@barcodeUnknown": {}, - "batchCode": "Grup kodu", - "@batchCode": {}, - "billOfMaterials": "Fatura materyalleri", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Oluştur", - "@build": {}, - "building": "Oluşturma", - "@building": {}, - "cancel": "İptal", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategori", - "@category": {}, - "categoryCreate": "Yeni Kategori", - "@categoryCreate": {}, - "categoryCreateDetail": "Yeni parça kategorisi oluştur", - "@categoryCreateDetail": {}, - "categoryUpdated": "Parça Kategorisi güncellendi", - "@categoryUpdated": {}, - "company": "Şirket", - "@company": {}, - "companyEdit": "Şirketi Düzenle", - "@companyEdit": {}, - "companyNoResults": "Sorguyla eşleşen şirket yok", - "@companyNoResults": {}, - "companyUpdated": "Firma bilgileri güncellendi", - "@companyUpdated": {}, - "companies": "Şirketler", - "@companies": {}, - "configureServer": "Sunucu ayarlarınızı yapılandırın", - "@configureServer": {}, - "connectionRefused": "Bağlantı reddedildi", - "@connectionRefused": {}, - "count": "Sayım", - "@count": { - "description": "Count" - }, - "countStock": "Stok sayımı", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Katkıda Bulunanlar", - "@credits": {}, - "customers": "Müşteriler", - "@customers": {}, - "damaged": "Hasarlı", - "@damaged": {}, - "delete": "Sil", - "@delete": {}, - "deletePart": "Parça Sil", - "@deletePart": {}, - "deletePartDetail": "Bu parçayı veritabanından kaldır", - "@deletePartDetail": {}, - "description": "Açıklama", - "@description": {}, - "destroyed": "Yok edildi", - "@destroyed": {}, - "details": "Detaylar", - "@details": { - "description": "details" - }, - "documentation": "Dökümantasyon", - "@documentation": {}, - "downloading": "Dosya indiriliyor", - "@downloading": {}, - "downloadError": "İndirme Hatası", - "@downloadError": {}, - "edit": "Düzenle", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategoriyi düzenle", - "@editCategory": {}, - "editLocation": "Konumu Düzenle", - "@editLocation": {}, - "editNotes": "Notları Düzenle", - "@editNotes": {}, - "editPart": "Parçayı Düzenle", - "@editPart": { - "description": "edit part" - }, - "editItem": "Parçayı Düzenle", - "@editItem": {}, - "enterPassword": "Şifrenizi girin", - "@enterPassword": {}, - "enterUsername": "Kullanıcı adını girin", - "@enterUsername": {}, - "error": "Hata", - "@error": { - "description": "Error" - }, - "errorCreate": "Veritabanı girdi oluşturma hatası", - "@errorCreate": {}, - "errorDelete": "Veritabanı girdisini silerken hata", - "@errorDelete": {}, - "errorDetails": "Hata Ayrıntıları", - "@errorDetails": {}, - "errorFetch": "Sunucudan veri alınırken hata oluştu", - "@errorFetch": {}, - "errorReporting": "Hata Raporlama", - "@errorReporting": {}, - "errorReportUpload": "Hata raporu yükle", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Anonim olarak hata ve log yükle", - "@errorReportUploadDetails": {}, - "feedback": "Geri Bildirim", - "@feedback": {}, - "feedbackError": "Geribildirim gönderme hatası", - "@feedbackError": {}, - "feedbackSuccess": "Geri bildirim gönderildi", - "@feedbackSuccess": {}, - "formatException": "Biçim İstisnası", - "@formatException": {}, - "formatExceptionJson": "JSON veri format istisnası", - "@formatExceptionJson": {}, - "formError": "Form hatası", - "@formError": {}, - "history": "Geçmiş", - "@history": { - "description": "history" - }, - "homeScreen": "Ana Ekran", - "@homeScreen": {}, - "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", - "@homeScreenSettings": {}, - "homeShowPo": "Satın Alma Siparişlerini Göster", - "@homeShowPo": {}, - "homeShowSubscribed": "Parça bildirimlerine abone ol", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Tedarikçileri Göster", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Üreticileri Göster", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Tedarikçi butonunu ana ekranda göster", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Müşterileri Göster", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Fotoğraf yükleme başarısız", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Resim yüklendi", - "@imageUploadSuccess": {}, - "inactive": "Pasif", - "@inactive": {}, - "inactiveDetail": "Bu parça pasif olarak işaretlendi", - "@inactiveDetail": {}, - "includeSubcategories": "Alt kategorileri dahil et", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Alt kategori parçalarını liste görünümünde göster", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Alt konumları dahil et", - "@includeSublocations": {}, - "includeSublocationsDetail": "Alt konum parçalarını liste görünümünde göster", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Tamamlanmamış profil detayları", - "@incompleteDetails": {}, - "internalPartNumber": "İç Parça Numarası", - "@internalPartNumber": {}, - "info": "Bilgi", - "@info": {}, - "inProduction": "Yapım Aşamasında", - "@inProduction": {}, - "inProductionDetail": "Bu ürün üretim aşamasında", - "@inProductionDetail": {}, - "invalidHost": "Geçersiz alan adı", - "@invalidHost": {}, - "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", - "@invalidHostDetails": {}, - "invalidPart": "Geçersiz Parça", - "@invalidPart": {}, - "invalidPartCategory": "Geçersiz Parça Kategorisi", - "@invalidPartCategory": {}, - "invalidStockLocation": "Geçersiz Stok Konumu", - "@invalidStockLocation": {}, - "invalidStockItem": "Geçersiz Stok Parçası", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", - "@invalidUsernamePassword": {}, - "issueDate": "Sorun Tarihi", - "@issueDate": {}, - "itemInLocation": "Parça zaten konumda", - "@itemInLocation": {}, - "keywords": "Anahtar kelimeler", - "@keywords": {}, - "lastStocktake": "Son stok tutma", - "@lastStocktake": {}, - "lastUpdated": "Son güncelleme", - "@lastUpdated": {}, - "lineItem": "Parça Sırası", - "@lineItem": {}, - "lineItems": "Parçalar Sırası", - "@lineItems": {}, - "locationCreate": "Yeni Konum", - "@locationCreate": {}, - "locationCreateDetail": "Yeni stok konumu oluştur", - "@locationCreateDetail": {}, - "locationNotSet": "Belirtilmiş konum yok", - "@locationNotSet": {}, - "locationUpdated": "Stok lokasyonu güncellendi", - "@locationUpdated": {}, - "link": "Bağlantı", - "@link": {}, - "lost": "Kayıp", - "@lost": {}, - "manufacturers": "Üreticiler", - "@manufacturers": {}, - "missingData": "Eksik Veri", - "@missingData": {}, - "name": "Adı", - "@name": {}, - "notConnected": "Bağlı değil", - "@notConnected": {}, - "notes": "Notlar", - "@notes": { - "description": "Notes" - }, - "noResponse": "Sunucudan yanıt yok", - "@noResponse": {}, - "noResults": "Sonuç Yok", - "@noResults": {}, - "noSubcategories": "Alt kategori yok", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Uygun alt kategori yok", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Geçersiz numara", - "@numberInvalid": {}, - "onOrder": "Siparişte", - "@onOrder": {}, - "onOrderDetails": "Parça şuan siparişte", - "@onOrderDetails": {}, - "packaging": "Paketleme", - "@packaging": {}, - "packageName": "Paket İsmi", - "@packageName": {}, - "parent": "Üst", - "@parent": {}, - "parentCategory": "Üst Kategori", - "@parentCategory": {}, - "parentLocation": "Bağlı lokasyon", - "@parentLocation": {}, - "part": "Parça", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Yeni Parça", - "@partCreate": {}, - "partCreateDetail": "Yeni parça kategorisi oluştur", - "@partCreateDetail": {}, - "partEdited": "Parça Güncellendi", - "@partEdited": {}, - "parts": "Parçalar", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Parça Yok", - "@partsNone": {}, - "partNoResults": "Sorguyla eşleşen parça yok", - "@partNoResults": {}, - "partsStarred": "Sürekli Gelen parçalar", - "@partsStarred": {}, - "partsStarredNone": "Yıldızlı parça yok", - "@partsStarredNone": {}, - "partSuppliers": "Parça Tedarikçileri", - "@partSuppliers": {}, - "partCategory": "Parça Kategorileri", - "@partCategory": {}, - "partCategoryTopLevel": "Üst seviye parça kategorisi", - "@partCategoryTopLevel": {}, - "partCategories": "Parça Kategorileri", - "@partCategories": {}, - "partDetails": "Parça detayları", - "@partDetails": {}, - "partNotes": "Parça notları", - "@partNotes": {}, - "partStock": "Parça stok", - "@partStock": { - "description": "part stock" - }, - "password": "Parola", - "@password": {}, - "passwordEmpty": "Parola boş bırakılamaz", - "@passwordEmpty": {}, - "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", - "@permissionAccountDenied": {}, - "permissionRequired": "İzin Gerekli", - "@permissionRequired": {}, - "printLabel": "Etiket Yazdır", - "@printLabel": {}, - "printLabelFailure": "Etiket yazdırılamadı", - "@printLabelFailure": {}, - "printLabelSuccess": "Etiket yazıcıya gönderildi", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Yeni Sunucu Profili Ekle", - "@profileAdd": {}, - "profileConnect": "Sunucuya bağlan", - "@profileConnect": {}, - "profileEdit": "Sunucu Profilini düzenle", - "@profileEdit": {}, - "profileDelete": "Sunucu profilini sil", - "@profileDelete": {}, - "profileName": "Profil Adı", - "@profileName": {}, - "profileNone": "Kullanılabiir profil yok", - "@profileNone": {}, - "profileNotSelected": "Profil seçilmedi", - "@profileNotSelected": {}, - "profileSelect": "InvenTree sunucusu seç", - "@profileSelect": {}, - "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", - "@profileTapToCreate": {}, - "purchaseOrder": "Satınalma Siparişi", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Satın Alma siparişini düzenle", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Satınalma Siparişleri", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Alış Fiyatı", - "@purchasePrice": {}, - "quantity": "Adet", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Adet boş", - "@quantityEmpty": {}, - "quantityInvalid": "Adet geçersiz", - "@quantityInvalid": {}, - "quantityPositive": "Adet pozitif bir sayı olmalı", - "@quantityPositive": {}, - "queryNoResults": "Sorgu için sonuç yok", - "@queryNoResults": {}, - "received": "Alınan", - "@received": {}, - "receiveItem": "Alınan Öğeler", - "@receiveItem": {}, - "receivedItem": "Alınan stok parçaları", - "@receivedItem": {}, - "refresh": "Yenile", - "@refresh": {}, - "refreshing": "Yenileniyor", - "@refreshing": {}, - "rejected": "Reddedildi", - "@rejected": {}, - "releaseNotes": "Sürüm notları", - "@releaseNotes": {}, - "remove": "Kaldır", - "@remove": { - "description": "remove" - }, - "removeStock": "Stok Kaldır", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Hata Bildir", - "@reportBug": {}, - "reportBugDescription": "Hata raporla ( github hesabı gerektirir)", - "@reportBugDescription": {}, - "results": "Sonuçlar", - "@results": {}, - "request": "Talep", - "@request": {}, - "requestingData": "Veri Talep Ediliyor", - "@requestingData": {}, - "required": "Gerekli", - "@required": { - "description": "This field is required" - }, - "response400": "Hatalı İstek", - "@response400": {}, - "response401": "Yetkisiz", - "@response401": {}, - "response403": "İzin Engellendi", - "@response403": {}, - "response404": "Kaynak bulunamadı", - "@response404": {}, - "response405": "İzin Verilmeyen Yöntem", - "@response405": {}, - "response429": "Çok Fazla İstek", - "@response429": {}, - "response500": "İç Sunucu Hatası", - "@response500": {}, - "response501": "Uygulanamadı", - "@response501": {}, - "response502": "Hatalı Ağ Geçidi", - "@response502": {}, - "response503": "Hizmet Kullanılamıyor", - "@response503": {}, - "response504": "Ağ Geçidi Zaman Aşımı", - "@response504": {}, - "response505": "HTTP Sürümü Desteklenmiyor", - "@response505": {}, - "responseData": "Yanıt verileri", - "@responseData": {}, - "responseInvalid": "Geçersiz yanıt kodu.", - "@responseInvalid": {}, - "responseUnknown": "Bilinmeyen yanıt", - "@responseUnknown": {}, - "result": "Sonuç", - "@result": { - "description": "" - }, - "returned": "Geri Dönen", - "@returned": {}, - "salesOrders": "Satış Siparişleri", - "@salesOrders": {}, - "save": "Kaydet", - "@save": { - "description": "Save" - }, - "scanBarcode": "Barkod Tara", - "@scanBarcode": {}, - "scanIntoLocation": "Konuma Tara", - "@scanIntoLocation": {}, - "search": "Ara", - "@search": { - "description": "search" - }, - "searchLocation": "Konum için Ara", - "@searchLocation": {}, - "searchParts": "Parçaları Ara", - "@searchParts": {}, - "searchStock": "Stok Ara", - "@searchStock": {}, - "select": "Seç", - "@select": {}, - "selectFile": "Dosya Seç", - "@selectFile": {}, - "selectImage": "Resim Seç", - "@selectImage": {}, - "selectLocation": "Bir yer seçin", - "@selectLocation": {}, - "send": "Gönder", - "@send": {}, - "serialNumber": "Seri Numara", - "@serialNumber": {}, - "server": "Sunucu", - "@server": {}, - "serverAddress": "Sunucu Adresi", - "@serverAddress": {}, - "serverApiRequired": "Gerekli API Sürümü", - "@serverApiRequired": {}, - "serverApiVersion": "Sunucu API Sürümü", - "@serverApiVersion": {}, - "serverAuthenticationError": "Doğrulama Hatası", - "@serverAuthenticationError": {}, - "serverCertificateError": "Sertifika Hatası", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Sunucunun sertifikası geçersiz", - "@serverCertificateInvalid": {}, - "serverConnected": "Sunucuya bağlanıldı", - "@serverConnected": {}, - "serverConnecting": "Sunucuya bağlanıyor", - "@serverConnecting": {}, - "serverCouldNotConnect": "Sunucuya bağlanılamadı", - "@serverCouldNotConnect": {}, - "serverEmpty": "Sunucu boş olamaz", - "@serverEmpty": {}, - "serverError": "Sunucu Hatası", - "@serverError": {}, - "serverDetails": "Sunucu Detayları", - "@serverDetails": {}, - "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", - "@serverMissingData": {}, - "serverOld": "Eski Sunucu Sürümü", - "@serverOld": {}, - "serverSettings": "Sunucu Ayarları", - "@serverSettings": {}, - "serverStart": "Sunucu http(s) ile başlamalı", - "@serverStart": {}, - "settings": "Ayarlar", - "@settings": {}, - "serverInstance": "Sunucu örneği", - "@serverInstance": {}, - "serverNotConnected": "Sunucu bağlı değil", - "@serverNotConnected": {}, - "sounds": "Sesler", - "@sounds": {}, - "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Sunucu hatasında sesli ton çal", - "@soundOnServerError": {}, - "status": "Durum", - "@status": {}, - "statusCode": "Durum Kodu", - "@statusCode": {}, - "stock": "Stok", - "@stock": { - "description": "stock" - }, - "stockItem": "Stok Kalemi", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Stok Kalemleri", - "@stockItems": {}, - "stockItemCreate": "Yeni Stok Kalemi", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Stok parçasını sil", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Stok parçası silinemedi", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stok parçası silindi", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stok Geçmişi", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Stok takip bilgisini göster", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stok kalemi transfer edildi", - "@stockItemTransferred": {}, - "stockItemUpdated": "Stok kalemi güncellendi", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Uygun stok kalemi yok", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stok Kalemi Notları", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stok kalemi güncellendi", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stok kalemi güncelleme hatası", - "@stockItemUpdateFailure": {}, - "stockLocation": "Stok Konumu", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Stok Konumları", - "@stockLocations": {}, - "stockTopLevel": "Üst seviye stok konumu", - "@stockTopLevel": {}, - "subcategory": "Alt kategori", - "@subcategory": {}, - "subcategories": "Alt kategoriler", - "@subcategories": {}, - "sublocation": "Alt konumlar", - "@sublocation": {}, - "sublocations": "Alt konumlar", - "@sublocations": {}, - "sublocationNone": "Alt konum yok", - "@sublocationNone": {}, - "sublocationNoneDetail": "Uygun alt kategori yok", - "@sublocationNoneDetail": {}, - "submitFeedback": "Geri Bildirim Gönder", - "@submitFeedback": {}, - "suppliedParts": "Sağlanan Parçalar", - "@suppliedParts": {}, - "supplier": "Tedarikçi", - "@supplier": {}, - "suppliers": "Tedarikçiler", - "@suppliers": {}, - "supplierReference": "Tedarikçi Referansı", - "@supplierReference": {}, - "takePicture": "Resim Çek", - "@takePicture": {}, - "targetDate": "Hedeflenen Tarih", - "@targetDate": {}, - "testName": "Test Adı", - "@testName": {}, - "testPassedOrFailed": "Test başarılı veya hatalı", - "@testPassedOrFailed": {}, - "testsRequired": "Gerekli Testler", - "@testsRequired": {}, - "testResults": "Test Sonuçları", - "@testResults": { - "description": "" - }, - "testResultAdd": "Test Sonucu Ekle", - "@testResultAdd": {}, - "testResultNone": "Test Sonucu Yok", - "@testResultNone": {}, - "testResultNoneDetail": "Uygun test sonucu yok", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Hatalı yüklenen test sonucu", - "@testResultUploadFail": {}, - "testResultUploadPass": "Test sonucu yüklendi", - "@testResultUploadPass": {}, - "timeout": "Zaman Aşımı", - "@timeout": { - "description": "" - }, - "tokenError": "Token Hatası", - "@tokenError": {}, - "tokenMissing": "Eksik Token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", - "@tokenMissingFromResponse": {}, - "transfer": "Aktarım", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Stok Aktar", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Çeviri", - "@translate": {}, - "translateHelp": "Çeviriye yardım et", - "@translateHelp": {}, - "units": "Birim", - "@units": {}, - "unknownResponse": "Bilinmeyen Yanıt", - "@unknownResponse": {}, - "upload": "Yükle", - "@upload": {}, - "uploadFailed": "Dosya yüklenemedi", - "@uploadFailed": {}, - "uploadSuccess": "Dosya yüklendi", - "@uploadSuccess": {}, - "usedIn": "Burada Kullanıldı", - "@usedIn": {}, - "usedInDetails": "Bu parçayı gerektiren montajlar", - "@usedInDetails": {}, - "username": "Kullanıcı Adı", - "@username": {}, - "usernameEmpty": "Kullanıcı adı boş bırakılamaz", - "@usernameEmpty": {}, - "value": "Değer", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Değer boş olamaz", - "@valueCannotBeEmpty": {}, - "valueRequired": "Değer gereklidir", - "@valueRequired": {}, - "version": "Sürüm", - "@version": {}, - "viewSupplierPart": "Tedarikçi Parçası Görüntüle", - "@viewSupplierPart": {}, - "website": "Web sitesi", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/vi/app_vi.arb b/lib/l10n/vi/app_vi.arb deleted file mode 100644 index 36d80aa..0000000 --- a/lib/l10n/vi/app_vi.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "en", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/zh-CN/app_zh.arb b/lib/l10n/zh-CN/app_zh.arb deleted file mode 100644 index 6a6c70d..0000000 --- a/lib/l10n/zh-CN/app_zh.arb +++ /dev/null @@ -1,341 +0,0 @@ -{ - "@@locale": "en", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "好", - "@ok": { - "description": "OK" - }, - "about": "关于", - "@about": {}, - "accountDetails": "账户详情", - "@accountDetails": {}, - "actions": "操作", - "@actions": { - "description": "" - }, - "add": "添加", - "@add": { - "description": "add" - }, - "addStock": "添加库存", - "@addStock": { - "description": "add stock" - }, - "address": "地址", - "@address": {}, - "appAbout": "关于 InventTree", - "@appAbout": {}, - "appDetails": "应用详情", - "@appDetails": {}, - "appSettings": "应用设置", - "@appSettings": {}, - "attention": "注意", - "@attention": {}, - "barcodeAssign": "分配条码", - "@barcodeAssign": {}, - "barcodeAssigned": "条码已分配", - "@barcodeAssigned": {}, - "barcodeError": "条形码扫描出错", - "@barcodeError": {}, - "barcodeInUse": "条码已经被分配", - "@barcodeInUse": {}, - "barcodeNoMatch": "无匹配条码", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "未分配条码", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "扫描以分配条码", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "扫描 InvenTree 条码", - "@barcodeScanGeneral": {}, - "barcodeScanLocation": "扫描库存地点", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "已扫描至位置", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanItem": "扫描库存项", - "@barcodeScanItem": {}, - "barcodeUnassign": "取消分配条码", - "@barcodeUnassign": {}, - "barcodeUnknown": "无法识别条码", - "@barcodeUnknown": {}, - "build": "生产", - "@build": {}, - "cancel": "取消", - "@cancel": { - "description": "Cancel" - }, - "category": "分类", - "@category": {}, - "categoryCreate": "新建分类", - "@categoryCreate": {}, - "categoryCreateDetail": "新建商品类别", - "@categoryCreateDetail": {}, - "company": "公司", - "@company": {}, - "companyEdit": "编辑公司信息", - "@companyEdit": {}, - "companies": "公司", - "@companies": {}, - "connectionRefused": "连接被拒绝", - "@connectionRefused": {}, - "count": "数量", - "@count": { - "description": "Count" - }, - "countStock": "库存数量", - "@countStock": { - "description": "Count Stock" - }, - "credits": "致谢", - "@credits": {}, - "damaged": "破损", - "@damaged": {}, - "delete": "删除", - "@delete": {}, - "description": "描述", - "@description": {}, - "destroyed": "销毁", - "@destroyed": {}, - "details": "详细信息", - "@details": { - "description": "details" - }, - "documentation": "文档", - "@documentation": {}, - "edit": "编辑", - "@edit": { - "description": "edit" - }, - "editCategory": "编辑分类", - "@editCategory": {}, - "editLocation": "编辑位置", - "@editLocation": {}, - "editPart": "编辑部件", - "@editPart": { - "description": "edit part" - }, - "error": "错误", - "@error": { - "description": "Error" - }, - "errorDetails": "c w错误详情", - "@errorDetails": {}, - "history": "历史", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "internalPartNumber": "内部部件号", - "@internalPartNumber": {}, - "info": "信息", - "@info": {}, - "invalidPart": "无效部件", - "@invalidPart": {}, - "invalidPartCategory": "无效部件分类", - "@invalidPartCategory": {}, - "invalidStockLocation": "无效库存位置", - "@invalidStockLocation": {}, - "invalidStockItem": "无效库存项", - "@invalidStockItem": {}, - "keywords": "关键词", - "@keywords": {}, - "link": "链接", - "@link": {}, - "lost": "丢失", - "@lost": {}, - "name": "名称", - "@name": {}, - "notConnected": "未连接", - "@notConnected": {}, - "notes": "注释", - "@notes": { - "description": "Notes" - }, - "noResponse": "服务器未响应", - "@noResponse": {}, - "parent": "父级", - "@parent": {}, - "parentCategory": "父类别", - "@parentCategory": {}, - "part": "部件", - "@part": { - "description": "Part (single)" - }, - "parts": "部件", - "@parts": { - "description": "Part (multiple)" - }, - "partCategory": "部件分类", - "@partCategory": {}, - "partCategories": "部件分类", - "@partCategories": {}, - "partDetails": "部件详情", - "@partDetails": {}, - "partNotes": "部件注释", - "@partNotes": {}, - "partStock": "部件库存", - "@partStock": { - "description": "part stock" - }, - "password": "密码", - "@password": {}, - "profile": "档案", - "@profile": {}, - "quantity": "数量", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "容量为空", - "@quantityEmpty": {}, - "quantityInvalid": "数量无效", - "@quantityInvalid": {}, - "quantityPositive": "数量必须大于0", - "@quantityPositive": {}, - "refresh": "刷新", - "@refresh": {}, - "refreshing": "正在刷新", - "@refreshing": {}, - "rejected": "已拒绝", - "@rejected": {}, - "releaseNotes": "更新日志", - "@releaseNotes": {}, - "remove": "移除", - "@remove": { - "description": "remove" - }, - "removeStock": "移除库存", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "反馈问题", - "@reportBug": {}, - "request": "请求", - "@request": {}, - "requestingData": "正在请求数据", - "@requestingData": {}, - "required": "必填", - "@required": { - "description": "This field is required" - }, - "responseInvalid": "无效响应码", - "@responseInvalid": {}, - "responseUnknown": "未知响应", - "@responseUnknown": {}, - "result": "结果", - "@result": { - "description": "" - }, - "save": "保存", - "@save": { - "description": "Save" - }, - "scanBarcode": "扫描条码", - "@scanBarcode": {}, - "scanIntoLocation": "已扫描至位置", - "@scanIntoLocation": {}, - "search": "搜索", - "@search": { - "description": "search" - }, - "searchParts": "搜索部件", - "@searchParts": {}, - "searchStock": "搜索库存", - "@searchStock": {}, - "select": "选择", - "@select": {}, - "send": "发送", - "@send": {}, - "serialNumber": "序列号", - "@serialNumber": {}, - "server": "服务器", - "@server": {}, - "serverAddress": "服务器地址", - "@serverAddress": {}, - "serverConnected": "已连接至服务器", - "@serverConnected": {}, - "serverError": "服务器错误", - "@serverError": {}, - "serverDetails": "服务器详情", - "@serverDetails": {}, - "serverOld": "过时的服务器版本", - "@serverOld": {}, - "serverSettings": "服务器设置", - "@serverSettings": {}, - "settings": "设置", - "@settings": {}, - "serverInstance": "服务器实例", - "@serverInstance": {}, - "serverNotConnected": "未连接至服务器", - "@serverNotConnected": {}, - "status": "状态", - "@status": {}, - "statusCode": "状态码", - "@statusCode": {}, - "stock": "库存", - "@stock": { - "description": "stock" - }, - "stockItem": "库存项", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "库存项", - "@stockItems": {}, - "stockItemNotes": "库存项注释", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "库存项已更新", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "库存项更新失败", - "@stockItemUpdateFailure": {}, - "stockLocation": "库存位置", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "库存位置", - "@stockLocations": {}, - "subcategory": "子类别", - "@subcategory": {}, - "subcategories": "子类别", - "@subcategories": {}, - "sublocation": "次级位置", - "@sublocation": {}, - "sublocations": "次级位置", - "@sublocations": {}, - "testResults": "测试结果", - "@testResults": { - "description": "" - }, - "timeout": "超时", - "@timeout": { - "description": "" - }, - "tokenError": "令牌错误", - "@tokenError": {}, - "tokenMissing": "缺少令牌", - "@tokenMissing": {}, - "transfer": "转移", - "@transfer": { - "description": "transfer" - }, - "transferStock": "转移库存", - "@transferStock": { - "description": "transfer stock" - }, - "unknownResponse": "未知响应", - "@unknownResponse": {}, - "upload": "上传", - "@upload": {}, - "username": "用户名", - "@username": {}, - "value": "值", - "@value": { - "description": "value" - }, - "version": "版本", - "@version": {}, - "website": "网站", - "@website": {} -} \ No newline at end of file From 9b9b2b52b606c67655a76590e0b7cb41bb413b33 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:42:35 +1000 Subject: [PATCH 012/746] Update crowdin.yml --- crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 204cc87..8278a32 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,3 @@ files: - source: /lib/l10n/app_en.arb - translation: /lib/l10n/app_%two_letters_code%.arb + translation: /lib/l10n/app_%locale_with_underscore%.arb From 2eb71194ba27b7ed7e6c9e96a64faed275057282 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:50:07 +1000 Subject: [PATCH 013/746] Update crowdin.yml --- crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 8278a32..15db0b5 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,3 @@ files: - source: /lib/l10n/app_en.arb - translation: /lib/l10n/app_%locale_with_underscore%.arb + translation: /lib/l10n/%locale_with_underscore*/app_%locale_with_underscore%.arb From a08e98493a500ac46ed5a930aedf8a07bb3fc20d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:52:35 +1000 Subject: [PATCH 014/746] Update crowdin.yml --- crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 15db0b5..d354ec1 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,3 @@ files: - source: /lib/l10n/app_en.arb - translation: /lib/l10n/%locale_with_underscore*/app_%locale_with_underscore%.arb + translation: /lib/l10n/%locale_with_underscore%/app_%locale_with_underscore%.arb From e99e70f89e380cae2f941dac741f0a2e6d5b1762 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:13 +1000 Subject: [PATCH 015/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/fr_FR/app_fr_FR.arb diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From fba412ddba1037dd91da3edc7e557bb89d61ac7e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:14 +1000 Subject: [PATCH 016/746] New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/pt_PT/app_pt_PT.arb diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 10597cc6ed1099bac3cacbd739b19e02b7c95996 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:14 +1000 Subject: [PATCH 017/746] New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_MX/app_es_MX.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/es_MX/app_es_MX.arb diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From a6f51ede670badfbb4db30bfbc4d562f9f9e4460 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:15 +1000 Subject: [PATCH 018/746] New translations app_en.arb (Persian) --- lib/l10n/fa_IR/app_fa_IR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/fa_IR/app_fa_IR.arb diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From c12bf5b269fa94a056bf2313c19c68bd72d1c6b2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:15 +1000 Subject: [PATCH 019/746] New translations app_en.arb (Indonesian) --- lib/l10n/id_ID/app_id_ID.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/id_ID/app_id_ID.arb diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 7bb6e872b986384bbf18839c4bf7a6070d1662e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:16 +1000 Subject: [PATCH 020/746] New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/pt_BR/app_pt_BR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/pt_BR/app_pt_BR.arb diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 7f12464419eba26b2525b607aa799a7ad4c6bcb2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:17 +1000 Subject: [PATCH 021/746] New translations app_en.arb (Vietnamese) --- lib/l10n/vi_VN/app_vi_VN.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/vi_VN/app_vi_VN.arb diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From ccfc5bc91b916b7f2099c42a40c49cf41e0efc46 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:17 +1000 Subject: [PATCH 022/746] New translations app_en.arb (Chinese Simplified) --- lib/l10n/zh_CN/app_zh_CN.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/zh_CN/app_zh_CN.arb diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From f0f604c586fedd93137d0c9cd82a4306ead9bd21 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:18 +1000 Subject: [PATCH 023/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/tr_TR/app_tr_TR.arb diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From cc897cea79425bacfa633cf725e655af56708ed2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:18 +1000 Subject: [PATCH 024/746] New translations app_en.arb (Swedish) --- lib/l10n/sv_SE/app_sv_SE.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/sv_SE/app_sv_SE.arb diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 78af823a8573dc486638cda18f1267dd86147f1b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:19 +1000 Subject: [PATCH 025/746] New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/ru_RU/app_ru_RU.arb diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 0a49632f11a916d9419f7137f415109ef35cc4d9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:20 +1000 Subject: [PATCH 026/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/pl_PL/app_pl_PL.arb diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From fa9957de0c7c1be7c3a0873f004ee45a8e0f783b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:20 +1000 Subject: [PATCH 027/746] New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/es_ES/app_es_ES.arb diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 591486cdd2a550526b215b661fae415aa9d7dc98 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:21 +1000 Subject: [PATCH 028/746] New translations app_en.arb (Norwegian) --- lib/l10n/no_NO/app_no_NO.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/no_NO/app_no_NO.arb diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 73f90458f5792d7e93b6a01f3fbf4814a6c3e685 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:21 +1000 Subject: [PATCH 029/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/nl_NL/app_nl_NL.arb diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 9429741e1248e4feef5596e567b9cac85b5d1da8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:22 +1000 Subject: [PATCH 030/746] New translations app_en.arb (Korean) --- lib/l10n/ko_KR/app_ko_KR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/ko_KR/app_ko_KR.arb diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From bae1a47521e8dd6a1888bb5f144a42693b41b31d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:23 +1000 Subject: [PATCH 031/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/ja_JP/app_ja_JP.arb diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From fadbb9769da5b5fb02f3c898d8840422e7f5debc Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:23 +1000 Subject: [PATCH 032/746] New translations app_en.arb (Italian) --- lib/l10n/it_IT/app_it_IT.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/it_IT/app_it_IT.arb diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 177750a4197335ea6b78a850d4f7253ca3dc2b7a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:24 +1000 Subject: [PATCH 033/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/hu_HU/app_hu_HU.arb diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 8bd9dd3dcf2120b38df416b7cb973611ba15fa41 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:25 +1000 Subject: [PATCH 034/746] New translations app_en.arb (Hebrew) --- lib/l10n/he_IL/app_he_IL.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/he_IL/app_he_IL.arb diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From fad347236e80149251d7afa28678f06dbe1f6448 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:25 +1000 Subject: [PATCH 035/746] New translations app_en.arb (Greek) --- lib/l10n/el_GR/app_el_GR.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/el_GR/app_el_GR.arb diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 0d8ed43e4749a21b932e222195492a84f3b771a2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:26 +1000 Subject: [PATCH 036/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/de_DE/app_de_DE.arb diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From c08b07b174e3461e5540404a48a7c2a96c8bc5dd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:26 +1000 Subject: [PATCH 037/746] New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/cs_CZ/app_cs_CZ.arb diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From a7b58f0ad6a508f78c03cd331cb5735b21eff258 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 11:54:27 +1000 Subject: [PATCH 038/746] New translations app_en.arb (Thai) --- lib/l10n/th_TH/app_th_TH.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/th_TH/app_th_TH.arb diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb new file mode 100644 index 0000000..36d80aa --- /dev/null +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "en", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From a6dafd25665c442ded629a7232e48a690825c0ed Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 12:02:22 +1000 Subject: [PATCH 039/746] Copy across previous translation flies --- lib/l10n/app_cs.arb | 5 - lib/l10n/app_de.arb | 745 ----------------------------------- lib/l10n/app_el.arb | 5 - lib/l10n/app_es.arb | 17 - lib/l10n/app_fa.arb | 5 - lib/l10n/app_fr.arb | 743 ---------------------------------- lib/l10n/app_he.arb | 5 - lib/l10n/app_hu.arb | 745 ----------------------------------- lib/l10n/app_id.arb | 5 - lib/l10n/app_it.arb | 505 ------------------------ lib/l10n/app_ja.arb | 682 -------------------------------- lib/l10n/app_ko.arb | 105 ----- lib/l10n/app_nl.arb | 5 - lib/l10n/app_no.arb | 5 - lib/l10n/app_pl.arb | 739 ---------------------------------- lib/l10n/app_pt.arb | 193 --------- lib/l10n/app_ru.arb | 263 ------------- lib/l10n/app_sv.arb | 5 - lib/l10n/app_th.arb | 5 - lib/l10n/app_tr.arb | 735 ---------------------------------- lib/l10n/app_vi.arb | 5 - lib/l10n/app_zh.arb | 341 ---------------- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 +- lib/l10n/de_DE/app_de_DE.arb | 744 +++++++++++++++++++++++++++++++++- lib/l10n/el_GR/app_el_GR.arb | 2 +- lib/l10n/es_ES/app_es_ES.arb | 16 +- lib/l10n/fa_IR/app_fa_IR.arb | 2 +- lib/l10n/fr_FR/app_fr_FR.arb | 742 +++++++++++++++++++++++++++++++++- lib/l10n/he_IL/app_he_IL.arb | 2 +- lib/l10n/hu_HU/app_hu_HU.arb | 744 +++++++++++++++++++++++++++++++++- lib/l10n/id_ID/app_id_ID.arb | 2 +- lib/l10n/it_IT/app_it_IT.arb | 504 +++++++++++++++++++++++- lib/l10n/ja_JP/app_ja_JP.arb | 681 +++++++++++++++++++++++++++++++- lib/l10n/ko_KR/app_ko_KR.arb | 104 ++++- lib/l10n/nl_NL/app_nl_NL.arb | 2 +- lib/l10n/no_NO/app_no_NO.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 738 +++++++++++++++++++++++++++++++++- lib/l10n/pt_PT/app_pt_PT.arb | 192 ++++++++- lib/l10n/ru_RU/app_ru_RU.arb | 262 +++++++++++- lib/l10n/sv_SE/app_sv_SE.arb | 2 +- lib/l10n/th_TH/app_th_TH.arb | 2 +- lib/l10n/tr_TR/app_tr_TR.arb | 734 +++++++++++++++++++++++++++++++++- lib/l10n/vi_VN/app_vi_VN.arb | 2 +- lib/l10n/zh_CN/app_zh_CN.arb | 340 +++++++++++++++- 44 files changed, 5787 insertions(+), 5897 deletions(-) delete mode 100644 lib/l10n/app_cs.arb delete mode 100644 lib/l10n/app_de.arb delete mode 100644 lib/l10n/app_el.arb delete mode 100644 lib/l10n/app_es.arb delete mode 100644 lib/l10n/app_fa.arb delete mode 100644 lib/l10n/app_fr.arb delete mode 100644 lib/l10n/app_he.arb delete mode 100644 lib/l10n/app_hu.arb delete mode 100644 lib/l10n/app_id.arb delete mode 100644 lib/l10n/app_it.arb delete mode 100644 lib/l10n/app_ja.arb delete mode 100644 lib/l10n/app_ko.arb delete mode 100644 lib/l10n/app_nl.arb delete mode 100644 lib/l10n/app_no.arb delete mode 100644 lib/l10n/app_pl.arb delete mode 100644 lib/l10n/app_pt.arb delete mode 100644 lib/l10n/app_ru.arb delete mode 100644 lib/l10n/app_sv.arb delete mode 100644 lib/l10n/app_th.arb delete mode 100644 lib/l10n/app_tr.arb delete mode 100644 lib/l10n/app_vi.arb delete mode 100644 lib/l10n/app_zh.arb diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb deleted file mode 100644 index 1aeae1d..0000000 --- a/lib/l10n/app_cs.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "cs", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb deleted file mode 100644 index ec3b2b6..0000000 --- a/lib/l10n/app_de.arb +++ /dev/null @@ -1,745 +0,0 @@ -{ - "@@locale": "de", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Über", - "@about": {}, - "accountDetails": "Konto Details", - "@accountDetails": {}, - "actions": "Aktionen", - "@actions": { - "description": "" - }, - "actionsNone": "Keine Aktionen verfügbar", - "@actionsNone": {}, - "add": "Hinzufügen", - "@add": { - "description": "add" - }, - "addStock": "Bestand hinzufügen", - "@addStock": { - "description": "add stock" - }, - "address": "Adresse", - "@address": {}, - "appAbout": "Über InvenTree", - "@appAbout": {}, - "appCredits": "Weitere App-Danksagungen", - "@appCredits": {}, - "appDetails": "App-Informationen", - "@appDetails": {}, - "appReleaseNotes": "App-Versionshinweise anzeigen", - "@appReleaseNotes": {}, - "appSettings": "App-Einstellungen", - "@appSettings": {}, - "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", - "@appSettingsDetails": {}, - "attachments": "Anhänge", - "@attachments": {}, - "attachImage": "Bild hinzufügen", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Keine Anhänge gefunden", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Anhang auswählen", - "@attachmentSelect": {}, - "attention": "Achtung", - "@attention": {}, - "availableStock": "Verfügbarer Lagerbestand", - "@availableStock": {}, - "barcodeAssign": "Barcode zuweisen", - "@barcodeAssign": {}, - "barcodeAssigned": "Barcode zugewiesen", - "@barcodeAssigned": {}, - "barcodeError": "Fehler beim Scannen des Barcodes", - "@barcodeError": {}, - "barcodeInUse": "Barcode wurde bereits zugewiesen", - "@barcodeInUse": {}, - "barcodeMissingHash": "Prüfsumme fehlt in Antwort", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Keine Übereinstimmung für den Barcode", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode nicht zugewiesen", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scannen um Barcode zuzuweisen", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Einen InvenTree Barcode scannen", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Artikel per Barcode-Scan zu Lagerort hinzufügen", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Lagerort scannen", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Artikel scannen", - "@barcodeScanItem": {}, - "barcodeTones": "Barcode-Ton", - "@barcodeTones": {}, - "barcodeUnassign": "Barcode entfernen", - "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode wurde nicht erkannt", - "@barcodeUnknown": {}, - "batchCode": "Losnummer", - "@batchCode": {}, - "billOfMaterials": "Stückliste", - "@billOfMaterials": {}, - "bom": "Stückliste", - "@bom": {}, - "build": "Bauauftrag", - "@build": {}, - "building": "Gebäude", - "@building": {}, - "cancel": "Abbrechen", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategorie", - "@category": {}, - "categoryCreate": "Neue Kategorie", - "@categoryCreate": {}, - "categoryCreateDetail": "Teile-Kategorie anlegen", - "@categoryCreateDetail": {}, - "categoryUpdated": "Kategorie aktualisiert", - "@categoryUpdated": {}, - "company": "Firma", - "@company": {}, - "companyEdit": "Firma bearbeiten", - "@companyEdit": {}, - "companyNoResults": "Keine Firmen entsprechen der Anfrage", - "@companyNoResults": {}, - "companyUpdated": "Firmendetails aktualisiert", - "@companyUpdated": {}, - "companies": "Firmen", - "@companies": {}, - "configureServer": "Server-Einstellungen konfigurieren", - "@configureServer": {}, - "connectionRefused": "Verbindung verweigert", - "@connectionRefused": {}, - "count": "Zählen", - "@count": { - "description": "Count" - }, - "countStock": "Bestand zählen", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Danksagungen", - "@credits": {}, - "customers": "Kunden", - "@customers": {}, - "damaged": "Beschädigt", - "@damaged": {}, - "delete": "Löschen", - "@delete": {}, - "deletePart": "Teil löschen", - "@deletePart": {}, - "deletePartDetail": "Dieses Teil aus der Datenbank löschen", - "@deletePartDetail": {}, - "description": "Beschreibung", - "@description": {}, - "destroyed": "Vernichtet", - "@destroyed": {}, - "details": "Details", - "@details": { - "description": "details" - }, - "documentation": "Dokumentation", - "@documentation": {}, - "downloading": "Datei wird heruntergeladen", - "@downloading": {}, - "downloadError": "Fehler beim Herunterladen", - "@downloadError": {}, - "edit": "Bearbeiten", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategorie bearbeiten", - "@editCategory": {}, - "editLocation": "Ort bearbeiten", - "@editLocation": {}, - "editNotes": "Notizen bearbeiten", - "@editNotes": {}, - "editPart": "Teil bearbeiten", - "@editPart": { - "description": "edit part" - }, - "editItem": "Artikel bearbeiten", - "@editItem": {}, - "enterPassword": "Passwort eingeben", - "@enterPassword": {}, - "enterUsername": "Benutzername eingeben", - "@enterUsername": {}, - "error": "Fehler", - "@error": { - "description": "Error" - }, - "errorCreate": "Fehler beim Erstellen des Datenbankeintrages", - "@errorCreate": {}, - "errorDelete": "Fehler beim Löschen von Datenbankeintrag", - "@errorDelete": {}, - "errorDetails": "Fehlerdetails", - "@errorDetails": {}, - "errorFetch": "Fehler beim Abrufen der Daten vom Server", - "@errorFetch": {}, - "errorReporting": "Fehlerberichterstattung", - "@errorReporting": {}, - "errorReportUpload": "Fehlerberichte hochladen", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", - "@errorReportUploadDetails": {}, - "feedback": "Feedback", - "@feedback": {}, - "feedbackError": "Fehler beim Senden des Feedbacks", - "@feedbackError": {}, - "feedbackSuccess": "Feedback gesendet", - "@feedbackSuccess": {}, - "formatException": "Formatfehler", - "@formatException": {}, - "formatExceptionJson": "Format-Fehler im JSON", - "@formatExceptionJson": {}, - "formError": "Formular-Fehler", - "@formError": {}, - "history": "Verlauf", - "@history": { - "description": "history" - }, - "homeScreen": "Startseite", - "@homeScreen": {}, - "homeScreenSettings": "Einstellungen für Startseite konfigurieren", - "@homeScreenSettings": {}, - "homeShowPo": "Bestellungen anzeigen", - "@homeShowPo": {}, - "homeShowSubscribed": "Abonnierte Teile", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Lieferanten anzeigen", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Hersteller anzeigen", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Hersteller auf Startseite anzeigen", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Kunden anzeigen", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Kunden auf Startseite anzeigen", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Das Bild konnte nicht hochgeladen werden", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Bild hochgeladen", - "@imageUploadSuccess": {}, - "inactive": "Inaktiv", - "@inactive": {}, - "inactiveDetail": "Teil als inaktiv gekennzeichnet", - "@inactiveDetail": {}, - "includeSubcategories": "Unter-Kategorien einschließen", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Teile aus Unter-Kategorien anzeigen", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Unter-Lagerorte einschließen", - "@includeSublocations": {}, - "includeSublocationsDetail": "Liste der Unter-Lagerorte anzeigen", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Profil unvollständig", - "@incompleteDetails": {}, - "internalPartNumber": "Interne Teilenummer", - "@internalPartNumber": {}, - "info": "Info", - "@info": {}, - "inProduction": "In Produktion", - "@inProduction": {}, - "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", - "@inProductionDetail": {}, - "invalidHost": "Ungültiger Hostname", - "@invalidHost": {}, - "invalidHostDetails": "Der angegebener Hostname ist ungültig", - "@invalidHostDetails": {}, - "invalidPart": "Ungültiges Teil", - "@invalidPart": {}, - "invalidPartCategory": "Ungültige Teil-Kategorie", - "@invalidPartCategory": {}, - "invalidStockLocation": "Ungültiger Lagerort", - "@invalidStockLocation": {}, - "invalidStockItem": "Ungültiger Artikel", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", - "@invalidUsernamePassword": {}, - "issueDate": "Ausstellungsdatum", - "@issueDate": {}, - "itemInLocation": "Artikel ist bereits in diesem Lagerort", - "@itemInLocation": {}, - "keywords": "Schlüsselwörter", - "@keywords": {}, - "lastStocktake": "Letzte Inventur", - "@lastStocktake": {}, - "lastUpdated": "Letzte Änderung", - "@lastUpdated": {}, - "lineItem": "Position", - "@lineItem": {}, - "lineItems": "Positionen", - "@lineItems": {}, - "locationCreate": "Neuer Lagerort", - "@locationCreate": {}, - "locationCreateDetail": "Neuen Lagerort erstellen", - "@locationCreateDetail": {}, - "locationNotSet": "Lagerort nicht angegeben", - "@locationNotSet": {}, - "locationUpdated": "Lagerort aktualisiert", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Verloren", - "@lost": {}, - "manufacturers": "Hersteller", - "@manufacturers": {}, - "missingData": "Fehlende Daten", - "@missingData": {}, - "name": "Name", - "@name": {}, - "notConnected": "Nicht verbunden", - "@notConnected": {}, - "notes": "Notizen", - "@notes": { - "description": "Notes" - }, - "noResponse": "Keine Antwort vom Server", - "@noResponse": {}, - "noResults": "Keine Ergebnisse", - "@noResults": {}, - "noSubcategories": "Keine Unter-Kategorien", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Keine gültige Zahl", - "@numberInvalid": {}, - "onOrder": "Bestellt", - "@onOrder": {}, - "onOrderDetails": "Artikel wurde bestellt", - "@onOrderDetails": {}, - "packaging": "Paket", - "@packaging": {}, - "packageName": "Paket-Name", - "@packageName": {}, - "parent": "Übergeordnetes", - "@parent": {}, - "parentCategory": "Übergeordnete Kategorie", - "@parentCategory": {}, - "parentLocation": "Übergeordneter Lagerort", - "@parentLocation": {}, - "part": "Teil", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Teil anlegen", - "@partCreate": {}, - "partCreateDetail": "Teil in dieser Kategorie anlegen", - "@partCreateDetail": {}, - "partEdited": "Teil aktualisiert", - "@partEdited": {}, - "parts": "Teile", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Keine Teile", - "@partsNone": {}, - "partNoResults": "Keine Teile entsprechen der Anfrage", - "@partNoResults": {}, - "partsStarred": "Abonnierte Teile", - "@partsStarred": {}, - "partsStarredNone": "Keine Teile abonniert", - "@partsStarredNone": {}, - "partSuppliers": "Teile-Lieferanten", - "@partSuppliers": {}, - "partCategory": "Teil-Kategorie", - "@partCategory": {}, - "partCategoryTopLevel": "Oberste Teile-Kategorie", - "@partCategoryTopLevel": {}, - "partCategories": "Teil-Kategorien", - "@partCategories": {}, - "partDetails": "Teil-Details", - "@partDetails": {}, - "partNotes": "Teil-Bemerkungen", - "@partNotes": {}, - "partStock": "Teilbestand", - "@partStock": { - "description": "part stock" - }, - "password": "Passwort", - "@password": {}, - "passwordEmpty": "Passwort darf nicht leer sein", - "@passwordEmpty": {}, - "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", - "@permissionAccountDenied": {}, - "permissionRequired": "Berechtigung erforderlich", - "@permissionRequired": {}, - "printLabel": "Label drucken", - "@printLabel": {}, - "printLabelFailure": "Labeldruck fehlgeschlagen", - "@printLabelFailure": {}, - "printLabelSuccess": "Label an den Drucker gesendet", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Server-Profil anlegen", - "@profileAdd": {}, - "profileConnect": "Mit Server verbinden", - "@profileConnect": {}, - "profileEdit": "Server-Profil bearbeiten", - "@profileEdit": {}, - "profileDelete": "Server-Profil löschen", - "@profileDelete": {}, - "profileName": "Profil-Name", - "@profileName": {}, - "profileNone": "Keine Profile angelegt", - "@profileNone": {}, - "profileNotSelected": "Kein Profil ausgewählt", - "@profileNotSelected": {}, - "profileSelect": "InvenTree-Server auswählen", - "@profileSelect": {}, - "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", - "@profileTapToCreate": {}, - "purchaseOrder": "Bestellung", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Bestellung bearbeiten", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Bestellungen", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Bestellung aktualisiert", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Einkaufspreis", - "@purchasePrice": {}, - "quantity": "Anzahl", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Menge ist leer", - "@quantityEmpty": {}, - "quantityInvalid": "Menge ist ungültig", - "@quantityInvalid": {}, - "quantityPositive": "Menge muss positiv sein", - "@quantityPositive": {}, - "queryNoResults": "Keine Ergebnisse für die Anfrage", - "@queryNoResults": {}, - "received": "Empfangen", - "@received": {}, - "receiveItem": "Artikel erhalten", - "@receiveItem": {}, - "receivedItem": "Artikel wurde erhalten", - "@receivedItem": {}, - "refresh": "Neu laden", - "@refresh": {}, - "refreshing": "Aktualisiere", - "@refreshing": {}, - "rejected": "Zurückgewiesen", - "@rejected": {}, - "releaseNotes": "Versionshinweise", - "@releaseNotes": {}, - "remove": "Entfernen", - "@remove": { - "description": "remove" - }, - "removeStock": "Bestand entfernen", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Fehler melden", - "@reportBug": {}, - "reportBugDescription": "Fehlerbericht senden (erfordert GitHub Konto)", - "@reportBugDescription": {}, - "results": "Ergebnisse", - "@results": {}, - "request": "Anfrage", - "@request": {}, - "requestingData": "Daten werden angefordert", - "@requestingData": {}, - "required": "Erforderlich", - "@required": { - "description": "This field is required" - }, - "response400": "Ungültige Anfrage", - "@response400": {}, - "response401": "Nicht autorisiert", - "@response401": {}, - "response403": "Zugriff verweigert", - "@response403": {}, - "response404": "Ressource nicht gefunden", - "@response404": {}, - "response405": "Methode nicht erlaubt", - "@response405": {}, - "response429": "Zu viele Anfragen", - "@response429": {}, - "response500": "Interner Serverfehler", - "@response500": {}, - "response501": "Nicht Implementiert", - "@response501": {}, - "response502": "Fehlerhaftes Gateway", - "@response502": {}, - "response503": "Dienst nicht verfügbar", - "@response503": {}, - "response504": "Gateway-Zeitüberschreitung", - "@response504": {}, - "response505": "HTTP-Version wird nicht unterstützt", - "@response505": {}, - "responseData": "Antwort-Daten", - "@responseData": {}, - "responseInvalid": "Ungültiger Antwort-Code", - "@responseInvalid": {}, - "responseUnknown": "Unbekannte Antwort", - "@responseUnknown": {}, - "result": "Ergebnis", - "@result": { - "description": "" - }, - "returned": "Retourniert", - "@returned": {}, - "salesOrders": "Kundenauftrag", - "@salesOrders": {}, - "save": "Speichern", - "@save": { - "description": "Save" - }, - "scanBarcode": "Barcode scannen", - "@scanBarcode": {}, - "scanIntoLocation": "In Lagerorten buchen", - "@scanIntoLocation": {}, - "search": "Suchen", - "@search": { - "description": "search" - }, - "searchLocation": "Lagerort suchen", - "@searchLocation": {}, - "searchParts": "Teile suchen", - "@searchParts": {}, - "searchStock": "Bestand durchsuchen", - "@searchStock": {}, - "select": "Auswählen", - "@select": {}, - "selectFile": "Datei auswählen", - "@selectFile": {}, - "selectImage": "Bild auswählen", - "@selectImage": {}, - "selectLocation": "Wähle einen Lagerort", - "@selectLocation": {}, - "send": "Senden", - "@send": {}, - "serialNumber": "Seriennummer", - "@serialNumber": {}, - "server": "Server", - "@server": {}, - "serverAddress": "Serveradresse", - "@serverAddress": {}, - "serverApiRequired": "Erforderliche API-Version", - "@serverApiRequired": {}, - "serverApiVersion": "API-Version des Servers", - "@serverApiVersion": {}, - "serverAuthenticationError": "Anmeldung fehlgeschlagen", - "@serverAuthenticationError": {}, - "serverCertificateError": "Zertifikatsfehler", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Zertifikat des Servers ist ungültig", - "@serverCertificateInvalid": {}, - "serverConnected": "Verbunden mit Server", - "@serverConnected": {}, - "serverConnecting": "Verbindung zum Server wird aufgebaut", - "@serverConnecting": {}, - "serverCouldNotConnect": "Verbindung zum Server nicht möglich", - "@serverCouldNotConnect": {}, - "serverEmpty": "Server darf nicht leer sein", - "@serverEmpty": {}, - "serverError": "Serverfehler", - "@serverError": {}, - "serverDetails": "Serverdetails", - "@serverDetails": {}, - "serverMissingData": "In der Server-Antwort fehlen erforderliche Felder", - "@serverMissingData": {}, - "serverOld": "Alte Server Version", - "@serverOld": {}, - "serverSettings": "Server Einstellungen", - "@serverSettings": {}, - "serverStart": "Server muss mit http[s] beginnen", - "@serverStart": {}, - "settings": "Einstellungen", - "@settings": {}, - "serverInstance": "Server Instanz", - "@serverInstance": {}, - "serverNotConnected": "Server nicht verbunden", - "@serverNotConnected": {}, - "sounds": "Töne", - "@sounds": {}, - "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Ton bei Serverfehler abspielen", - "@soundOnServerError": {}, - "status": "Status", - "@status": {}, - "statusCode": "Statuscode", - "@statusCode": {}, - "stock": "Bestand", - "@stock": { - "description": "stock" - }, - "stockDetails": "Aktuell verfügbare Lagermenge", - "@stockDetails": {}, - "stockItem": "Artikel", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Artikel", - "@stockItems": {}, - "stockItemCreate": "Neuen Artikel anlegen", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Neuen Artikel an diesem Lagerort erstellen", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Lagerartikel löschen", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Sind Sie sicher, dass Sie diesen Lagerartikel löschen wollen?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Lagerbestand konnte nicht gelöscht werden", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Lagerbestand gelöscht", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historie des Artikels", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Zeige historische Bestandsverfolgungsdaten", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Artikel umgezogen", - "@stockItemTransferred": {}, - "stockItemUpdated": "Artikel aktualisiert", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Keine Artikel verfügbar", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notizen zum Artikel", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Artikel aktualisiert", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Fehler bei Artikel-Aktualisierung", - "@stockItemUpdateFailure": {}, - "stockLocation": "Lagerort", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Lagerorte", - "@stockLocations": {}, - "stockTopLevel": "Oberster Lagerort", - "@stockTopLevel": {}, - "strictHttps": "Striktes HTTPS verwenden", - "@strictHttps": {}, - "strictHttpsDetails": "Erzwinge strenge Überprüfung von HTTPs-Zertifikaten", - "@strictHttpsDetails": {}, - "subcategory": "Unterkategorie", - "@subcategory": {}, - "subcategories": "Unterkategorien", - "@subcategories": {}, - "sublocation": "Unter-Lagerort", - "@sublocation": {}, - "sublocations": "Unter-Lagerorte", - "@sublocations": {}, - "sublocationNone": "Keine Unter-Lagerorte", - "@sublocationNone": {}, - "sublocationNoneDetail": "Keine Unter-Lagerorte verfügbar", - "@sublocationNoneDetail": {}, - "submitFeedback": "Feedback geben", - "@submitFeedback": {}, - "suppliedParts": "Gelieferte Teile", - "@suppliedParts": {}, - "supplier": "Lieferant", - "@supplier": {}, - "suppliers": "Lieferanten", - "@suppliers": {}, - "supplierReference": "Lieferanten-Referenz", - "@supplierReference": {}, - "takePicture": "Foto aufnehmen", - "@takePicture": {}, - "targetDate": "Zieldatum", - "@targetDate": {}, - "templatePart": "Übergeordnetes Vorlagenteil", - "@templatePart": {}, - "testName": "Test-Name", - "@testName": {}, - "testPassedOrFailed": "Test erfolgreich oder fehlgeschlagen", - "@testPassedOrFailed": {}, - "testsRequired": "Erforderliche Tests", - "@testsRequired": {}, - "testResults": "Testergebnisse", - "@testResults": { - "description": "" - }, - "testResultAdd": "Testergebnis hinzufügen", - "@testResultAdd": {}, - "testResultNone": "Keine Testergebnisse", - "@testResultNone": {}, - "testResultNoneDetail": "Keine Testergebnisse vorhanden", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Fehler beim Hochladen des Testergebnisses", - "@testResultUploadFail": {}, - "testResultUploadPass": "Testergebnis hochgeladen", - "@testResultUploadPass": {}, - "timeout": "Zeitüberschreitung", - "@timeout": { - "description": "" - }, - "tokenError": "Token-Fehler", - "@tokenError": {}, - "tokenMissing": "Token fehlt", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", - "@tokenMissingFromResponse": {}, - "transfer": "Verschieben", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Bestand verschieben", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Übersetzen", - "@translate": {}, - "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", - "@translateHelp": {}, - "units": "Einheiten", - "@units": {}, - "unknownResponse": "Unbekannte Antwort", - "@unknownResponse": {}, - "upload": "Hochladen", - "@upload": {}, - "uploadFailed": "Datei hochladen fehlgeschlagen", - "@uploadFailed": {}, - "uploadSuccess": "Datei hochgeladen", - "@uploadSuccess": {}, - "usedIn": "Verwendet in", - "@usedIn": {}, - "usedInDetails": "Baugruppen, die dieses Teil benötigen", - "@usedInDetails": {}, - "username": "Benutzername", - "@username": {}, - "usernameEmpty": "Der Benutzername darf nicht leer sein", - "@usernameEmpty": {}, - "value": "Wert", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Dieser Wert darf nicht leer sein", - "@valueCannotBeEmpty": {}, - "valueRequired": "Wert erforderlich", - "@valueRequired": {}, - "version": "Version", - "@version": {}, - "viewSupplierPart": "Zulieferer-Teil anzeigen", - "@viewSupplierPart": {}, - "website": "Website", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_el.arb b/lib/l10n/app_el.arb deleted file mode 100644 index 2ae9e43..0000000 --- a/lib/l10n/app_el.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "el", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb deleted file mode 100644 index 17a7a62..0000000 --- a/lib/l10n/app_es.arb +++ /dev/null @@ -1,17 +0,0 @@ -{ - "@@locale": "es", - "barcodeScanInItems": "Escanear artículos de stock en su ubicación", - "@barcodeScanInItems": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", - "@includeSublocationsDetail": {}, - "lineItems": "Ítems de línea", - "@lineItems": {}, - "onOrderDetails": "Artículos actualmente en pedido", - "@onOrderDetails": {}, - "stockItems": "Elementos de stock", - "@stockItems": {}, - "stockItemsNotAvailable": "No hay artículos de stock disponibles", - "@stockItemsNotAvailable": {} -} \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb deleted file mode 100644 index f17cd61..0000000 --- a/lib/l10n/app_fa.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "fa", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb deleted file mode 100644 index b4ded9e..0000000 --- a/lib/l10n/app_fr.arb +++ /dev/null @@ -1,743 +0,0 @@ -{ - "@@locale": "fr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "À propos", - "@about": {}, - "accountDetails": "Détails du compte", - "@accountDetails": {}, - "actions": "Actions", - "@actions": { - "description": "" - }, - "actionsNone": "Aucune action disponible", - "@actionsNone": {}, - "add": "Ajouter", - "@add": { - "description": "add" - }, - "addStock": "Ajouter un stock", - "@addStock": { - "description": "add stock" - }, - "address": "Adresse", - "@address": {}, - "appAbout": "À propos d'InvenTree", - "@appAbout": {}, - "appCredits": "Crédits d'application supplémentaires", - "@appCredits": {}, - "appDetails": "Détails de l'application", - "@appDetails": {}, - "appReleaseNotes": "Afficher les notes de version de l'application", - "@appReleaseNotes": {}, - "appSettings": "Réglages de l'application", - "@appSettings": {}, - "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", - "@appSettingsDetails": {}, - "attachments": "Pieces jointes", - "@attachments": {}, - "attachImage": "Ajouter une image", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Aucune pièce jointe trouvée", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Sélectionner une pièce jointe", - "@attachmentSelect": {}, - "attention": "Attention", - "@attention": {}, - "availableStock": "Stock disponible", - "@availableStock": {}, - "barcodeAssign": "Affecter un code-barres", - "@barcodeAssign": {}, - "barcodeAssigned": "Code-barres affecté", - "@barcodeAssigned": {}, - "barcodeError": "Erreur lors du scan du code-barres", - "@barcodeError": {}, - "barcodeInUse": "Le code-barres est déjà en cours d’utilisation", - "@barcodeInUse": {}, - "barcodeMissingHash": "Les données de hachage du code-barres sont manquantes dans la réponse", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Pas de correspondance pour ce code-barres", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Code-barres non assigné", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scanner pour attribuer un code-barres", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Scanner un code-barres InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scannez les items de stock à l'emplacement", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scanner la localisation du stock", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item non scanné dans", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scanner l'article en stock", - "@barcodeScanItem": {}, - "barcodeTones": "Types de code-barre", - "@barcodeTones": {}, - "barcodeUnassign": "Désaffecter le code-barres", - "@barcodeUnassign": {}, - "barcodeUnknown": "Code-barres non reconnu", - "@barcodeUnknown": {}, - "batchCode": "Code de lot", - "@batchCode": {}, - "billOfMaterials": "Liste des matériaux", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Assemblage", - "@build": {}, - "building": "Assemblage en cours", - "@building": {}, - "cancel": "Annuler", - "@cancel": { - "description": "Cancel" - }, - "category": "Catégorie", - "@category": {}, - "categoryCreate": "Nouvelle catégorie", - "@categoryCreate": {}, - "categoryCreateDetail": "Créer une nouvelle catégorie de pièce", - "@categoryCreateDetail": {}, - "categoryUpdated": "Catégorie de pièce mise à jour", - "@categoryUpdated": {}, - "company": "Société", - "@company": {}, - "companyEdit": "Modifier la société", - "@companyEdit": {}, - "companyNoResults": "Aucune société ne correspond à la requête", - "@companyNoResults": {}, - "companyUpdated": "Détails de la société mis à jour", - "@companyUpdated": {}, - "companies": "Sociétés", - "@companies": {}, - "configureServer": "Configurer les paramètres serveur", - "@configureServer": {}, - "connectionRefused": "Connexion refusée", - "@connectionRefused": {}, - "count": "Nombre", - "@count": { - "description": "Count" - }, - "countStock": "Nombre de stock", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Crédits", - "@credits": {}, - "customers": "Clients", - "@customers": {}, - "damaged": "Endommagé", - "@damaged": {}, - "delete": "Supprimer", - "@delete": {}, - "deletePart": "Supprimer la pièce", - "@deletePart": {}, - "deletePartDetail": "Supprimer cette pièce de la base de données", - "@deletePartDetail": {}, - "description": "Description", - "@description": {}, - "destroyed": "Détruit", - "@destroyed": {}, - "details": "Détails", - "@details": { - "description": "details" - }, - "documentation": "Documentation", - "@documentation": {}, - "downloading": "Téléchargement du fichier", - "@downloading": {}, - "downloadError": "Erreur lors du téléchargement", - "@downloadError": {}, - "edit": "Modifier", - "@edit": { - "description": "edit" - }, - "editCategory": "Modifier la catégorie", - "@editCategory": {}, - "editLocation": "Modifier l’emplacement", - "@editLocation": {}, - "editNotes": "Modifier les notes", - "@editNotes": {}, - "editPart": "Modifier la pièce", - "@editPart": { - "description": "edit part" - }, - "editItem": "Editer l'article en stock", - "@editItem": {}, - "enterPassword": "Saisissez le mot de passe", - "@enterPassword": {}, - "enterUsername": "Saisissez le nom d'utilisateur", - "@enterUsername": {}, - "error": "Erreur", - "@error": { - "description": "Error" - }, - "errorCreate": "Erreur lors de la création de l'entrée de la base de données", - "@errorCreate": {}, - "errorDelete": "Erreur lors de la suppression de l'entrée de la base de données", - "@errorDelete": {}, - "errorDetails": "Détails de l'erreur", - "@errorDetails": {}, - "errorFetch": "Erreur de récupération des données du serveur", - "@errorFetch": {}, - "errorReporting": "Rapport d'erreur", - "@errorReporting": {}, - "errorReportUpload": "Envoyer le rapport d 'erreur", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", - "@errorReportUploadDetails": {}, - "feedback": "Donner votre avis", - "@feedback": {}, - "feedbackError": "Erreur lors de l'envoi du commentaire", - "@feedbackError": {}, - "feedbackSuccess": "Commentaire envoyé", - "@feedbackSuccess": {}, - "formatException": "Exception de format", - "@formatException": {}, - "formatExceptionJson": "Exception de format de données JSON", - "@formatExceptionJson": {}, - "formError": "Erreur de formulaire", - "@formError": {}, - "history": "Historique", - "@history": { - "description": "history" - }, - "homeScreen": "Ecran d'accueil", - "@homeScreen": {}, - "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", - "@homeScreenSettings": {}, - "homeShowPo": "Afficher les commandes d'achat", - "@homeShowPo": {}, - "homeShowSubscribed": "Pièces suivies", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Afficher les fournisseurs", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Afficher les fabriquants", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Afficher le bouton fabriquant sur l'écran d'accueil", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Afficher les clients", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Afficher le bouton clients sur l'écran d'accueil", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Échec de l'envoi de l'image", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Image transférée", - "@imageUploadSuccess": {}, - "inactive": "Inactif", - "@inactive": {}, - "inactiveDetail": "Cette pièce est marquée comme inactive", - "@inactiveDetail": {}, - "includeSubcategories": "Inclure les sous-catégories", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Afficher les sous-catégories dans la vue liste", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Inclure les sous-emplacements", - "@includeSublocations": {}, - "includeSublocationsDetail": "Afficher les sous-emplacements des articles dans la vue liste", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Profil incomplet", - "@incompleteDetails": {}, - "internalPartNumber": "Numéro de pièce interne", - "@internalPartNumber": {}, - "info": "Information", - "@info": {}, - "inProduction": "En production", - "@inProduction": {}, - "inProductionDetail": "Cet article de stock est en production", - "@inProductionDetail": {}, - "invalidHost": "Nom d’hôte invalide", - "@invalidHost": {}, - "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", - "@invalidHostDetails": {}, - "invalidPart": "Article non valide", - "@invalidPart": {}, - "invalidPartCategory": "Catégorie d'article invalide", - "@invalidPartCategory": {}, - "invalidStockLocation": "Emplacement invalide", - "@invalidStockLocation": {}, - "invalidStockItem": "Article en stock non valide", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", - "@invalidUsernamePassword": {}, - "issueDate": "Date d'émission", - "@issueDate": {}, - "itemInLocation": "Article déjà dans l'emplacement", - "@itemInLocation": {}, - "keywords": "Mots clés", - "@keywords": {}, - "lastStocktake": "Dernier inventaire", - "@lastStocktake": {}, - "lastUpdated": "Dernière mise à jour", - "@lastUpdated": {}, - "lineItem": "Position", - "@lineItem": {}, - "lineItems": "Position", - "@lineItems": {}, - "locationCreate": "Nouvel emplacement", - "@locationCreate": {}, - "locationCreateDetail": "Créer un nouvel emplacement de stock", - "@locationCreateDetail": {}, - "locationNotSet": "Aucun emplacement spécifié", - "@locationNotSet": {}, - "locationUpdated": "Emplacement du stock mis à jour", - "@locationUpdated": {}, - "link": "Lien", - "@link": {}, - "lost": "Perdu", - "@lost": {}, - "manufacturers": "Fabricants", - "@manufacturers": {}, - "missingData": "Données manquantes", - "@missingData": {}, - "name": "Nom", - "@name": {}, - "notConnected": "Non connecté", - "@notConnected": {}, - "notes": "Notes", - "@notes": { - "description": "Notes" - }, - "noResponse": "Aucune réponse du serveur", - "@noResponse": {}, - "noResults": "Aucun résultat", - "@noResults": {}, - "noSubcategories": "Pas de sous-catégorie", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Nombre invalide", - "@numberInvalid": {}, - "onOrder": "Sur Commande", - "@onOrder": {}, - "onOrderDetails": "Articles en cours de commande", - "@onOrderDetails": {}, - "packaging": "Emballage", - "@packaging": {}, - "packageName": "Nom du package", - "@packageName": {}, - "parent": "Parent", - "@parent": {}, - "parentCategory": "Catégorie parent", - "@parentCategory": {}, - "parentLocation": "Emplacement parent", - "@parentLocation": {}, - "part": "Pièce", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Nouvelle pièce", - "@partCreate": {}, - "partCreateDetail": "Créer une nouvelle pièce dans cette catégorie", - "@partCreateDetail": {}, - "partEdited": "Pièce mise à jour", - "@partEdited": {}, - "parts": "Pièces", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Aucune pièces", - "@partsNone": {}, - "partNoResults": "Pas de pièces correspondant à la requête", - "@partNoResults": {}, - "partsStarred": "Pièces suivies", - "@partsStarred": {}, - "partsStarredNone": "Aucune pièce favorite disponible", - "@partsStarredNone": {}, - "partSuppliers": "Fournisseurs de pièces", - "@partSuppliers": {}, - "partCategory": "Catégorie de la pièce", - "@partCategory": {}, - "partCategoryTopLevel": "Catégorie de pièce parente", - "@partCategoryTopLevel": {}, - "partCategories": "Catégories de pièce", - "@partCategories": {}, - "partDetails": "Détails de la pièce", - "@partDetails": {}, - "partNotes": "Notes de la pièce", - "@partNotes": {}, - "partStock": "Stock de la pièce", - "@partStock": { - "description": "part stock" - }, - "password": "Mot de passe", - "@password": {}, - "passwordEmpty": "Le mot de passe peut pas être vide", - "@passwordEmpty": {}, - "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", - "@permissionAccountDenied": {}, - "permissionRequired": "Autorisation requise", - "@permissionRequired": {}, - "printLabel": "Imprimer l'étiquette", - "@printLabel": {}, - "printLabelFailure": "Echec de l'impression", - "@printLabelFailure": {}, - "printLabelSuccess": "Etiquette envoyée à l'imprimante", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Ajouter un profil serveur", - "@profileAdd": {}, - "profileConnect": "Se connecter au serveur", - "@profileConnect": {}, - "profileEdit": "Editer le profil du serveur", - "@profileEdit": {}, - "profileDelete": "Supprimer le profil du serveur", - "@profileDelete": {}, - "profileName": "Nom du profil", - "@profileName": {}, - "profileNone": "Aucun profil disponible", - "@profileNone": {}, - "profileNotSelected": "Aucun profil sélectionné", - "@profileNotSelected": {}, - "profileSelect": "Sélectionner le serveur InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", - "@profileTapToCreate": {}, - "purchaseOrder": "Commande d’achat", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Modifier la commande d'achat", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Commandes d'achat", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Bon de commande mis à jour", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Prix d'achat", - "@purchasePrice": {}, - "quantity": "Quantité", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "La quantité est vide", - "@quantityEmpty": {}, - "quantityInvalid": "La quantité n'est pas valide", - "@quantityInvalid": {}, - "quantityPositive": "La quantité doit être positive", - "@quantityPositive": {}, - "queryNoResults": "Pas de résultat pour votre requête", - "@queryNoResults": {}, - "received": "Reçu", - "@received": {}, - "receiveItem": "Articles reçus", - "@receiveItem": {}, - "receivedItem": "Article de stock reçu", - "@receivedItem": {}, - "refresh": "Actualiser", - "@refresh": {}, - "refreshing": "Actualisation en cours", - "@refreshing": {}, - "rejected": "Rejeté", - "@rejected": {}, - "releaseNotes": "Notes de Version", - "@releaseNotes": {}, - "remove": "Supprimer", - "@remove": { - "description": "remove" - }, - "removeStock": "Supprimer le stock", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Signaler un bug", - "@reportBug": {}, - "reportBugDescription": "Envoyer un rapport de bug (nécessite un compte GitHub)", - "@reportBugDescription": {}, - "results": "Résultats", - "@results": {}, - "request": "Requête", - "@request": {}, - "requestingData": "Demande de données", - "@requestingData": {}, - "required": "Requis", - "@required": { - "description": "This field is required" - }, - "response400": "Mauvaise requête", - "@response400": {}, - "response401": "Non autorisé", - "@response401": {}, - "response403": "Autorisation refusée", - "@response403": {}, - "response404": "Ressource non trouvée", - "@response404": {}, - "response405": "Méthode non autorisé", - "@response405": {}, - "response429": "Trop de requêtes", - "@response429": {}, - "response500": "Erreur interne du serveur", - "@response500": {}, - "response501": "Non implémenté", - "@response501": {}, - "response502": "Mauvaise passerelle", - "@response502": {}, - "response503": "Service indisponible", - "@response503": {}, - "response504": "Délai d'attente de la passerelle expiré", - "@response504": {}, - "response505": "Version HTTP non prise en charge", - "@response505": {}, - "responseData": "Données de la réponse", - "@responseData": {}, - "responseInvalid": "Code de réponse invalide", - "@responseInvalid": {}, - "responseUnknown": "Réponse inconnue", - "@responseUnknown": {}, - "result": "Résultat ", - "@result": { - "description": "" - }, - "returned": "Retourné", - "@returned": {}, - "salesOrders": "Ventes", - "@salesOrders": {}, - "save": "Enregistrer", - "@save": { - "description": "Save" - }, - "scanBarcode": "Scanner un code-barres", - "@scanBarcode": {}, - "scanIntoLocation": "Scanner vers l'emplacement", - "@scanIntoLocation": {}, - "search": "Rechercher", - "@search": { - "description": "search" - }, - "searchLocation": "Rechercher un emplacement", - "@searchLocation": {}, - "searchParts": "Rechercher de pièces", - "@searchParts": {}, - "searchStock": "Rechercher un stock", - "@searchStock": {}, - "select": "Sélectionner", - "@select": {}, - "selectFile": "Sélectionner un fichier", - "@selectFile": {}, - "selectImage": "Sélectionner une image", - "@selectImage": {}, - "selectLocation": "Sélectionnez un emplacement", - "@selectLocation": {}, - "send": "Envoyer", - "@send": {}, - "serialNumber": "Numéro de série", - "@serialNumber": {}, - "server": "Serveur", - "@server": {}, - "serverAddress": "Adresse du serveur", - "@serverAddress": {}, - "serverApiRequired": "Version de l'API requise", - "@serverApiRequired": {}, - "serverApiVersion": "Version de l'API du serveur", - "@serverApiVersion": {}, - "serverAuthenticationError": "Erreur lors de l'authentification", - "@serverAuthenticationError": {}, - "serverCertificateError": "Erreur de certificat", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Le certificat HTTPS du serveur n'est pas valide", - "@serverCertificateInvalid": {}, - "serverConnected": "Connecté au serveur", - "@serverConnected": {}, - "serverConnecting": "Connexion au serveur", - "@serverConnecting": {}, - "serverCouldNotConnect": "Connexion au serveur impossible", - "@serverCouldNotConnect": {}, - "serverEmpty": "Le serveur ne peut pas être vide", - "@serverEmpty": {}, - "serverError": "Erreur serveur", - "@serverError": {}, - "serverDetails": "Détails du serveur", - "@serverDetails": {}, - "serverMissingData": "La réponse du serveur ne possède pas les champs obligatoires", - "@serverMissingData": {}, - "serverOld": "Ancienne version du serveur", - "@serverOld": {}, - "serverSettings": "Paramètres du serveur", - "@serverSettings": {}, - "serverStart": "Le serveur doit débuter par http[s]", - "@serverStart": {}, - "settings": "Réglages", - "@settings": {}, - "serverInstance": "Instance du serveur", - "@serverInstance": {}, - "serverNotConnected": "Le serveur n'est pas connecté", - "@serverNotConnected": {}, - "sounds": "Sons", - "@sounds": {}, - "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Jouer une tonalité sonore en cas d'erreur du serveur", - "@soundOnServerError": {}, - "status": "État", - "@status": {}, - "statusCode": "Code d'état", - "@statusCode": {}, - "stock": "Stock", - "@stock": { - "description": "stock" - }, - "stockDetails": "Quantité actuelle de stock disponible", - "@stockDetails": {}, - "stockItem": "Article en stock", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Articles en stock", - "@stockItems": {}, - "stockItemCreate": "Nouvel article en stock", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Créer un nouvel article en stock dans cet emplacement", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Supprimer l'article du stock", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Êtes-vous certain de vouloir supprimer cet article ?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Impossible de supprmer cet article", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Article supprimé", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historique du stock", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Afficher les informations de suivi de stock", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Article en stock transféré", - "@stockItemTransferred": {}, - "stockItemUpdated": "Article en stock mis à jour", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Aucun article en stock", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notes de l'article en stock", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Article en stock mis à jour", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Echec de la mise à jour de l'article en stock", - "@stockItemUpdateFailure": {}, - "stockLocation": "Emplacement du stock", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Emplacements du stock", - "@stockLocations": {}, - "stockTopLevel": "Emplacement de stock de premier niveau", - "@stockTopLevel": {}, - "strictHttps": "Utiliser HTTPS strict", - "@strictHttps": {}, - "strictHttpsDetails": "Obliger une vérification stricte des certificats HTTP", - "@strictHttpsDetails": {}, - "subcategory": "Sous-catégorie", - "@subcategory": {}, - "subcategories": "Sous-catégories", - "@subcategories": {}, - "sublocation": "Sous-emplacement", - "@sublocation": {}, - "sublocations": "Sous-emplacements", - "@sublocations": {}, - "sublocationNone": "Aucun sous-emplacement", - "@sublocationNone": {}, - "sublocationNoneDetail": "Aucun sous-emplacement disponible", - "@sublocationNoneDetail": {}, - "submitFeedback": "Soumettre le commentaire", - "@submitFeedback": {}, - "suppliedParts": "Composants fournis", - "@suppliedParts": {}, - "supplier": "Fournisseur", - "@supplier": {}, - "suppliers": "Fournisseurs", - "@suppliers": {}, - "supplierReference": "Référence du fournisseur", - "@supplierReference": {}, - "takePicture": "Prendre une photo", - "@takePicture": {}, - "targetDate": "Date Cible", - "@targetDate": {}, - "testName": "Nom de test", - "@testName": {}, - "testPassedOrFailed": "Test réussi ou échoué", - "@testPassedOrFailed": {}, - "testsRequired": "Tests requis", - "@testsRequired": {}, - "testResults": "Résultats du test", - "@testResults": { - "description": "" - }, - "testResultAdd": "Ajouter un résultat de test", - "@testResultAdd": {}, - "testResultNone": "Aucun résultat de test", - "@testResultNone": {}, - "testResultNoneDetail": "Aucun résultat de test disponible", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Erreur lors de l'envoi du résultat du test", - "@testResultUploadFail": {}, - "testResultUploadPass": "Résultats du test chargés", - "@testResultUploadPass": {}, - "timeout": "Délai dépassé", - "@timeout": { - "description": "" - }, - "tokenError": "Erreur du jeton", - "@tokenError": {}, - "tokenMissing": "Jeton manquant", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", - "@tokenMissingFromResponse": {}, - "transfer": "Transfert", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Transférer le stock", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Traduire", - "@translate": {}, - "translateHelp": "Aidez à traduire l'application InvenTree", - "@translateHelp": {}, - "units": "Unités", - "@units": {}, - "unknownResponse": "Réponse inconnue", - "@unknownResponse": {}, - "upload": "Importer le fichier", - "@upload": {}, - "uploadFailed": "Échec du chargement du fichier", - "@uploadFailed": {}, - "uploadSuccess": "Fichier transféré", - "@uploadSuccess": {}, - "usedIn": "Utilisé dans", - "@usedIn": {}, - "usedInDetails": "Assemblages qui requièrent ce composant", - "@usedInDetails": {}, - "username": "Nom d'utilisateur", - "@username": {}, - "usernameEmpty": "Le nom d'utilisateur peut pas être vide", - "@usernameEmpty": {}, - "value": "Valeur", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "La valeur ne peut pas être vide", - "@valueCannotBeEmpty": {}, - "valueRequired": "La valeur est requise", - "@valueRequired": {}, - "version": "Version", - "@version": {}, - "viewSupplierPart": "Voir la pièce du fournisseur", - "@viewSupplierPart": {}, - "website": "Site web", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_he.arb b/lib/l10n/app_he.arb deleted file mode 100644 index 2d1bbf1..0000000 --- a/lib/l10n/app_he.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "he", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_hu.arb b/lib/l10n/app_hu.arb deleted file mode 100644 index 98a69b4..0000000 --- a/lib/l10n/app_hu.arb +++ /dev/null @@ -1,745 +0,0 @@ -{ - "@@locale": "hu", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Névjegy", - "@about": {}, - "accountDetails": "Felhasználó adatok", - "@accountDetails": {}, - "actions": "Műveletek", - "@actions": { - "description": "" - }, - "actionsNone": "Nincsenek műveletek", - "@actionsNone": {}, - "add": "Hozzáadás", - "@add": { - "description": "add" - }, - "addStock": "Készlet növelése", - "@addStock": { - "description": "add stock" - }, - "address": "Cím", - "@address": {}, - "appAbout": "InvenTree névjegy", - "@appAbout": {}, - "appCredits": "További közreműködők", - "@appCredits": {}, - "appDetails": "App részletek", - "@appDetails": {}, - "appReleaseNotes": "Kiadási közlemények", - "@appReleaseNotes": {}, - "appSettings": "Alkalmazásbeállítások", - "@appSettings": {}, - "appSettingsDetails": "Inventree alkalmazás beállításai", - "@appSettingsDetails": {}, - "attachments": "Mellékletek", - "@attachments": {}, - "attachImage": "Kép csatolása", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nem találhatók mellékletek", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Melléklet kiválasztása", - "@attachmentSelect": {}, - "attention": "Figyelem", - "@attention": {}, - "availableStock": "Elérhető készlet", - "@availableStock": {}, - "barcodeAssign": "Vonalkód hozzárendelése", - "@barcodeAssign": {}, - "barcodeAssigned": "Vonalkód hozzárendelve", - "@barcodeAssigned": {}, - "barcodeError": "Vonalkód olvasási hiba", - "@barcodeError": {}, - "barcodeInUse": "Vonalkód már hozzárendelve", - "@barcodeInUse": {}, - "barcodeMissingHash": "Vonalkód hash hiányzik a válaszból", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Nincs egyezés vonalkódra", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Készlet bevételezése az adott helyre", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Hely beolvasása", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Készlet tétel beolvasása", - "@barcodeScanItem": {}, - "barcodeTones": "Vonalkód hangszín", - "@barcodeTones": {}, - "barcodeUnassign": "Vonalkód leválasztása", - "@barcodeUnassign": {}, - "barcodeUnknown": "Vonalkód nem ismerhető fel", - "@barcodeUnknown": {}, - "batchCode": "Batch kód", - "@batchCode": {}, - "billOfMaterials": "Alkatrészjegyzék", - "@billOfMaterials": {}, - "bom": "Alkatrészjegyzék", - "@bom": {}, - "build": "Gyártás", - "@build": {}, - "building": "Gyártásban", - "@building": {}, - "cancel": "Mégsem", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategória", - "@category": {}, - "categoryCreate": "Új kategória", - "@categoryCreate": {}, - "categoryCreateDetail": "Alkatrész kategória létrehozása", - "@categoryCreateDetail": {}, - "categoryUpdated": "Alkatrész kategória módosítva", - "@categoryUpdated": {}, - "company": "Cég", - "@company": {}, - "companyEdit": "Cég szerkesztése", - "@companyEdit": {}, - "companyNoResults": "Nincs a lekérdezésnek megfelelő cég", - "@companyNoResults": {}, - "companyUpdated": "Cég adatai frissítve", - "@companyUpdated": {}, - "companies": "Cégek", - "@companies": {}, - "configureServer": "Kiszolgáló beállítások konfigurálása", - "@configureServer": {}, - "connectionRefused": "A kapcsolat visszautasítva", - "@connectionRefused": {}, - "count": "Mennyiség", - "@count": { - "description": "Count" - }, - "countStock": "Leltározás", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Közreműködők", - "@credits": {}, - "customers": "Vevők", - "@customers": {}, - "damaged": "Sérült", - "@damaged": {}, - "delete": "Törlés", - "@delete": {}, - "deletePart": "Alkatrész törlése", - "@deletePart": {}, - "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", - "@deletePartDetail": {}, - "description": "Leírás", - "@description": {}, - "destroyed": "Megsemmisült", - "@destroyed": {}, - "details": "Részletek", - "@details": { - "description": "details" - }, - "documentation": "Dokumentáció", - "@documentation": {}, - "downloading": "Fájl letöltése", - "@downloading": {}, - "downloadError": "Letöltési hiba", - "@downloadError": {}, - "edit": "Szerkesztés", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategória szerkesztése", - "@editCategory": {}, - "editLocation": "Hely szerkesztése", - "@editLocation": {}, - "editNotes": "Megjegyzések szerkesztése", - "@editNotes": {}, - "editPart": "Alkatrész szerkesztése", - "@editPart": { - "description": "edit part" - }, - "editItem": "Készlet tétel szerkesztése", - "@editItem": {}, - "enterPassword": "Jelszó megadása", - "@enterPassword": {}, - "enterUsername": "Felhasználó megadása", - "@enterUsername": {}, - "error": "Hiba", - "@error": { - "description": "Error" - }, - "errorCreate": "Hiba az adatbázis bejegyzés létrehozása közben", - "@errorCreate": {}, - "errorDelete": "Hiba az adatbázis bejegyzés törlése közben", - "@errorDelete": {}, - "errorDetails": "Hiba részletei", - "@errorDetails": {}, - "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", - "@errorFetch": {}, - "errorReporting": "Hibajelentés", - "@errorReporting": {}, - "errorReportUpload": "Hibajelentések feltöltése", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", - "@errorReportUploadDetails": {}, - "feedback": "Visszajelzés", - "@feedback": {}, - "feedbackError": "Visszajelzés küldése sikertelen", - "@feedbackError": {}, - "feedbackSuccess": "Visszajelzés elküldve", - "@feedbackSuccess": {}, - "formatException": "Formátum hiba", - "@formatException": {}, - "formatExceptionJson": "JSON adatformátum hiba", - "@formatExceptionJson": {}, - "formError": "Form hiba", - "@formError": {}, - "history": "Előzmények", - "@history": { - "description": "history" - }, - "homeScreen": "Főképernyő", - "@homeScreen": {}, - "homeScreenSettings": "Főképernyő beállítások konfigurálása", - "@homeScreenSettings": {}, - "homeShowPo": "Beszerzési rendelések megjelenítése", - "@homeShowPo": {}, - "homeShowSubscribed": "Értesítésre beállított alkatrészek", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Beszállítók megjelenítése", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Gyártók megjelenítése", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Gyártók gomb megjelenítése a főoldalon", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Vevők megjelenítése", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Vevők gomb megjelenítése a főoldalon", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Kép feltöltése sikertelen", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Kép feltöltve", - "@imageUploadSuccess": {}, - "inactive": "Inaktív", - "@inactive": {}, - "inactiveDetail": "Ez az alkatrész inaktív lett", - "@inactiveDetail": {}, - "includeSubcategories": "Alkategóriákkal együtt", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Al-kategóriájú alkatrészek megjelenítése a lista nézetben", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Alhelyekkel együtt", - "@includeSublocations": {}, - "includeSublocationsDetail": "Al-helyen lévő alkatrészek megjelenítése a lista nézetben", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Nem teljes profil adatok", - "@incompleteDetails": {}, - "internalPartNumber": "Belső alkatrész azonosító", - "@internalPartNumber": {}, - "info": "Infó", - "@info": {}, - "inProduction": "Gyártásban", - "@inProduction": {}, - "inProductionDetail": "Ez a készlet tétel gyártásban van", - "@inProductionDetail": {}, - "invalidHost": "Érvénytelen hostnév", - "@invalidHost": {}, - "invalidHostDetails": "A megadott hostnév nem érvényes", - "@invalidHostDetails": {}, - "invalidPart": "Érvénytelen alkatrész", - "@invalidPart": {}, - "invalidPartCategory": "Érvénytelen kategória", - "@invalidPartCategory": {}, - "invalidStockLocation": "Érvénytelen készlet hely", - "@invalidStockLocation": {}, - "invalidStockItem": "Érvénytelen készlet tétel", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", - "@invalidUsernamePassword": {}, - "issueDate": "Kiállítás dátuma", - "@issueDate": {}, - "itemInLocation": "A tétel már a megadott helyen van", - "@itemInLocation": {}, - "keywords": "Kulcsszavak", - "@keywords": {}, - "lastStocktake": "Utolsó leltár", - "@lastStocktake": {}, - "lastUpdated": "Utoljára módosítva", - "@lastUpdated": {}, - "lineItem": "Sortétel", - "@lineItem": {}, - "lineItems": "Sortételek", - "@lineItems": {}, - "locationCreate": "Új hely", - "@locationCreate": {}, - "locationCreateDetail": "Új készlet hely létrehozása", - "@locationCreateDetail": {}, - "locationNotSet": "Nincs megadva hely", - "@locationNotSet": {}, - "locationUpdated": "Készlet hely adatai frissítve", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Elveszett", - "@lost": {}, - "manufacturers": "Gyártók", - "@manufacturers": {}, - "missingData": "Hiányzó adatok", - "@missingData": {}, - "name": "Név", - "@name": {}, - "notConnected": "Nincs kapcsolódva", - "@notConnected": {}, - "notes": "Megjegyzések", - "@notes": { - "description": "Notes" - }, - "noResponse": "Nincs válasz a kiszolgálótól", - "@noResponse": {}, - "noResults": "Nincs találat", - "@noResults": {}, - "noSubcategories": "Nincsenek alkategóriák", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Nincsenek alkategóriák", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Érvénytelen szám", - "@numberInvalid": {}, - "onOrder": "Beszállítás alatt", - "@onOrder": {}, - "onOrderDetails": "Alaktrészek beszállítás alatt", - "@onOrderDetails": {}, - "packaging": "Csomagolás", - "@packaging": {}, - "packageName": "Csomag neve", - "@packageName": {}, - "parent": "Szülő", - "@parent": {}, - "parentCategory": "Szülő kategória", - "@parentCategory": {}, - "parentLocation": "Szülő hely", - "@parentLocation": {}, - "part": "Alkatrész", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Új alkatrész", - "@partCreate": {}, - "partCreateDetail": "Alkatrész létrehozása ebben a kategóriában", - "@partCreateDetail": {}, - "partEdited": "Alkatrész frissítve", - "@partEdited": {}, - "parts": "Alkatrészek", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Nincsenek alkatrészek", - "@partsNone": {}, - "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", - "@partNoResults": {}, - "partsStarred": "Értesítésre beállított alkatrészek", - "@partsStarred": {}, - "partsStarredNone": "Nincsenek csillagozott alkatrészek", - "@partsStarredNone": {}, - "partSuppliers": "Alkatrész beszállítók", - "@partSuppliers": {}, - "partCategory": "Alkatrész kategória", - "@partCategory": {}, - "partCategoryTopLevel": "Legfelső szintű alkatrész kategória", - "@partCategoryTopLevel": {}, - "partCategories": "Alkatrész kategóriák", - "@partCategories": {}, - "partDetails": "Alkatrész részletei", - "@partDetails": {}, - "partNotes": "Alkatrész megjegyzések", - "@partNotes": {}, - "partStock": "Alkatrész készlet", - "@partStock": { - "description": "part stock" - }, - "password": "Jelszó", - "@password": {}, - "passwordEmpty": "Jelszó nem lehet üres", - "@passwordEmpty": {}, - "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", - "@permissionAccountDenied": {}, - "permissionRequired": "Engedély szükséges", - "@permissionRequired": {}, - "printLabel": "Címke nyomtatása", - "@printLabel": {}, - "printLabelFailure": "Címkenyomtatás sikertelen", - "@printLabelFailure": {}, - "printLabelSuccess": "Címke nyomtatónak elküldve", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Kiszolgáló profil hozzáadása", - "@profileAdd": {}, - "profileConnect": "Kapcsolódás a kiszolgálóhoz", - "@profileConnect": {}, - "profileEdit": "Kiszolgáló profil szerkesztése", - "@profileEdit": {}, - "profileDelete": "Kiszolgáló profil törlése", - "@profileDelete": {}, - "profileName": "Profil neve", - "@profileName": {}, - "profileNone": "Nincsenek profilok", - "@profileNone": {}, - "profileNotSelected": "Nincs kiválasztva profil", - "@profileNotSelected": {}, - "profileSelect": "Válassz InvenTree kiszolgálót", - "@profileSelect": {}, - "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", - "@profileTapToCreate": {}, - "purchaseOrder": "Beszerzési rendelés", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Beszerzési rendelések", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Beszerzési rendelés frissítve", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Beszerzési ár", - "@purchasePrice": {}, - "quantity": "Mennyiség", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Mennyiség üres", - "@quantityEmpty": {}, - "quantityInvalid": "Mennyiség érvénytelen", - "@quantityInvalid": {}, - "quantityPositive": "Mennyiség pozitív kell legyen", - "@quantityPositive": {}, - "queryNoResults": "Nincs találat", - "@queryNoResults": {}, - "received": "Beérkezett", - "@received": {}, - "receiveItem": "Bevételezés", - "@receiveItem": {}, - "receivedItem": "Beérkezett készlet", - "@receivedItem": {}, - "refresh": "Frissítés", - "@refresh": {}, - "refreshing": "Frissítés...", - "@refreshing": {}, - "rejected": "Elutasított", - "@rejected": {}, - "releaseNotes": "Kiadási közlemények", - "@releaseNotes": {}, - "remove": "Törlés", - "@remove": { - "description": "remove" - }, - "removeStock": "Készlet csökkentése", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Hibabejelentés", - "@reportBug": {}, - "reportBugDescription": "Hibabejelentés küldése (GitHub fiók szükséges)", - "@reportBugDescription": {}, - "results": "Eredmények", - "@results": {}, - "request": "Kérés", - "@request": {}, - "requestingData": "Adatok lekérése", - "@requestingData": {}, - "required": "Kötelező", - "@required": { - "description": "This field is required" - }, - "response400": "Rossz kérés", - "@response400": {}, - "response401": "Jogosulatlan", - "@response401": {}, - "response403": "Hozzáférés megtagadva", - "@response403": {}, - "response404": "Erőforrás nem található", - "@response404": {}, - "response405": "Metódus nincs engedélyezve", - "@response405": {}, - "response429": "Túl sok kérés", - "@response429": {}, - "response500": "Belső kiszolgáló hiba", - "@response500": {}, - "response501": "Nincs implementálva", - "@response501": {}, - "response502": "Rossz átjáró", - "@response502": {}, - "response503": "A szolgáltatás nem érhető el", - "@response503": {}, - "response504": "Átjáró időtúllépés", - "@response504": {}, - "response505": "HTTP verzió nem támogatott", - "@response505": {}, - "responseData": "Válasz adatok", - "@responseData": {}, - "responseInvalid": "Érvénytelen válasz kód", - "@responseInvalid": {}, - "responseUnknown": "Ismeretlen válasz", - "@responseUnknown": {}, - "result": "Eredmény", - "@result": { - "description": "" - }, - "returned": "Visszaküldve", - "@returned": {}, - "salesOrders": "Vevői rendelések", - "@salesOrders": {}, - "save": "Mentés", - "@save": { - "description": "Save" - }, - "scanBarcode": "Vonalkód beolvasása", - "@scanBarcode": {}, - "scanIntoLocation": "Beolvasás helyre", - "@scanIntoLocation": {}, - "search": "Keresés", - "@search": { - "description": "search" - }, - "searchLocation": "Hely keresése", - "@searchLocation": {}, - "searchParts": "Alkatrészek keresése", - "@searchParts": {}, - "searchStock": "Készlet keresése", - "@searchStock": {}, - "select": "Kiválaszt", - "@select": {}, - "selectFile": "Fájl kiválasztása", - "@selectFile": {}, - "selectImage": "Válassz képet", - "@selectImage": {}, - "selectLocation": "Válassz helyet", - "@selectLocation": {}, - "send": "Küldés", - "@send": {}, - "serialNumber": "Sorozatszám", - "@serialNumber": {}, - "server": "Kiszolgáló", - "@server": {}, - "serverAddress": "Kiszolgáló címe", - "@serverAddress": {}, - "serverApiRequired": "Szükséges API verzió", - "@serverApiRequired": {}, - "serverApiVersion": "Szerver API verzió", - "@serverApiVersion": {}, - "serverAuthenticationError": "Hitelesítési hiba", - "@serverAuthenticationError": {}, - "serverCertificateError": "Tanúsítvány hiba", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Érvénytelen kiszolgáló HTTPS tanúsítvány", - "@serverCertificateInvalid": {}, - "serverConnected": "Kapcsolódva a kiszolgálóhoz", - "@serverConnected": {}, - "serverConnecting": "Kapcsolódás a kiszolgálóhoz", - "@serverConnecting": {}, - "serverCouldNotConnect": "Nem sikerült kapcsolódni a kiszolgálóhoz", - "@serverCouldNotConnect": {}, - "serverEmpty": "A kiszolgálónév nem lehet üres", - "@serverEmpty": {}, - "serverError": "Kiszolgálóhiba", - "@serverError": {}, - "serverDetails": "Kiszolgáló részletei", - "@serverDetails": {}, - "serverMissingData": "A kiszolgáló válaszából szükséges mezők hiányoznak", - "@serverMissingData": {}, - "serverOld": "Régi kiszolgáló verzió", - "@serverOld": {}, - "serverSettings": "Kiszolgáló beállítások", - "@serverSettings": {}, - "serverStart": "A kiszolgálónak http(s) kezdetűnek kell lennie", - "@serverStart": {}, - "settings": "Beállítások", - "@settings": {}, - "serverInstance": "Kiszolgáló példány", - "@serverInstance": {}, - "serverNotConnected": "Kiszolgáló nem csatlakozik", - "@serverNotConnected": {}, - "sounds": "Hangok", - "@sounds": {}, - "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", - "@soundOnServerError": {}, - "status": "Állapot", - "@status": {}, - "statusCode": "Állapot kód", - "@statusCode": {}, - "stock": "Készlet", - "@stock": { - "description": "stock" - }, - "stockDetails": "Jelenleg elérhető készlet mennyiség", - "@stockDetails": {}, - "stockItem": "Készlet tétel", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Készlet tételek", - "@stockItems": {}, - "stockItemCreate": "Új készlet tétel", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Új készlet tétel létrehozása ezen a helyen", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Készlet tétel törlése", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Biztosan törölni szeretnéd ezt a készlet tételt?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Készlet tétel nem törölhető", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Készlet tétel törölve", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Készlettörténet", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Készlettörténet megjelenítése", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Készlet áthelyezve", - "@stockItemTransferred": {}, - "stockItemUpdated": "Készlet tétel feltöltve", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Nincs elérhető készlet", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Készlet tétel megjegyzések", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Készlet tétel feltöltve", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Készlet tétel módosítása sikertelen", - "@stockItemUpdateFailure": {}, - "stockLocation": "Készlet hely", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Készlethelyek", - "@stockLocations": {}, - "stockTopLevel": "Legfelső szintű készlet hely", - "@stockTopLevel": {}, - "strictHttps": "Kizárólag HTTPS használata", - "@strictHttps": {}, - "strictHttpsDetails": "HTTPS tanúsítványok szigorú ellenőrzése", - "@strictHttpsDetails": {}, - "subcategory": "Alkategória", - "@subcategory": {}, - "subcategories": "Alkategóriák", - "@subcategories": {}, - "sublocation": "Alhely", - "@sublocation": {}, - "sublocations": "Alhelyek", - "@sublocations": {}, - "sublocationNone": "Nincsenek alhelyek", - "@sublocationNone": {}, - "sublocationNoneDetail": "Nincsenek elérhető alhelyek", - "@sublocationNoneDetail": {}, - "submitFeedback": "Visszajelzés Küldése", - "@submitFeedback": {}, - "suppliedParts": "Szállított alkatrészek", - "@suppliedParts": {}, - "supplier": "Beszállító", - "@supplier": {}, - "suppliers": "Beszállítók", - "@suppliers": {}, - "supplierReference": "Beszállítói azonosító", - "@supplierReference": {}, - "takePicture": "Fotó készítése", - "@takePicture": {}, - "targetDate": "Cél dátum", - "@targetDate": {}, - "templatePart": "Szülő sablon alkatrész", - "@templatePart": {}, - "testName": "Teszt neve", - "@testName": {}, - "testPassedOrFailed": "Teszt sikeres vagy sikertelen", - "@testPassedOrFailed": {}, - "testsRequired": "Szükséges tesztek", - "@testsRequired": {}, - "testResults": "Teszt eredmények", - "@testResults": { - "description": "" - }, - "testResultAdd": "Teszt eredmény hozzáadása", - "@testResultAdd": {}, - "testResultNone": "Nincsenek teszt eredmények", - "@testResultNone": {}, - "testResultNoneDetail": "Teszt eredmény nem áll rendelkezésre", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Hiba a teszt eredmény feltöltése közben", - "@testResultUploadFail": {}, - "testResultUploadPass": "Teszt eredmény feltöltve", - "@testResultUploadPass": {}, - "timeout": "Időtúllépés", - "@timeout": { - "description": "" - }, - "tokenError": "Token hiba", - "@tokenError": {}, - "tokenMissing": "Hiányzó token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", - "@tokenMissingFromResponse": {}, - "transfer": "Áthelyezés", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Készlet áthelyezése", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Fordítás", - "@translate": {}, - "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", - "@translateHelp": {}, - "units": "Mértékegységek", - "@units": {}, - "unknownResponse": "Ismeretlen válasz", - "@unknownResponse": {}, - "upload": "Feltöltés", - "@upload": {}, - "uploadFailed": "Fájl feltöltése sikertelen", - "@uploadFailed": {}, - "uploadSuccess": "Fájl feltöltve", - "@uploadSuccess": {}, - "usedIn": "Felhasználva ebben", - "@usedIn": {}, - "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", - "@usedInDetails": {}, - "username": "Felhasználónév", - "@username": {}, - "usernameEmpty": "Felhasználónév nem lehet üres", - "@usernameEmpty": {}, - "value": "Érték", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Az érték nem lehet üres", - "@valueCannotBeEmpty": {}, - "valueRequired": "Érték megadása szükséges", - "@valueRequired": {}, - "version": "Verzió", - "@version": {}, - "viewSupplierPart": "Beszállítói alkatrész megtekintése", - "@viewSupplierPart": {}, - "website": "Weboldal", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb deleted file mode 100644 index c917076..0000000 --- a/lib/l10n/app_id.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "id", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb deleted file mode 100644 index 4df3b7d..0000000 --- a/lib/l10n/app_it.arb +++ /dev/null @@ -1,505 +0,0 @@ -{ - "@@locale": "it", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Info", - "@about": {}, - "accountDetails": "Dettagli account", - "@accountDetails": {}, - "actions": "Azioni", - "@actions": { - "description": "" - }, - "actionsNone": "Nessuna azione disponibile", - "@actionsNone": {}, - "add": "Aggiungi", - "@add": { - "description": "add" - }, - "address": "Indirizzo", - "@address": {}, - "appAbout": "Info su InvenTree", - "@appAbout": {}, - "appCredits": "Riconoscimenti addizionali", - "@appCredits": {}, - "appDetails": "Dettagli App", - "@appDetails": {}, - "appReleaseNotes": "Mostra le note di rilascio dell'app", - "@appReleaseNotes": {}, - "appSettings": "Impostazioni App", - "@appSettings": {}, - "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", - "@appSettingsDetails": {}, - "attachments": "Allegati", - "@attachments": {}, - "attachImage": "Allega Immagine", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nessun allegato trovato", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Seleziona allegato", - "@attachmentSelect": {}, - "attention": "Attenzione", - "@attention": {}, - "barcodeAssign": "Assegna Codice A Barre", - "@barcodeAssign": {}, - "barcodeAssigned": "Codice a barre assegnato", - "@barcodeAssigned": {}, - "barcodeError": "Errore scansione codice a barre", - "@barcodeError": {}, - "barcodeInUse": "Codice a barre già in uso", - "@barcodeInUse": {}, - "barcodeMissingHash": "Dati hash codice a barre mancanti dalla risposta", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Nessuna corrispondenza per il codice a barre", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Codice a barre non assegnato", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scansiona per assegnare codice a barre", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", - "@barcodeScanIntoLocationFailure": {}, - "barcodeTones": "Toni Codice a Barre", - "@barcodeTones": {}, - "barcodeUnassign": "Deseleziona Il Barcode", - "@barcodeUnassign": {}, - "barcodeUnknown": "Codice a barre non leggibile", - "@barcodeUnknown": {}, - "batchCode": "Codice Lotto", - "@batchCode": {}, - "billOfMaterials": "Distinta materiali", - "@billOfMaterials": {}, - "bom": "Distinta materiali", - "@bom": {}, - "build": "Crea", - "@build": {}, - "cancel": "Annulla", - "@cancel": { - "description": "Cancel" - }, - "category": "Categoria", - "@category": {}, - "categoryCreate": "Nuova categoria", - "@categoryCreate": {}, - "company": "Azienda", - "@company": {}, - "companyEdit": "Modifica azienda", - "@companyEdit": {}, - "companyNoResults": "Nessuna azienda corrispondente alla query", - "@companyNoResults": {}, - "companies": "Aziende", - "@companies": {}, - "connectionRefused": "Connessione rifiutata", - "@connectionRefused": {}, - "count": "Quantità", - "@count": { - "description": "Count" - }, - "credits": "Riconoscimenti", - "@credits": {}, - "customers": "Clienti", - "@customers": {}, - "damaged": "Danneggiato", - "@damaged": {}, - "delete": "Cancella", - "@delete": {}, - "description": "Descrizione", - "@description": {}, - "destroyed": "Distrutto", - "@destroyed": {}, - "details": "Dettagli", - "@details": { - "description": "details" - }, - "documentation": "Documentazione", - "@documentation": {}, - "downloading": "File in download", - "@downloading": {}, - "downloadError": "Errore download", - "@downloadError": {}, - "edit": "Modifica", - "@edit": { - "description": "edit" - }, - "editCategory": "Modifica Categoria", - "@editCategory": {}, - "enterPassword": "Inserire la password", - "@enterPassword": {}, - "enterUsername": "Inserisci nome utente", - "@enterUsername": {}, - "error": "Errore", - "@error": { - "description": "Error" - }, - "errorCreate": "Errore nella creazione della voce del database", - "@errorCreate": {}, - "errorDetails": "Dettagli errore", - "@errorDetails": {}, - "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", - "@errorFetch": {}, - "feedback": "Commenti e suggerimenti", - "@feedback": {}, - "feedbackError": "Errore nell'invio del feedback", - "@feedbackError": {}, - "feedbackSuccess": "Feedback inviato", - "@feedbackSuccess": {}, - "formatException": "Eccezione Formato", - "@formatException": {}, - "formatExceptionJson": "Eccezione formato dati JSON", - "@formatExceptionJson": {}, - "formError": "Errore Modulo", - "@formError": {}, - "history": "Cronologia", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "imageUploadFailure": "Il caricamento della foto è fallito", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Immagine caricata", - "@imageUploadSuccess": {}, - "inactive": "Inattivo", - "@inactive": {}, - "includeSubcategories": "Includi sottocategorie", - "@includeSubcategories": {}, - "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", - "@incompleteDetails": {}, - "info": "Info", - "@info": {}, - "invalidHost": "Nome host non valido", - "@invalidHost": {}, - "invalidHostDetails": "Il nome host fornito non è valido", - "@invalidHostDetails": {}, - "invalidUsernamePassword": "Combinazione nome utente e password non valida", - "@invalidUsernamePassword": {}, - "issueDate": "Data di emissione", - "@issueDate": {}, - "itemInLocation": "Elemento già in posizione", - "@itemInLocation": {}, - "keywords": "Parole Chiave", - "@keywords": {}, - "lastUpdated": "Ultimo aggiornamento", - "@lastUpdated": {}, - "lost": "Perso", - "@lost": {}, - "manufacturers": "Produttori", - "@manufacturers": {}, - "missingData": "Dati mancanti", - "@missingData": {}, - "name": "Nome", - "@name": {}, - "notConnected": "Non connesso", - "@notConnected": {}, - "notes": "Note", - "@notes": { - "description": "Notes" - }, - "noResponse": "Nessuna risposta dal server", - "@noResponse": {}, - "noResults": "Nessun risultato", - "@noResults": {}, - "noSubcategories": "Nessuna sotto categoria", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Numero non valido", - "@numberInvalid": {}, - "onOrderDetails": "Articoli attualmente in ordine", - "@onOrderDetails": {}, - "packaging": "Confezionamento", - "@packaging": {}, - "packageName": "Nome pacchetto", - "@packageName": {}, - "parent": "Superiore", - "@parent": {}, - "parentCategory": "Categoria Superiore", - "@parentCategory": {}, - "parts": "Articoli", - "@parts": { - "description": "Part (multiple)" - }, - "partSuppliers": "Fornitori articoli", - "@partSuppliers": {}, - "password": "Password", - "@password": {}, - "passwordEmpty": "La password non può essere vuota", - "@passwordEmpty": {}, - "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", - "@permissionAccountDenied": {}, - "permissionRequired": "Autorizzazione necessaria", - "@permissionRequired": {}, - "profile": "Profilo", - "@profile": {}, - "profileAdd": "Aggiungi Profilo Server", - "@profileAdd": {}, - "profileConnect": "Connetti al Server", - "@profileConnect": {}, - "profileEdit": "Modifica il profilo del Server", - "@profileEdit": {}, - "profileDelete": "Elimina Profilo Del Server", - "@profileDelete": {}, - "profileName": "Nome Profilo", - "@profileName": {}, - "profileNone": "Nessun profilo disponibile", - "@profileNone": {}, - "profileNotSelected": "Nessun profilo selezionato", - "@profileNotSelected": {}, - "profileSelect": "Seleziona Server InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Tocca per creare o selezionare un profilo", - "@profileTapToCreate": {}, - "purchaseOrder": "Ordine d'acquisto", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Modifica ordine d'acquisto", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Ordini d'acquisto", - "@purchaseOrders": {}, - "purchasePrice": "Prezzo d'acquisto", - "@purchasePrice": {}, - "quantity": "Quantità", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Quantità vuota", - "@quantityEmpty": {}, - "quantityInvalid": "La quantità non è valida", - "@quantityInvalid": {}, - "quantityPositive": "La quantità deve essere positiva", - "@quantityPositive": {}, - "queryNoResults": "Nessun risultato per la tua ricerca", - "@queryNoResults": {}, - "received": "Ricevuto", - "@received": {}, - "receiveItem": "Ricevi Articolo", - "@receiveItem": {}, - "refresh": "Aggiorna", - "@refresh": {}, - "refreshing": "In aggiornamento", - "@refreshing": {}, - "rejected": "Respinto", - "@rejected": {}, - "releaseNotes": "Note di Rilascio", - "@releaseNotes": {}, - "remove": "Rimuovi", - "@remove": { - "description": "remove" - }, - "reportBug": "Segnala un bug", - "@reportBug": {}, - "results": "Risultati", - "@results": {}, - "request": "Richiesta", - "@request": {}, - "requestingData": "Dati in richiesta", - "@requestingData": {}, - "required": "Richiesto", - "@required": { - "description": "This field is required" - }, - "response400": "Richiesta non valida", - "@response400": {}, - "response401": "Non Autorizzato", - "@response401": {}, - "response403": "Permesso negato", - "@response403": {}, - "response404": "Risorsa non trovata", - "@response404": {}, - "response405": "Metodo non consentito", - "@response405": {}, - "response429": "Troppe richieste", - "@response429": {}, - "response500": "Errore Interno del Server", - "@response500": {}, - "response501": "Non implementato", - "@response501": {}, - "response502": "Gateway Errato", - "@response502": {}, - "response503": "Servizio Non Disponibile", - "@response503": {}, - "response504": "Timeout del gateway", - "@response504": {}, - "response505": "Versione HTTP non supportata", - "@response505": {}, - "responseData": "Dati risposta", - "@responseData": {}, - "responseInvalid": "Codice Risposta Non Valido", - "@responseInvalid": {}, - "responseUnknown": "Risposta Sconosciuta", - "@responseUnknown": {}, - "result": "Risultato", - "@result": { - "description": "" - }, - "returned": "Restituito", - "@returned": {}, - "salesOrders": "Ordini di vendita", - "@salesOrders": {}, - "save": "Salva", - "@save": { - "description": "Save" - }, - "scanBarcode": "Scansiona codice a barre", - "@scanBarcode": {}, - "search": "Cerca", - "@search": { - "description": "search" - }, - "select": "Seleziona", - "@select": {}, - "selectFile": "Seleziona file", - "@selectFile": {}, - "selectImage": "Seleziona un'immagine", - "@selectImage": {}, - "send": "Invia", - "@send": {}, - "serialNumber": "Numero seriale", - "@serialNumber": {}, - "server": "Server", - "@server": {}, - "serverAddress": "Indirizzo del server", - "@serverAddress": {}, - "serverApiRequired": "Versione API Richiesta", - "@serverApiRequired": {}, - "serverApiVersion": "Versione API Server", - "@serverApiVersion": {}, - "serverAuthenticationError": "Errore di autenticazione", - "@serverAuthenticationError": {}, - "serverCertificateError": "Errore certificato", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Il certificato del server non è valido", - "@serverCertificateInvalid": {}, - "serverConnected": "Connesso al Server", - "@serverConnected": {}, - "serverConnecting": "Connessione al server", - "@serverConnecting": {}, - "serverCouldNotConnect": "Impossibile connettersi al server", - "@serverCouldNotConnect": {}, - "serverEmpty": "Nome server non può essere vuoto", - "@serverEmpty": {}, - "serverError": "Errore del server", - "@serverError": {}, - "serverDetails": "Dettagli del server", - "@serverDetails": {}, - "serverMissingData": "Dati mancanti nella risposta del server", - "@serverMissingData": {}, - "serverOld": "Versione Vecchia Del Server", - "@serverOld": {}, - "serverSettings": "Impostazioni Server", - "@serverSettings": {}, - "serverStart": "Il server deve iniziare con http[s]", - "@serverStart": {}, - "settings": "Impostazioni", - "@settings": {}, - "serverInstance": "Istanza Del Server", - "@serverInstance": {}, - "serverNotConnected": "Server non connesso", - "@serverNotConnected": {}, - "sounds": "Audio", - "@sounds": {}, - "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Riproduci il tono sonoro su un errore del server", - "@soundOnServerError": {}, - "status": "Stato", - "@status": {}, - "statusCode": "Codice di stato", - "@statusCode": {}, - "stock": "Magazzino", - "@stock": { - "description": "stock" - }, - "subcategory": "Sottocategoria", - "@subcategory": {}, - "subcategories": "Sottocategorie", - "@subcategories": {}, - "submitFeedback": "Invia feedback", - "@submitFeedback": {}, - "supplier": "Fornitore", - "@supplier": {}, - "suppliers": "Fornitori", - "@suppliers": {}, - "supplierReference": "Riferimento fornitore", - "@supplierReference": {}, - "takePicture": "Scatta Foto", - "@takePicture": {}, - "testName": "Nome del test", - "@testName": {}, - "testPassedOrFailed": "Test superato o fallito", - "@testPassedOrFailed": {}, - "testsRequired": "Test Richiesti", - "@testsRequired": {}, - "testResults": "Risultati del test", - "@testResults": { - "description": "" - }, - "testResultAdd": "Aggiungi Risultato Test", - "@testResultAdd": {}, - "testResultNone": "Nessun Risultato Del Test", - "@testResultNone": {}, - "testResultNoneDetail": "Nessun risultato del test disponibile", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Errore nel caricamento del risultato del test", - "@testResultUploadFail": {}, - "testResultUploadPass": "Risultato del test caricato", - "@testResultUploadPass": {}, - "timeout": "Tempo Scaduto", - "@timeout": { - "description": "" - }, - "tokenError": "Errore Token", - "@tokenError": {}, - "tokenMissing": "Token Mancante", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", - "@tokenMissingFromResponse": {}, - "transfer": "Trasferisci", - "@transfer": { - "description": "transfer" - }, - "translate": "Traduci", - "@translate": {}, - "translateHelp": "Aiuta a tradurre l'app InvenTree", - "@translateHelp": {}, - "units": "Unità", - "@units": {}, - "unknownResponse": "Risposta Sconosciuta", - "@unknownResponse": {}, - "upload": "Carica", - "@upload": {}, - "uploadFailed": "Caricamento di file non riuscito", - "@uploadFailed": {}, - "uploadSuccess": "File caricato", - "@uploadSuccess": {}, - "usedIn": "Viene utilizzato in", - "@usedIn": {}, - "username": "Nome utente", - "@username": {}, - "usernameEmpty": "Il nome utente non può essere vuoto", - "@usernameEmpty": {}, - "value": "Valore", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Il valore non può essere vuoto", - "@valueCannotBeEmpty": {}, - "valueRequired": "È richiesto un valore", - "@valueRequired": {}, - "version": "Versione", - "@version": {}, - "viewSupplierPart": "Visualizza Fornitore", - "@viewSupplierPart": {}, - "website": "Sito Web", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb deleted file mode 100644 index c55ad78..0000000 --- a/lib/l10n/app_ja.arb +++ /dev/null @@ -1,682 +0,0 @@ -{ - "@@locale": "ja", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "概要", - "@about": {}, - "accountDetails": "アカウントの詳細", - "@accountDetails": {}, - "actions": "アクション", - "@actions": { - "description": "" - }, - "actionsNone": "利用可能なアクションはありません", - "@actionsNone": {}, - "add": "追加", - "@add": { - "description": "add" - }, - "addStock": "在庫を追加", - "@addStock": { - "description": "add stock" - }, - "address": "アドレス", - "@address": {}, - "appAbout": "InvenTree について", - "@appAbout": {}, - "appCredits": "すぺしゃる★さんくす!", - "@appCredits": {}, - "appDetails": "アプリ詳細", - "@appDetails": {}, - "appReleaseNotes": "アプリのリリースノートを表示", - "@appReleaseNotes": {}, - "appSettings": "アプリ設定", - "@appSettings": {}, - "appSettingsDetails": "アプリ設定を構成します", - "@appSettingsDetails": {}, - "attachments": "添付ファイル", - "@attachments": {}, - "attachImage": "画像を添付", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "添付ファイルが見つかりません。", - "@attachmentNone": {}, - "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "添付ファイルを選択", - "@attachmentSelect": {}, - "attention": "注意", - "@attention": {}, - "availableStock": "在庫あり", - "@availableStock": {}, - "barcodeAssign": "バーコードを割り当てる", - "@barcodeAssign": {}, - "barcodeAssigned": "バーコードが割り当てられました", - "@barcodeAssigned": {}, - "barcodeError": "バーコードのスキャンエラー", - "@barcodeError": {}, - "barcodeInUse": "バーコードは既に割り当てられています", - "@barcodeInUse": {}, - "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "バーコードが一致しません", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "バーコードが割り当てられていません", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "スキャンしてバーコードを割り当てます", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "InvenTree バーコードをスキャンする", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "在庫アイテムを在庫場所にスキャン", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "在庫場所をスキャン", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "在庫アイテムをスキャン", - "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", - "@barcodeTones": {}, - "barcodeUnassign": "バーコードの割り当てを解除", - "@barcodeUnassign": {}, - "barcodeUnknown": "バーコードが認識されません", - "@barcodeUnknown": {}, - "billOfMaterials": "Bill of Materials", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "ビルド", - "@build": {}, - "building": "ビルド", - "@building": {}, - "cancel": "キャンセル", - "@cancel": { - "description": "Cancel" - }, - "category": "カテゴリ", - "@category": {}, - "categoryCreate": "新規カテゴリ", - "@categoryCreate": {}, - "categoryCreateDetail": "新しい部品カテゴリを作成", - "@categoryCreateDetail": {}, - "categoryUpdated": "部品カテゴリを更新しました", - "@categoryUpdated": {}, - "company": "会社", - "@company": {}, - "companyEdit": "会社を編集", - "@companyEdit": {}, - "companyNoResults": "検索条件に一致する会社はありません", - "@companyNoResults": {}, - "companyUpdated": "会社の詳細を更新しました", - "@companyUpdated": {}, - "companies": "会社", - "@companies": {}, - "configureServer": "サーバー設定", - "@configureServer": {}, - "connectionRefused": "接続を拒否しました", - "@connectionRefused": {}, - "count": "カウント", - "@count": { - "description": "Count" - }, - "countStock": "在庫数", - "@countStock": { - "description": "Count Stock" - }, - "credits": "謝辞", - "@credits": {}, - "customers": "顧客", - "@customers": {}, - "damaged": "破損", - "@damaged": {}, - "delete": "削除", - "@delete": {}, - "deletePart": "部品を削除", - "@deletePart": {}, - "deletePartDetail": "データベースからこの部品を削除します", - "@deletePartDetail": {}, - "description": "説明", - "@description": {}, - "destroyed": "破壊", - "@destroyed": {}, - "details": "詳細", - "@details": { - "description": "details" - }, - "documentation": "ドキュメント", - "@documentation": {}, - "downloading": "ファイルをダウンロード中", - "@downloading": {}, - "downloadError": "ダウンロードエラー", - "@downloadError": {}, - "edit": "編集", - "@edit": { - "description": "edit" - }, - "editCategory": "カテゴリの編集", - "@editCategory": {}, - "editLocation": "在庫場所を編集", - "@editLocation": {}, - "editNotes": "メモを編集", - "@editNotes": {}, - "editPart": "パートの編集", - "@editPart": { - "description": "edit part" - }, - "editItem": "在庫商品を編集", - "@editItem": {}, - "enterPassword": "パスワードを入力してください", - "@enterPassword": {}, - "enterUsername": "ユーザー名を入力してください", - "@enterUsername": {}, - "error": "エラー", - "@error": { - "description": "Error" - }, - "errorCreate": "データベースの作成中にエラーが発生しました", - "@errorCreate": {}, - "errorDelete": "データベースの削除中にエラーが発生しました", - "@errorDelete": {}, - "errorDetails": "エラーの詳細", - "@errorDetails": {}, - "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", - "@errorFetch": {}, - "errorReporting": "エラー報告", - "@errorReporting": {}, - "errorReportUpload": "エラー報告をアップロード", - "@errorReportUpload": {}, - "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", - "@errorReportUploadDetails": {}, - "feedback": "フィードバック", - "@feedback": {}, - "feedbackError": "フィードバックの送信エラー", - "@feedbackError": {}, - "feedbackSuccess": "フィードバックが送信されました", - "@feedbackSuccess": {}, - "formatException": "フォーマットの例外エラー", - "@formatException": {}, - "formatExceptionJson": "JSONデータフォーマット例外エラー", - "@formatExceptionJson": {}, - "formError": "フォームエラー", - "@formError": {}, - "history": "履歴", - "@history": { - "description": "history" - }, - "homeScreen": "ホーム画面", - "@homeScreen": {}, - "homeScreenSettings": "ホーム画面の設定", - "@homeScreenSettings": {}, - "homeShowPo": "注文書を表示", - "@homeShowPo": {}, - "homeShowSubscribed": "購読済みのパーツ", - "@homeShowSubscribed": {}, - "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "仕入先を表示", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "メーカーを表示", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "顧客を表示", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "画像のアップロードに失敗しました", - "@imageUploadFailure": {}, - "imageUploadSuccess": "アップロードされた画像", - "@imageUploadSuccess": {}, - "inactive": "無効", - "@inactive": {}, - "inactiveDetail": "この部品は無効としてマークされています", - "@inactiveDetail": {}, - "includeSubcategories": "サブカテゴリを含む", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "サブカテゴリをリストビューに表示します", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "サブ在庫場所を含める", - "@includeSublocations": {}, - "includeSublocationsDetail": "サブ在庫場所を表示します", - "@includeSublocationsDetail": {}, - "incompleteDetails": "不完全なプロフィールの詳細", - "@incompleteDetails": {}, - "internalPartNumber": "内部パーツ番号", - "@internalPartNumber": {}, - "info": "情報", - "@info": {}, - "inProduction": "生産中", - "@inProduction": {}, - "inProductionDetail": "この在庫品は生産中です", - "@inProductionDetail": {}, - "invalidHost": "無効なホスト名", - "@invalidHost": {}, - "invalidHostDetails": "このホスト名は無効です。", - "@invalidHostDetails": {}, - "invalidPart": "無効なパーツ", - "@invalidPart": {}, - "invalidPartCategory": "無効なパーツカテゴリー", - "@invalidPartCategory": {}, - "invalidStockLocation": "無効な在庫場所", - "@invalidStockLocation": {}, - "invalidStockItem": "無効な在庫アイテム", - "@invalidStockItem": {}, - "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", - "@invalidUsernamePassword": {}, - "issueDate": "発行日", - "@issueDate": {}, - "itemInLocation": "アイテムは既に在庫場所にあります", - "@itemInLocation": {}, - "keywords": "キーワード", - "@keywords": {}, - "lastUpdated": "最終更新", - "@lastUpdated": {}, - "locationCreate": "新しい場所", - "@locationCreate": {}, - "locationCreateDetail": "新しい在庫場所を作成", - "@locationCreateDetail": {}, - "locationNotSet": "在庫場所が指定されていません", - "@locationNotSet": {}, - "locationUpdated": "在庫場所を更新しました", - "@locationUpdated": {}, - "link": "リンク", - "@link": {}, - "lost": "損失", - "@lost": {}, - "missingData": "データ消失", - "@missingData": {}, - "name": "名前", - "@name": {}, - "notConnected": "接続されていません", - "@notConnected": {}, - "notes": "メモ", - "@notes": { - "description": "Notes" - }, - "noResponse": "サーバーからの応答がありません", - "@noResponse": {}, - "noResults": "一致する結果なし", - "@noResults": {}, - "noSubcategories": "サブカテゴリはありません", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "無効な値", - "@numberInvalid": {}, - "onOrder": "注文中", - "@onOrder": {}, - "packaging": "梱包中", - "@packaging": {}, - "packageName": "パッケージ名", - "@packageName": {}, - "parent": "親", - "@parent": {}, - "parentCategory": "親カテゴリ", - "@parentCategory": {}, - "parentLocation": "上位の場所", - "@parentLocation": {}, - "part": "パーツ", - "@part": { - "description": "Part (single)" - }, - "parts": "パーツ", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "パーツがありません", - "@partsNone": {}, - "partsStarredNone": "お気に入りのパーツはありません", - "@partsStarredNone": {}, - "partCategory": "パーツカテゴリー", - "@partCategory": {}, - "partCategoryTopLevel": "トップレベルのパーツカテゴリ", - "@partCategoryTopLevel": {}, - "partCategories": "パーツカテゴリー", - "@partCategories": {}, - "partDetails": "パーツ詳細", - "@partDetails": {}, - "partNotes": "パーツメモ", - "@partNotes": {}, - "partStock": "パーツ在庫:", - "@partStock": { - "description": "part stock" - }, - "password": "パスワード", - "@password": {}, - "passwordEmpty": "パスワードは空欄にできません。", - "@passwordEmpty": {}, - "permissionAccountDenied": "操作を行う権限がありません", - "@permissionAccountDenied": {}, - "permissionRequired": "権限が必要です", - "@permissionRequired": {}, - "printLabel": "ラベルを印刷", - "@printLabel": {}, - "printLabelFailure": "ラベルの印刷に失敗しました", - "@printLabelFailure": {}, - "printLabelSuccess": "ラベルをプリンタに送信しました", - "@printLabelSuccess": {}, - "profile": "プロフィール", - "@profile": {}, - "profileAdd": "サーバープロファイルを追加", - "@profileAdd": {}, - "profileConnect": "サーバーに接続", - "@profileConnect": {}, - "profileEdit": "サーバープロファイルを編集", - "@profileEdit": {}, - "profileDelete": "サーバープロファイルの削除", - "@profileDelete": {}, - "profileName": "プロファイル名", - "@profileName": {}, - "profileNone": "利用可能なプロファイルがありません", - "@profileNone": {}, - "profileNotSelected": "プロフィールが選択されていません", - "@profileNotSelected": {}, - "profileSelect": "InvenTreeサーバーを選択", - "@profileSelect": {}, - "profileTapToCreate": "タップしてプロフィールを作成または選択します", - "@profileTapToCreate": {}, - "purchaseOrder": "発注書", - "@purchaseOrder": {}, - "purchaseOrderEdit": "発注書の更新", - "@purchaseOrderEdit": {}, - "purchaseOrders": "発注書", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "発注書が更新されました", - "@purchaseOrderUpdated": {}, - "purchasePrice": "購入金額", - "@purchasePrice": {}, - "quantity": "数量", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "数量が空です", - "@quantityEmpty": {}, - "quantityInvalid": "数量が無効です", - "@quantityInvalid": {}, - "quantityPositive": "数量は1以上", - "@quantityPositive": {}, - "queryNoResults": "検索結果はありません", - "@queryNoResults": {}, - "refresh": "更新", - "@refresh": {}, - "refreshing": "更新中", - "@refreshing": {}, - "rejected": "却下済み", - "@rejected": {}, - "releaseNotes": "リリースノート", - "@releaseNotes": {}, - "remove": "削除", - "@remove": { - "description": "remove" - }, - "removeStock": "在庫を削除", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "不具合の報告", - "@reportBug": {}, - "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", - "@reportBugDescription": {}, - "results": "結果", - "@results": {}, - "request": "リクエスト", - "@request": {}, - "requestingData": "データをリクエスト中", - "@requestingData": {}, - "required": "必須", - "@required": { - "description": "This field is required" - }, - "response400": "不正なリクエスト", - "@response400": {}, - "response401": "認証されていません", - "@response401": {}, - "response403": "権限がありません", - "@response403": {}, - "response404": "リソースが見つかりません", - "@response404": {}, - "response405": "メソッドが許可されていません", - "@response405": {}, - "response429": "リクエストが多すぎます", - "@response429": {}, - "response501": "未実装", - "@response501": {}, - "response503": "サービスは利用できません", - "@response503": {}, - "response505": "このHTTP バージョンはサポートされていません", - "@response505": {}, - "responseData": "応答データ", - "@responseData": {}, - "responseInvalid": "無効な応答", - "@responseInvalid": {}, - "responseUnknown": "不明な応答コード", - "@responseUnknown": {}, - "result": "結果", - "@result": { - "description": "" - }, - "returned": "返品済", - "@returned": {}, - "save": "保存", - "@save": { - "description": "Save" - }, - "scanBarcode": "バーコードをスキャン", - "@scanBarcode": {}, - "scanIntoLocation": "スキャンされた在庫場所", - "@scanIntoLocation": {}, - "search": "検索", - "@search": { - "description": "search" - }, - "searchLocation": "在庫場所場所を検索", - "@searchLocation": {}, - "searchParts": "パーツの検索", - "@searchParts": {}, - "searchStock": "在庫を検索", - "@searchStock": {}, - "select": "選択", - "@select": {}, - "selectFile": "ファイルを選択", - "@selectFile": {}, - "selectImage": "画像を選択", - "@selectImage": {}, - "selectLocation": "在庫場所を選択", - "@selectLocation": {}, - "send": "送信", - "@send": {}, - "serialNumber": "シリアルナンバー", - "@serialNumber": {}, - "server": "サーバー", - "@server": {}, - "serverAddress": "サーバーアドレス:", - "@serverAddress": {}, - "serverApiRequired": "必要なAPIバージョン", - "@serverApiRequired": {}, - "serverApiVersion": "サーバー API バージョン", - "@serverApiVersion": {}, - "serverAuthenticationError": "認証エラー", - "@serverAuthenticationError": {}, - "serverCertificateError": "認証エラー", - "@serverCertificateError": {}, - "serverCertificateInvalid": "サーバー HTTPS 証明書が無効です", - "@serverCertificateInvalid": {}, - "serverConnected": "サーバへ接続しました\n", - "@serverConnected": {}, - "serverConnecting": "サーバに接続中", - "@serverConnecting": {}, - "serverCouldNotConnect": "サーバーに接続できませんでした", - "@serverCouldNotConnect": {}, - "serverError": "サーバーエラー", - "@serverError": {}, - "serverDetails": "サーバの詳細", - "@serverDetails": {}, - "serverOld": "旧サーバーのバージョン", - "@serverOld": {}, - "serverSettings": "サーバー設定:", - "@serverSettings": {}, - "serverStart": "サーバーは http[s] で開始する必要があります", - "@serverStart": {}, - "settings": "設定", - "@settings": {}, - "serverInstance": "サーバインスタンス", - "@serverInstance": {}, - "serverNotConnected": "サーバーに接続されていません", - "@serverNotConnected": {}, - "sounds": "サウンド", - "@sounds": {}, - "soundOnBarcodeAction": "バーコード動作で音を鳴らす", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "サーバーのエラー時に音を鳴らす", - "@soundOnServerError": {}, - "status": "ステータス", - "@status": {}, - "statusCode": "ステータスコード", - "@statusCode": {}, - "stock": "在庫", - "@stock": { - "description": "stock" - }, - "stockItem": "在庫アイテム", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "在庫アイテム", - "@stockItems": {}, - "stockItemCreate": "新しい在庫アイテム", - "@stockItemCreate": {}, - "stockItemCreateDetail": "この場所に新しい在庫アイテムを作成", - "@stockItemCreateDetail": {}, - "stockItemDelete": "在庫アイテムを削除", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "この在庫アイテムを削除しますか?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "在庫アイテムを削除できませんでした。", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "在庫アイテムを削除しました", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "在庫履歴", - "@stockItemHistory": {}, - "stockItemTransferred": "在庫アイテムが転送されました", - "@stockItemTransferred": {}, - "stockItemUpdated": "在庫アイテムが更新されました", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "在庫アイテムがありません", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "在庫アイテムメモ", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "在庫アイテムが更新されました", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", - "@stockItemUpdateFailure": {}, - "stockLocation": "在庫場所", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "在庫場所", - "@stockLocations": {}, - "stockTopLevel": "トップレベルの在庫場所", - "@stockTopLevel": {}, - "strictHttps": "厳格なHTTPSを使用", - "@strictHttps": {}, - "subcategory": "サブカテゴリー", - "@subcategory": {}, - "subcategories": "サブカテゴリー", - "@subcategories": {}, - "sublocation": "サブ在庫場所", - "@sublocation": {}, - "sublocations": "サブ在庫場所", - "@sublocations": {}, - "sublocationNone": "サブ在庫場所がありません", - "@sublocationNone": {}, - "sublocationNoneDetail": "利用可能なサブ在庫場所がありません", - "@sublocationNoneDetail": {}, - "submitFeedback": "フィードバックを送信", - "@submitFeedback": {}, - "supplier": "サプライヤー", - "@supplier": {}, - "suppliers": "サプライヤー", - "@suppliers": {}, - "takePicture": "画像を撮影", - "@takePicture": {}, - "templatePart": "上位テンプレートパーツ", - "@templatePart": {}, - "testName": "テスト名", - "@testName": {}, - "testPassedOrFailed": "テストの合格または失敗", - "@testPassedOrFailed": {}, - "testsRequired": "必須テスト", - "@testsRequired": {}, - "testResults": "テスト結果", - "@testResults": { - "description": "" - }, - "testResultAdd": "テスト結果を追加", - "@testResultAdd": {}, - "testResultNone": "テスト結果がありません", - "@testResultNone": {}, - "testResultNoneDetail": "利用可能なテスト結果がありません", - "@testResultNoneDetail": {}, - "testResultUploadFail": "テスト結果のアップロードエラー", - "@testResultUploadFail": {}, - "testResultUploadPass": "テスト結果がアップロードされました", - "@testResultUploadPass": {}, - "timeout": "タイムアウト", - "@timeout": { - "description": "" - }, - "tokenError": "トークンエラー", - "@tokenError": {}, - "tokenMissing": "トークンがありません", - "@tokenMissing": {}, - "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", - "@tokenMissingFromResponse": {}, - "transfer": "転送", - "@transfer": { - "description": "transfer" - }, - "transferStock": "在庫の転送", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "翻訳", - "@translate": {}, - "translateHelp": "InvenTree アプリの翻訳に協力する", - "@translateHelp": {}, - "units": "単位", - "@units": {}, - "unknownResponse": "不明な応答", - "@unknownResponse": {}, - "upload": "アップロード", - "@upload": {}, - "uploadFailed": "ファイルのアップロードに失敗しました。", - "@uploadFailed": {}, - "uploadSuccess": "アップロードされたファイル", - "@uploadSuccess": {}, - "username": "ユーザー名", - "@username": {}, - "usernameEmpty": "ユーザー名は空にできません。", - "@usernameEmpty": {}, - "value": "設定値", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "値を空にすることはできません。", - "@valueCannotBeEmpty": {}, - "valueRequired": "値が必要です", - "@valueRequired": {}, - "version": "バージョン", - "@version": {}, - "website": "Webサイト", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb deleted file mode 100644 index 0bc359b..0000000 --- a/lib/l10n/app_ko.arb +++ /dev/null @@ -1,105 +0,0 @@ -{ - "@@locale": "ko", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "add": "추가", - "@add": { - "description": "add" - }, - "address": "주소", - "@address": {}, - "appAbout": "InvenTree 소개", - "@appAbout": {}, - "appReleaseNotes": "앱 릴리즈 노트 표시", - "@appReleaseNotes": {}, - "appSettings": "앱 설정", - "@appSettings": {}, - "billOfMaterials": "부품 명세서", - "@billOfMaterials": {}, - "cancel": "취소", - "@cancel": { - "description": "Cancel" - }, - "company": "회사", - "@company": {}, - "companyEdit": "회사 수정", - "@companyEdit": {}, - "error": "오류", - "@error": { - "description": "Error" - }, - "errorDetails": "오류 세부 정보", - "@errorDetails": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "keywords": "키워드", - "@keywords": {}, - "noResults": "결과 없음", - "@noResults": {}, - "password": "비밀번호", - "@password": {}, - "passwordEmpty": "비밀번호는 비워둘 수 없습니다", - "@passwordEmpty": {}, - "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", - "@permissionAccountDenied": {}, - "profileConnect": "서버에 연결", - "@profileConnect": {}, - "quantity": "수량", - "@quantity": { - "description": "Quantity" - }, - "reportBug": "버그 신고", - "@reportBug": {}, - "response505": "지원되지 않는 HTTP 버전", - "@response505": {}, - "save": "저장", - "@save": { - "description": "Save" - }, - "select": "선택", - "@select": {}, - "selectFile": "파일 선택", - "@selectFile": {}, - "server": "서버", - "@server": {}, - "serverAddress": "서버 주소", - "@serverAddress": {}, - "serverApiRequired": "필요한 API 버전", - "@serverApiRequired": {}, - "serverApiVersion": "서버 API 버전", - "@serverApiVersion": {}, - "serverAuthenticationError": "인증 오류", - "@serverAuthenticationError": {}, - "serverConnecting": "서버에 연결하는 중", - "@serverConnecting": {}, - "serverError": "서버 오류", - "@serverError": {}, - "serverOld": "오래된 서버 버전", - "@serverOld": {}, - "serverSettings": "서버 설정", - "@serverSettings": {}, - "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", - "@serverStart": {}, - "status": "상태", - "@status": {}, - "statusCode": "상태 코드", - "@statusCode": {}, - "targetDate": "목표 날짜", - "@targetDate": {}, - "timeout": "시간 초과", - "@timeout": { - "description": "" - }, - "tokenError": "토큰 오류", - "@tokenError": {}, - "translate": "번역", - "@translate": {}, - "translateHelp": "InvenTree 앱의 번역을 도와주세요", - "@translateHelp": {}, - "version": "버전", - "@version": {}, - "website": "웹사이트", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb deleted file mode 100644 index 40c32de..0000000 --- a/lib/l10n/app_nl.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "nl", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_no.arb b/lib/l10n/app_no.arb deleted file mode 100644 index 34df543..0000000 --- a/lib/l10n/app_no.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "no", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb deleted file mode 100644 index 4274486..0000000 --- a/lib/l10n/app_pl.arb +++ /dev/null @@ -1,739 +0,0 @@ -{ - "@@locale": "pl", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "O nas", - "@about": {}, - "accountDetails": "Szczegóły konta", - "@accountDetails": {}, - "actions": "Działania", - "@actions": { - "description": "" - }, - "actionsNone": "Brak dostępnych działań", - "@actionsNone": {}, - "add": "Dodaj", - "@add": { - "description": "add" - }, - "addStock": "Dodaj stan", - "@addStock": { - "description": "add stock" - }, - "address": "Adresy", - "@address": {}, - "appAbout": "O InvenTree", - "@appAbout": {}, - "appCredits": "Dodatkowe podziękowania autorskie", - "@appCredits": {}, - "appDetails": "Szczegóły aplikacji", - "@appDetails": {}, - "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", - "@appReleaseNotes": {}, - "appSettings": "Ustawienia aplikacji", - "@appSettings": {}, - "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", - "@appSettingsDetails": {}, - "attachments": "Załączniki", - "@attachments": {}, - "attachImage": "Dodaj zdjęcie", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Nie znaleziono załączników", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Brak załączników dla tego komponentu", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Wybierz załącznik", - "@attachmentSelect": {}, - "attention": "Uwaga", - "@attention": {}, - "barcodeAssign": "Przypisz kod kreskowy", - "@barcodeAssign": {}, - "barcodeAssigned": "Kod kreskowy przypisany", - "@barcodeAssigned": {}, - "barcodeError": "Błąd czytnika kodów kreskowych", - "@barcodeError": {}, - "barcodeInUse": "Kod kreskowy jest już przypisany", - "@barcodeInUse": {}, - "barcodeMissingHash": "Brak danych haszujących w odpowiedzi kodu kreskowego", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Brak dopasowania dla kodu kreskowego", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Kod kreskowy nieprzypisany", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Zeskanuj przedmioty do lokalizacji", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Skanuj lokalizację zapasów", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Skanuj element magazynowy", - "@barcodeScanItem": {}, - "barcodeTones": "Dźwięki kodów kreskowych", - "@barcodeTones": {}, - "barcodeUnassign": "Nieprzydzielony kod kreskowy", - "@barcodeUnassign": {}, - "barcodeUnknown": "Nie rozpoznano kodu kreskowego", - "@barcodeUnknown": {}, - "batchCode": "Kod partii", - "@batchCode": {}, - "billOfMaterials": "Zestawienie materiałów", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Budowa", - "@build": {}, - "building": "Budowanie", - "@building": {}, - "cancel": "Anuluj", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategoria", - "@category": {}, - "categoryCreate": "Nowa Kategoria", - "@categoryCreate": {}, - "categoryCreateDetail": "Utwórz nową kategorię komponentu", - "@categoryCreateDetail": {}, - "categoryUpdated": "Kategoria części została zmieniona", - "@categoryUpdated": {}, - "company": "Firma", - "@company": {}, - "companyEdit": "Edytuj Firmę", - "@companyEdit": {}, - "companyNoResults": "Brak firm pasujących do zapytania", - "@companyNoResults": {}, - "companyUpdated": "Szczegóły firmy zostały zaktualizowane", - "@companyUpdated": {}, - "companies": "Firmy", - "@companies": {}, - "configureServer": "Konfiguruj ustawienia serwera", - "@configureServer": {}, - "connectionRefused": "Połączenie odrzucone", - "@connectionRefused": {}, - "count": "Ilość", - "@count": { - "description": "Count" - }, - "countStock": "Przelicz stan", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Podziękowania", - "@credits": {}, - "customers": "Klienci", - "@customers": {}, - "damaged": "Uszkodzone", - "@damaged": {}, - "delete": "Usuń", - "@delete": {}, - "deletePart": "Usuń Komponent", - "@deletePart": {}, - "deletePartDetail": "Usuń ten komponent z bazy danych", - "@deletePartDetail": {}, - "description": "Opis", - "@description": {}, - "destroyed": "Zniszczony", - "@destroyed": {}, - "details": "Szczegóły", - "@details": { - "description": "details" - }, - "documentation": "Dokumentacja", - "@documentation": {}, - "downloading": "Pobieranie Pliku", - "@downloading": {}, - "downloadError": "Błąd Pobierania", - "@downloadError": {}, - "edit": "Edytuj", - "@edit": { - "description": "edit" - }, - "editCategory": "Edytuj kategorię", - "@editCategory": {}, - "editLocation": "Edytuj lokację", - "@editLocation": {}, - "editNotes": "Edytuj Notatki", - "@editNotes": {}, - "editPart": "Edytuj część", - "@editPart": { - "description": "edit part" - }, - "editItem": "Edytuj Pozycję Magazynową", - "@editItem": {}, - "enterPassword": "Wprowadź hasło", - "@enterPassword": {}, - "enterUsername": "Wprowadź nazwę użytkownika", - "@enterUsername": {}, - "error": "Błąd", - "@error": { - "description": "Error" - }, - "errorCreate": "Błąd tworzenia wpisu w bazie danych", - "@errorCreate": {}, - "errorDelete": "Błąd podczas usuwania wpisu bazy danych", - "@errorDelete": {}, - "errorDetails": "Szczegóły błędu", - "@errorDetails": {}, - "errorFetch": "Błąd pobierania danych z serwea", - "@errorFetch": {}, - "errorReporting": "Raportowanie błędów", - "@errorReporting": {}, - "errorReportUpload": "Prześlij raport o błędach", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", - "@errorReportUploadDetails": {}, - "feedback": "Opinie", - "@feedback": {}, - "feedbackError": "Błąd dodawania opinii", - "@feedbackError": {}, - "feedbackSuccess": "Opinia przesłana", - "@feedbackSuccess": {}, - "formatException": "Wyjątek formatowania", - "@formatException": {}, - "formatExceptionJson": "Wyjątek formatu danych JSON", - "@formatExceptionJson": {}, - "formError": "Błąd Formularza", - "@formError": {}, - "history": "Historia", - "@history": { - "description": "history" - }, - "homeScreen": "Ekran główny", - "@homeScreen": {}, - "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", - "@homeScreenSettings": {}, - "homeShowPo": "Pokaż zamówienia zakupu", - "@homeShowPo": {}, - "homeShowSubscribed": "Obserwowane części", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Pokaż dostawców", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Pokaż producentów", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Pokaż przycisk producentów na ekranie głównym", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Pokaż klientów", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Pokaż przycisk klientów na ekranie głównym", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Przesyłanie zdjęcia nie powiodło się", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Obraz przesłany", - "@imageUploadSuccess": {}, - "inactive": "Nieaktywny", - "@inactive": {}, - "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", - "@inactiveDetail": {}, - "includeSubcategories": "Zawieraj podkategorie", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Wyświetl części z podkategorii w widoku listy", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Zawieraj sublokacje", - "@includeSublocations": {}, - "includeSublocationsDetail": "Wyświetl części z sublokacji w widoku listy", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Niekompletne szczegóły profilu", - "@incompleteDetails": {}, - "internalPartNumber": "Wewnętrzny numer części", - "@internalPartNumber": {}, - "info": "Info", - "@info": {}, - "inProduction": "W produkcji", - "@inProduction": {}, - "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", - "@inProductionDetail": {}, - "invalidHost": "Nieprawidłowa nazwa hosta", - "@invalidHost": {}, - "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", - "@invalidHostDetails": {}, - "invalidPart": "Nieprawidłowa część", - "@invalidPart": {}, - "invalidPartCategory": "Nieprawidłowa kategoria części", - "@invalidPartCategory": {}, - "invalidStockLocation": "Nieprawidłowa lokacja magazynowa", - "@invalidStockLocation": {}, - "invalidStockItem": "Nieprawidłowa część magazynowa", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Nieprawidłowy login lub hasło", - "@invalidUsernamePassword": {}, - "issueDate": "Data Wystawienia", - "@issueDate": {}, - "itemInLocation": "Część jest już w lokacji", - "@itemInLocation": {}, - "keywords": "Słowa kluczowe", - "@keywords": {}, - "lastStocktake": "Ostatnia inwentaryzacja", - "@lastStocktake": {}, - "lastUpdated": "Ostatnia aktualizacja", - "@lastUpdated": {}, - "lineItem": "Pozycja", - "@lineItem": {}, - "lineItems": "Pozycje", - "@lineItems": {}, - "locationCreate": "Nowa Lokalizacja", - "@locationCreate": {}, - "locationCreateDetail": "Utwórz nową pozycję magazynową", - "@locationCreateDetail": {}, - "locationNotSet": "Nie określono lokacji", - "@locationNotSet": {}, - "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", - "@locationUpdated": {}, - "link": "Link", - "@link": {}, - "lost": "Zagubiono", - "@lost": {}, - "manufacturers": "Producenci", - "@manufacturers": {}, - "missingData": "Brakujące dane", - "@missingData": {}, - "name": "Nazwa", - "@name": {}, - "notConnected": "Nie połączony", - "@notConnected": {}, - "notes": "Notatki", - "@notes": { - "description": "Notes" - }, - "noResponse": "Brak odpowiedzi od serwera", - "@noResponse": {}, - "noResults": "Brak wyników", - "@noResults": {}, - "noSubcategories": "Brak podkategorii", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Brak dostępnych podkategorii", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Błędny numer", - "@numberInvalid": {}, - "onOrder": "W Zamówieniu", - "@onOrder": {}, - "onOrderDetails": "Pozycje obecnie w zamówieniu", - "@onOrderDetails": {}, - "packaging": "Opakowanie", - "@packaging": {}, - "packageName": "Nazwa pakietu", - "@packageName": {}, - "parent": "Nadrzędny", - "@parent": {}, - "parentCategory": "Kategoria nadrzędna", - "@parentCategory": {}, - "parentLocation": "Lokalizacja Nadrzędna", - "@parentLocation": {}, - "part": "Część", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Nowy Komponent", - "@partCreate": {}, - "partCreateDetail": "Utwórz nowy komponent w tej kategorii", - "@partCreateDetail": {}, - "partEdited": "Część zaktualizowana", - "@partEdited": {}, - "parts": "Części", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Brak części", - "@partsNone": {}, - "partNoResults": "Brak komponentów pasujących do zapytania", - "@partNoResults": {}, - "partsStarred": "Obserwowane części", - "@partsStarred": {}, - "partsStarredNone": "Brak części oznaczonych gwiazdką", - "@partsStarredNone": {}, - "partSuppliers": "Dostawcy Części", - "@partSuppliers": {}, - "partCategory": "Kategoria części", - "@partCategory": {}, - "partCategoryTopLevel": "Kategoria części najwyższego poziomu", - "@partCategoryTopLevel": {}, - "partCategories": "Kategorie części", - "@partCategories": {}, - "partDetails": "Szczegóły części", - "@partDetails": {}, - "partNotes": "Notatki do części", - "@partNotes": {}, - "partStock": "Zapasy cześci", - "@partStock": { - "description": "part stock" - }, - "password": "Hasło", - "@password": {}, - "passwordEmpty": "Hasło nie może być puste", - "@passwordEmpty": {}, - "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", - "@permissionAccountDenied": {}, - "permissionRequired": "Wymagane uprawnienia", - "@permissionRequired": {}, - "printLabel": "Drukuj etykietę", - "@printLabel": {}, - "printLabelFailure": "Drukowanie etykiet nie powiodło się", - "@printLabelFailure": {}, - "printLabelSuccess": "Etykieta wysłana do drukarki", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Dodaj profil serwera", - "@profileAdd": {}, - "profileConnect": "Połącz się z serwerem", - "@profileConnect": {}, - "profileEdit": "Edytuj profil serwera", - "@profileEdit": {}, - "profileDelete": "Usuń profil serwera", - "@profileDelete": {}, - "profileName": "Nazwa Profilu", - "@profileName": {}, - "profileNone": "Brak dostępnych profili", - "@profileNone": {}, - "profileNotSelected": "Nie wybrano profilu", - "@profileNotSelected": {}, - "profileSelect": "Wybierz serwer InvenTree", - "@profileSelect": {}, - "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", - "@profileTapToCreate": {}, - "purchaseOrder": "Zlecenie Zakupu", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Zlecenia zakupu", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Cena Zakupu", - "@purchasePrice": {}, - "quantity": "Ilość", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Ilość jest pusta", - "@quantityEmpty": {}, - "quantityInvalid": "Ilość jest nieprawidłowa", - "@quantityInvalid": {}, - "quantityPositive": "Ilość musi być dodatnia", - "@quantityPositive": {}, - "queryNoResults": "Nie znaleziono wyników dla zapytania", - "@queryNoResults": {}, - "received": "Odebrane", - "@received": {}, - "receiveItem": "Przyjmij artykuły", - "@receiveItem": {}, - "receivedItem": "Przyjęta Pozycja Magazynowa", - "@receivedItem": {}, - "refresh": "Odśwież", - "@refresh": {}, - "refreshing": "Odświeżanie", - "@refreshing": {}, - "rejected": "Odrzucono", - "@rejected": {}, - "releaseNotes": "Lista zmian", - "@releaseNotes": {}, - "remove": "Usuń", - "@remove": { - "description": "remove" - }, - "removeStock": "Usuń stan", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Zgłoś błąd", - "@reportBug": {}, - "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", - "@reportBugDescription": {}, - "results": "Wyniki", - "@results": {}, - "request": "Żądanie", - "@request": {}, - "requestingData": "Żądanie danych", - "@requestingData": {}, - "required": "Wymagane", - "@required": { - "description": "This field is required" - }, - "response400": "Błędne żądanie", - "@response400": {}, - "response401": "Nieautoryzowany", - "@response401": {}, - "response403": "Odmowa dostępu", - "@response403": {}, - "response404": "Nie znaleziono", - "@response404": {}, - "response405": "Metoda niedozwolona", - "@response405": {}, - "response429": "Zbyt wiele żądań", - "@response429": {}, - "response500": "Wewnętrzny błąd serwera", - "@response500": {}, - "response501": "Nie zaimplementowano", - "@response501": {}, - "response502": "Zła brama", - "@response502": {}, - "response503": "Usługa niedostępna", - "@response503": {}, - "response504": "Przekroczono limit czasu", - "@response504": {}, - "response505": "Wersja HTTP nie obsługiwana", - "@response505": {}, - "responseData": "Dane odpowiedzi", - "@responseData": {}, - "responseInvalid": "Nieprawidłowy kod odpowiedzi", - "@responseInvalid": {}, - "responseUnknown": "Nieznana odpowiedź", - "@responseUnknown": {}, - "result": "Wynik", - "@result": { - "description": "" - }, - "returned": "Zwrócono", - "@returned": {}, - "salesOrders": "Zlecenia Sprzedaży", - "@salesOrders": {}, - "save": "Zapisz", - "@save": { - "description": "Save" - }, - "scanBarcode": "Skanuj kod kreskowy", - "@scanBarcode": {}, - "scanIntoLocation": "Skanuj do lokacji", - "@scanIntoLocation": {}, - "search": "Szukaj", - "@search": { - "description": "search" - }, - "searchLocation": "Wyszukaj lokalizację", - "@searchLocation": {}, - "searchParts": "Szukaj części", - "@searchParts": {}, - "searchStock": "Szukaj zapasów", - "@searchStock": {}, - "select": "Wybierz", - "@select": {}, - "selectFile": "Wybierz Plik", - "@selectFile": {}, - "selectImage": "Wybierz obraz", - "@selectImage": {}, - "selectLocation": "Wybierz lokację", - "@selectLocation": {}, - "send": "Wyślij", - "@send": {}, - "serialNumber": "Numer seryjny", - "@serialNumber": {}, - "server": "Serwer", - "@server": {}, - "serverAddress": "Adres serwera", - "@serverAddress": {}, - "serverApiRequired": "Wymagana wersja API", - "@serverApiRequired": {}, - "serverApiVersion": "Wersja API serwera", - "@serverApiVersion": {}, - "serverAuthenticationError": "Błąd uwierzytelniania", - "@serverAuthenticationError": {}, - "serverCertificateError": "Błąd certyfikatu", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Certyfikat serwera HTTPS jest nieprawidłowy", - "@serverCertificateInvalid": {}, - "serverConnected": "Połączony z serwerem", - "@serverConnected": {}, - "serverConnecting": "Łączenie z serwerem", - "@serverConnecting": {}, - "serverCouldNotConnect": "Nie można połączyć się z serwerem", - "@serverCouldNotConnect": {}, - "serverEmpty": "Serwer nie może być pusty", - "@serverEmpty": {}, - "serverError": "Błąd serwera", - "@serverError": {}, - "serverDetails": "Szczegóły serwera", - "@serverDetails": {}, - "serverMissingData": "Odpowiedź serwera nie ma wymaganych pól", - "@serverMissingData": {}, - "serverOld": "Stara wersja serwera", - "@serverOld": {}, - "serverSettings": "Ustawienia Serwera", - "@serverSettings": {}, - "serverStart": "Serwer musi zaczynać się od http[s]", - "@serverStart": {}, - "settings": "Ustawienia", - "@settings": {}, - "serverInstance": "Instancja serwera", - "@serverInstance": {}, - "serverNotConnected": "Serwer nie podłączony", - "@serverNotConnected": {}, - "sounds": "Dźwięki", - "@sounds": {}, - "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", - "@soundOnServerError": {}, - "status": "Status", - "@status": {}, - "statusCode": "Kod statusu", - "@statusCode": {}, - "stock": "Stan", - "@stock": { - "description": "stock" - }, - "stockItem": "Element magazynowy", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Elementy magazynowe", - "@stockItems": {}, - "stockItemCreate": "Nowa Pozycja Magazynowa", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Utwórz nową pozycję magazynową w tej lokalizacji", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Usuń przedmiot magazynowy", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Czy jesteś pewien, że chcesz usunąć ten przedmiot magazynowy?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Nie można usunąć przedmiotu magazynowego", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Przedmiot magazynowy usunięty", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Historia zapasów", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Wyświetl historyczne informacje o śledzeniu stanów magazynowych", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Element magazynowy przeniesiony", - "@stockItemTransferred": {}, - "stockItemUpdated": "Zaktualizowano element magazynowy", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Brak dostępnych elementów", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notatki przedmiotu magazynowego", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Zaktualizowano element magazynowy", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Nie zaktualizowano elementu magazynowego", - "@stockItemUpdateFailure": {}, - "stockLocation": "Lokacja stanu", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Lokacje stanów", - "@stockLocations": {}, - "stockTopLevel": "Najwyższy poziom lokalizacji magazynu", - "@stockTopLevel": {}, - "strictHttps": "Ścisły HTTPS", - "@strictHttps": {}, - "strictHttpsDetails": "Wymuś ścisłe sprawdzanie certyfikatów HTTPS", - "@strictHttpsDetails": {}, - "subcategory": "Podkategoria", - "@subcategory": {}, - "subcategories": "Podkategorie", - "@subcategories": {}, - "sublocation": "Sublokacja", - "@sublocation": {}, - "sublocations": "Subblokacje", - "@sublocations": {}, - "sublocationNone": "Brak subblokacji", - "@sublocationNone": {}, - "sublocationNoneDetail": "Brak dostępnych podlokalizacji", - "@sublocationNoneDetail": {}, - "submitFeedback": "Prześlij opinię", - "@submitFeedback": {}, - "suppliedParts": "Dostarczone Części", - "@suppliedParts": {}, - "supplier": "Dostawca", - "@supplier": {}, - "suppliers": "Dostawcy", - "@suppliers": {}, - "supplierReference": "Identyfikator Dostawcy", - "@supplierReference": {}, - "takePicture": "Zrób zdjęcie", - "@takePicture": {}, - "targetDate": "Data Docelowa", - "@targetDate": {}, - "testName": "Nazwa testu", - "@testName": {}, - "testPassedOrFailed": "Test zaliczony lub nieudany", - "@testPassedOrFailed": {}, - "testsRequired": "Wymagane testy", - "@testsRequired": {}, - "testResults": "Wyniki testu", - "@testResults": { - "description": "" - }, - "testResultAdd": "Dodaj wynik testu", - "@testResultAdd": {}, - "testResultNone": "Brak wyników testu", - "@testResultNone": {}, - "testResultNoneDetail": "Brak dostępnych wyników testu", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Błąd przesyłania wyniku testu", - "@testResultUploadFail": {}, - "testResultUploadPass": "Wynik testu przesłany", - "@testResultUploadPass": {}, - "timeout": "Upłynął limit czasu", - "@timeout": { - "description": "" - }, - "tokenError": "Błąd tokenu", - "@tokenError": {}, - "tokenMissing": "Brakujący token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", - "@tokenMissingFromResponse": {}, - "transfer": "Przenieś", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Przenieś stan", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Przetłumacz", - "@translate": {}, - "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", - "@translateHelp": {}, - "units": "Jednostki", - "@units": {}, - "unknownResponse": "Nieznana odpowiedź", - "@unknownResponse": {}, - "upload": "Wyślij", - "@upload": {}, - "uploadFailed": "Błąd wysyłania pliku", - "@uploadFailed": {}, - "uploadSuccess": "Plik przesłany", - "@uploadSuccess": {}, - "usedIn": "Użyte w", - "@usedIn": {}, - "usedInDetails": "Złożenie, które wymagają tego komponentu", - "@usedInDetails": {}, - "username": "Nazwa użytkownika", - "@username": {}, - "usernameEmpty": "Nazwa użytkownika nie może być pusta", - "@usernameEmpty": {}, - "value": "Wartość", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Wartość nie może być pusta", - "@valueCannotBeEmpty": {}, - "valueRequired": "Wartość jest wymagana", - "@valueRequired": {}, - "version": "Wersja", - "@version": {}, - "viewSupplierPart": "Zobacz Dostawcę Części", - "@viewSupplierPart": {}, - "website": "Strona WWW", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb deleted file mode 100644 index 65bbe17..0000000 --- a/lib/l10n/app_pt.arb +++ /dev/null @@ -1,193 +0,0 @@ -{ - "@@locale": "pt", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, - "about": "Sobre", - "@about": {}, - "accountDetails": "Detalhes da Conta", - "@accountDetails": {}, - "actions": "Ações", - "@actions": { - "description": "" - }, - "actionsNone": "Nenhuma ação disponível", - "@actionsNone": {}, - "add": "Adicionar", - "@add": { - "description": "add" - }, - "addStock": "Adicionar ao estoque", - "@addStock": { - "description": "add stock" - }, - "address": "Endereço", - "@address": {}, - "appAbout": "Sobre o InvenTree", - "@appAbout": {}, - "appCredits": "Créditos adicionais do aplicativo", - "@appCredits": {}, - "appDetails": "Detalhes do App", - "@appDetails": {}, - "appReleaseNotes": "Exibir notas de versão do aplicativo", - "@appReleaseNotes": {}, - "appSettings": "Configurações do App", - "@appSettings": {}, - "appSettingsDetails": "Configurar os parâmetros do InvenTree", - "@appSettingsDetails": {}, - "attachments": "Anexos", - "@attachments": {}, - "attachImage": "Anexar Imagem", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Não foram encontrados quaisquer anexos", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Selecionar anexo", - "@attachmentSelect": {}, - "attention": "Aviso", - "@attention": {}, - "barcodeAssign": "Atribuir Código de Barras", - "@barcodeAssign": {}, - "barcodeAssigned": "Código de barras atribuído", - "@barcodeAssigned": {}, - "barcodeError": "Erro ao escanear código de barras", - "@barcodeError": {}, - "barcodeInUse": "Código de barras já atribuído", - "@barcodeInUse": {}, - "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Não corresponde a nenhum código de barras", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Código de barras não atribuído", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Escaneie para atribuir código de barras", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Escaneie itens de estoque no local", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Escanear Localização", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Escaneado no local", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanItem": "Escanear ítem", - "@barcodeScanItem": {}, - "barcodeTones": "Tons do código de barras", - "@barcodeTones": {}, - "barcodeUnassign": "Remover código de barras pre-designado", - "@barcodeUnassign": {}, - "barcodeUnknown": "Código de barras não reconhecido", - "@barcodeUnknown": {}, - "batchCode": "Código de lote", - "@batchCode": {}, - "billOfMaterials": "Lista de Materiais", - "@billOfMaterials": {}, - "bom": "Lista de Materiais", - "@bom": {}, - "build": "Compilar", - "@build": {}, - "building": "Compilando", - "@building": {}, - "cancel": "Cancelar", - "@cancel": { - "description": "Cancel" - }, - "category": "Categoria", - "@category": {}, - "categoryCreate": "Nova Categoria", - "@categoryCreate": {}, - "categoryCreateDetail": "Criar nova categoria de peças", - "@categoryCreateDetail": {}, - "categoryUpdated": "Categoria de peça atualizada", - "@categoryUpdated": {}, - "company": "Empresa", - "@company": {}, - "companyEdit": "Editar empresa", - "@companyEdit": {}, - "companyNoResults": "Nenhuma empresa corresponde a consulta", - "@companyNoResults": {}, - "companyUpdated": "Dados da empresa atualizados", - "@companyUpdated": {}, - "companies": "Empresas", - "@companies": {}, - "configureServer": "Configurar os parâmetros do servidor de email", - "@configureServer": {}, - "connectionRefused": "Conexão recusada", - "@connectionRefused": {}, - "count": "Contagem", - "@count": { - "description": "Count" - }, - "countStock": "Contagem de Estoque", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Créditos", - "@credits": {}, - "customers": "Clientes", - "@customers": {}, - "damaged": "Danificado", - "@damaged": {}, - "delete": "Excluir", - "@delete": {}, - "deletePart": "Excluir esta parte", - "@deletePart": {}, - "deletePartDetail": "Remover esta peça da base de dados", - "@deletePartDetail": {}, - "description": "Descrição", - "@description": {}, - "destroyed": "Destruído", - "@destroyed": {}, - "details": "Detalhes", - "@details": { - "description": "details" - }, - "documentation": "Documentação", - "@documentation": {}, - "downloading": "Baixando arquivo", - "@downloading": {}, - "downloadError": "Erro de download", - "@downloadError": {}, - "edit": "Editar", - "@edit": { - "description": "edit" - }, - "editCategory": "Editar categoria", - "@editCategory": {}, - "editLocation": "Editar Localização", - "@editLocation": {}, - "editNotes": "Editar notas", - "@editNotes": {}, - "editPart": "Editar a peça", - "@editPart": { - "description": "edit part" - }, - "editItem": "Editar Item do Estoque", - "@editItem": {}, - "enterPassword": "Digite a senha", - "@enterPassword": {}, - "enterUsername": "Inserir usuário", - "@enterUsername": {}, - "error": "Erro", - "@error": { - "description": "Error" - }, - "errorCreate": "Erro ao criar entrada de banco de dados", - "@errorCreate": {}, - "errorDelete": "Erro ao excluir entrada no banco de dados", - "@errorDelete": {}, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "lastUpdated": "Ultima atualização", - "@lastUpdated": {}, - "lineItems": "Itens de linha", - "@lineItems": {} -} \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb deleted file mode 100644 index d89f472..0000000 --- a/lib/l10n/app_ru.arb +++ /dev/null @@ -1,263 +0,0 @@ -{ - "@@locale": "ru", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "ОК", - "@ok": { - "description": "OK" - }, - "about": "О проекте", - "@about": {}, - "accountDetails": "Данные аккаунта", - "@accountDetails": {}, - "actions": "Действия", - "@actions": { - "description": "" - }, - "actionsNone": "Действия недоступны", - "@actionsNone": {}, - "add": "Добавить", - "@add": { - "description": "add" - }, - "addStock": "Добавить запасы", - "@addStock": { - "description": "add stock" - }, - "address": "Адрес", - "@address": {}, - "appAbout": "О InvenTree", - "@appAbout": {}, - "appCredits": "Благодарности за помощь и поддержку", - "@appCredits": {}, - "appDetails": "Информация о приложении", - "@appDetails": {}, - "appReleaseNotes": "Показать заметки о выпуске приложения", - "@appReleaseNotes": {}, - "appSettings": "Настройки приложения", - "@appSettings": {}, - "companyNoResults": "Нет организаций, соответствующих запросу", - "@companyNoResults": {}, - "downloading": "Загрузка файла", - "@downloading": {}, - "downloadError": "Ошибка загрузки", - "@downloadError": {}, - "edit": "Изменить", - "@edit": { - "description": "edit" - }, - "editCategory": "Редактировать категорию", - "@editCategory": {}, - "editLocation": "Редактировать местонахождение", - "@editLocation": {}, - "editNotes": "Редактировать примечания", - "@editNotes": {}, - "editPart": "Ред. эту часть", - "@editPart": { - "description": "edit part" - }, - "editItem": "Отредактированный товар", - "@editItem": {}, - "enterPassword": "Введите пароль", - "@enterPassword": {}, - "enterUsername": "Введите имя пользователя", - "@enterUsername": {}, - "error": "Ошибка", - "@error": { - "description": "Error" - }, - "errorCreate": "Ошибка создания записи базы данных", - "@errorCreate": {}, - "errorDetails": "Подробнее об ошибке", - "@errorDetails": {}, - "errorFetch": "Ошибка при получении данных с сервера", - "@errorFetch": {}, - "feedback": "Обратная Связь", - "@feedback": {}, - "feedbackError": "Ошибка отправки отзыва", - "@feedbackError": {}, - "feedbackSuccess": "Отзыв отправлен", - "@feedbackSuccess": {}, - "formatException": "Формат исключения", - "@formatException": {}, - "formatExceptionJson": "Ошибка формата JSON", - "@formatExceptionJson": {}, - "formError": "Ошибка в форме", - "@formError": {}, - "history": "История", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "imageUploadFailure": "Не удалось загрузить изображение", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Изображение загружено", - "@imageUploadSuccess": {}, - "inactive": "Неактивный", - "@inactive": {}, - "inactiveDetail": "Эта часть помечена как неактивная", - "@inactiveDetail": {}, - "includeSubcategories": "Включить подкатегории", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Отображать подкатегории в виде списка", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Добавить доп. местоположения", - "@includeSublocations": {}, - "includeSublocationsDetail": "Отображать доп. местоположения в виде списка", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Неполные данные профиля", - "@incompleteDetails": {}, - "internalPartNumber": "Внутренний номер", - "@internalPartNumber": {}, - "info": "Информация", - "@info": {}, - "invalidHost": "Неверное имя хоста", - "@invalidHost": {}, - "invalidHostDetails": "Недопустимый пароль", - "@invalidHostDetails": {}, - "invalidPart": "Недопустимый элемент", - "@invalidPart": {}, - "invalidPartCategory": "Неверная категория элемента", - "@invalidPartCategory": {}, - "invalidStockLocation": "Неверное расположение склада", - "@invalidStockLocation": {}, - "invalidStockItem": "Недопустимый товарный пункт", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", - "@invalidUsernamePassword": {}, - "issueDate": "Дата проблемы", - "@issueDate": {}, - "itemInLocation": "Элемент уже находится на месте", - "@itemInLocation": {}, - "keywords": "Ключевые слова", - "@keywords": {}, - "lastStocktake": "Последняя инвентаризация", - "@lastStocktake": {}, - "lastUpdated": "Последние обновлённые", - "@lastUpdated": {}, - "lineItem": "Элемент строки", - "@lineItem": {}, - "lineItems": "Элементы строки", - "@lineItems": {}, - "locationCreate": "Новое местоположение", - "@locationCreate": {}, - "locationCreateDetail": "Создать новое расположение склада", - "@locationCreateDetail": {}, - "locationNotSet": "Не указано месторасположение", - "@locationNotSet": {}, - "link": "Ссылка", - "@link": {}, - "lost": "Потерян", - "@lost": {}, - "manufacturers": "Производители", - "@manufacturers": {}, - "missingData": "Отсутствующие данные", - "@missingData": {}, - "name": "Название", - "@name": {}, - "notConnected": "Соединение не установлено", - "@notConnected": {}, - "notes": "Заметки", - "@notes": { - "description": "Notes" - }, - "noResponse": "Нет ответа от сервера", - "@noResponse": {}, - "noResults": "Нет результатов", - "@noResults": {}, - "noSubcategories": "Нет подкатегории", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Нет доступных подкатегорий", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Неправильный номер", - "@numberInvalid": {}, - "onOrder": "Под заказ", - "@onOrder": {}, - "onOrderDetails": "Заказаные элементы", - "@onOrderDetails": {}, - "packaging": "Упаковка", - "@packaging": {}, - "packageName": "Название упаковки", - "@packageName": {}, - "parent": "Родитель", - "@parent": {}, - "parentCategory": "Родительская категория", - "@parentCategory": {}, - "parentLocation": "Родительское местоположение", - "@parentLocation": {}, - "part": "Компонент", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Новый компонент", - "@partCreate": {}, - "partCreateDetail": "Создать компонент в данной категории", - "@partCreateDetail": {}, - "parts": "Номенклатура", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Нет компонентов", - "@partsNone": {}, - "partNoResults": "Нет компонентов, соответствующих запросу", - "@partNoResults": {}, - "response405": "405 Метод не разрешен", - "@response405": {}, - "response429": "Слишком много запросов", - "@response429": {}, - "response500": "Внутренняя ошибка сервера", - "@response500": {}, - "response501": "Не реализовано", - "@response501": {}, - "response502": "Недопустимый шлюз", - "@response502": {}, - "response503": "Сервис недоступен", - "@response503": {}, - "response504": "504: тайм-аут шлюза", - "@response504": {}, - "response505": "505: версия не поддерживается", - "@response505": {}, - "responseData": "Информация об ответе", - "@responseData": {}, - "responseInvalid": "Неверный код ответа", - "@responseInvalid": {}, - "responseUnknown": "Неизвестный ответ", - "@responseUnknown": {}, - "result": "Результат", - "@result": { - "description": "" - }, - "returned": "Возвращено", - "@returned": {}, - "salesOrders": "Заказы на продажу", - "@salesOrders": {}, - "save": "Сохранить", - "@save": { - "description": "Save" - }, - "scanBarcode": "Сканировать штрихкод", - "@scanBarcode": {}, - "scanIntoLocation": "Сканировать в местоположение", - "@scanIntoLocation": {}, - "search": "Поиск", - "@search": { - "description": "search" - }, - "searchLocation": "Искать по месту", - "@searchLocation": {}, - "searchParts": "Найти номенклатуру", - "@searchParts": {}, - "searchStock": "Поиск в наличии", - "@searchStock": {}, - "select": "Выбрать", - "@select": {}, - "selectFile": "Выбрать файл", - "@selectFile": {}, - "selectImage": "Выбрать изображение", - "@selectImage": {}, - "website": "Сайт", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb deleted file mode 100644 index e37c200..0000000 --- a/lib/l10n/app_sv.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "sv", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb deleted file mode 100644 index 5fdf211..0000000 --- a/lib/l10n/app_th.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "th", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb deleted file mode 100644 index 447ecee..0000000 --- a/lib/l10n/app_tr.arb +++ /dev/null @@ -1,735 +0,0 @@ -{ - "@@locale": "tr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "TAMAM", - "@ok": { - "description": "OK" - }, - "about": "Hakkında", - "@about": {}, - "accountDetails": "Hesap Detayları", - "@accountDetails": {}, - "actions": "Eylemler", - "@actions": { - "description": "" - }, - "actionsNone": "Kullanılabilir eylem yok", - "@actionsNone": {}, - "add": "Ekle", - "@add": { - "description": "add" - }, - "addStock": "Stok ekle", - "@addStock": { - "description": "add stock" - }, - "address": "Adres", - "@address": {}, - "appAbout": "InvenTree Hakkında", - "@appAbout": {}, - "appCredits": "Uygulama kredisi ekle", - "@appCredits": {}, - "appDetails": "Uygulama Detayları", - "@appDetails": {}, - "appReleaseNotes": "Uygulama yayınlama notları", - "@appReleaseNotes": {}, - "appSettings": "Uygulama Ayarları", - "@appSettings": {}, - "appSettingsDetails": "Uygulama ayarlarından yapılandır", - "@appSettingsDetails": {}, - "attachments": "Ekler", - "@attachments": {}, - "attachImage": "Resim ekle", - "@attachImage": { - "description": "Attach an image" - }, - "attachmentNone": "Hiçbir ek bulunamadı", - "@attachmentNone": {}, - "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", - "@attachmentNonePartDetail": {}, - "attachmentSelect": "Ek seçin", - "@attachmentSelect": {}, - "attention": "Dikkat", - "@attention": {}, - "barcodeAssign": "Barkod Ata", - "@barcodeAssign": {}, - "barcodeAssigned": "Barkod atandı", - "@barcodeAssigned": {}, - "barcodeError": "Barkod tarama hatası", - "@barcodeError": {}, - "barcodeInUse": "Barkod zaten kullanımda", - "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash verisi alınamadı", - "@barcodeMissingHash": {}, - "barcodeNoMatch": "Barkod için eşleşme yok", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barkod atanmış değil", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Atanmış barkodu tara", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Bir Iventree barkodu tara", - "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Stok öğelerini konum içine tara", - "@barcodeScanInItems": {}, - "barcodeScanLocation": "Stok konumu tara", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Konuma tarandı", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Madde taranmış değil", - "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Stok öğesi tara", - "@barcodeScanItem": {}, - "barcodeTones": "Barkod Tonları", - "@barcodeTones": {}, - "barcodeUnassign": "Atanmamış barkod", - "@barcodeUnassign": {}, - "barcodeUnknown": "Barkod tanınmadı", - "@barcodeUnknown": {}, - "batchCode": "Grup kodu", - "@batchCode": {}, - "billOfMaterials": "Fatura materyalleri", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, - "build": "Oluştur", - "@build": {}, - "building": "Oluşturma", - "@building": {}, - "cancel": "İptal", - "@cancel": { - "description": "Cancel" - }, - "category": "Kategori", - "@category": {}, - "categoryCreate": "Yeni Kategori", - "@categoryCreate": {}, - "categoryCreateDetail": "Yeni parça kategorisi oluştur", - "@categoryCreateDetail": {}, - "categoryUpdated": "Parça Kategorisi güncellendi", - "@categoryUpdated": {}, - "company": "Şirket", - "@company": {}, - "companyEdit": "Şirketi Düzenle", - "@companyEdit": {}, - "companyNoResults": "Sorguyla eşleşen şirket yok", - "@companyNoResults": {}, - "companyUpdated": "Firma bilgileri güncellendi", - "@companyUpdated": {}, - "companies": "Şirketler", - "@companies": {}, - "configureServer": "Sunucu ayarlarınızı yapılandırın", - "@configureServer": {}, - "connectionRefused": "Bağlantı reddedildi", - "@connectionRefused": {}, - "count": "Sayım", - "@count": { - "description": "Count" - }, - "countStock": "Stok sayımı", - "@countStock": { - "description": "Count Stock" - }, - "credits": "Katkıda Bulunanlar", - "@credits": {}, - "customers": "Müşteriler", - "@customers": {}, - "damaged": "Hasarlı", - "@damaged": {}, - "delete": "Sil", - "@delete": {}, - "deletePart": "Parça Sil", - "@deletePart": {}, - "deletePartDetail": "Bu parçayı veritabanından kaldır", - "@deletePartDetail": {}, - "description": "Açıklama", - "@description": {}, - "destroyed": "Yok edildi", - "@destroyed": {}, - "details": "Detaylar", - "@details": { - "description": "details" - }, - "documentation": "Dökümantasyon", - "@documentation": {}, - "downloading": "Dosya indiriliyor", - "@downloading": {}, - "downloadError": "İndirme Hatası", - "@downloadError": {}, - "edit": "Düzenle", - "@edit": { - "description": "edit" - }, - "editCategory": "Kategoriyi düzenle", - "@editCategory": {}, - "editLocation": "Konumu Düzenle", - "@editLocation": {}, - "editNotes": "Notları Düzenle", - "@editNotes": {}, - "editPart": "Parçayı Düzenle", - "@editPart": { - "description": "edit part" - }, - "editItem": "Parçayı Düzenle", - "@editItem": {}, - "enterPassword": "Şifrenizi girin", - "@enterPassword": {}, - "enterUsername": "Kullanıcı adını girin", - "@enterUsername": {}, - "error": "Hata", - "@error": { - "description": "Error" - }, - "errorCreate": "Veritabanı girdi oluşturma hatası", - "@errorCreate": {}, - "errorDelete": "Veritabanı girdisini silerken hata", - "@errorDelete": {}, - "errorDetails": "Hata Ayrıntıları", - "@errorDetails": {}, - "errorFetch": "Sunucudan veri alınırken hata oluştu", - "@errorFetch": {}, - "errorReporting": "Hata Raporlama", - "@errorReporting": {}, - "errorReportUpload": "Hata raporu yükle", - "@errorReportUpload": {}, - "errorReportUploadDetails": "Anonim olarak hata ve log yükle", - "@errorReportUploadDetails": {}, - "feedback": "Geri Bildirim", - "@feedback": {}, - "feedbackError": "Geribildirim gönderme hatası", - "@feedbackError": {}, - "feedbackSuccess": "Geri bildirim gönderildi", - "@feedbackSuccess": {}, - "formatException": "Biçim İstisnası", - "@formatException": {}, - "formatExceptionJson": "JSON veri format istisnası", - "@formatExceptionJson": {}, - "formError": "Form hatası", - "@formError": {}, - "history": "Geçmiş", - "@history": { - "description": "history" - }, - "homeScreen": "Ana Ekran", - "@homeScreen": {}, - "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", - "@homeScreenSettings": {}, - "homeShowPo": "Satın Alma Siparişlerini Göster", - "@homeShowPo": {}, - "homeShowSubscribed": "Parça bildirimlerine abone ol", - "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", - "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Tedarikçileri Göster", - "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", - "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Üreticileri Göster", - "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Tedarikçi butonunu ana ekranda göster", - "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Müşterileri Göster", - "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", - "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Fotoğraf yükleme başarısız", - "@imageUploadFailure": {}, - "imageUploadSuccess": "Resim yüklendi", - "@imageUploadSuccess": {}, - "inactive": "Pasif", - "@inactive": {}, - "inactiveDetail": "Bu parça pasif olarak işaretlendi", - "@inactiveDetail": {}, - "includeSubcategories": "Alt kategorileri dahil et", - "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Alt kategori parçalarını liste görünümünde göster", - "@includeSubcategoriesDetail": {}, - "includeSublocations": "Alt konumları dahil et", - "@includeSublocations": {}, - "includeSublocationsDetail": "Alt konum parçalarını liste görünümünde göster", - "@includeSublocationsDetail": {}, - "incompleteDetails": "Tamamlanmamış profil detayları", - "@incompleteDetails": {}, - "internalPartNumber": "İç Parça Numarası", - "@internalPartNumber": {}, - "info": "Bilgi", - "@info": {}, - "inProduction": "Yapım Aşamasında", - "@inProduction": {}, - "inProductionDetail": "Bu ürün üretim aşamasında", - "@inProductionDetail": {}, - "invalidHost": "Geçersiz alan adı", - "@invalidHost": {}, - "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", - "@invalidHostDetails": {}, - "invalidPart": "Geçersiz Parça", - "@invalidPart": {}, - "invalidPartCategory": "Geçersiz Parça Kategorisi", - "@invalidPartCategory": {}, - "invalidStockLocation": "Geçersiz Stok Konumu", - "@invalidStockLocation": {}, - "invalidStockItem": "Geçersiz Stok Parçası", - "@invalidStockItem": {}, - "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", - "@invalidUsernamePassword": {}, - "issueDate": "Sorun Tarihi", - "@issueDate": {}, - "itemInLocation": "Parça zaten konumda", - "@itemInLocation": {}, - "keywords": "Anahtar kelimeler", - "@keywords": {}, - "lastStocktake": "Son stok tutma", - "@lastStocktake": {}, - "lastUpdated": "Son güncelleme", - "@lastUpdated": {}, - "lineItem": "Parça Sırası", - "@lineItem": {}, - "lineItems": "Parçalar Sırası", - "@lineItems": {}, - "locationCreate": "Yeni Konum", - "@locationCreate": {}, - "locationCreateDetail": "Yeni stok konumu oluştur", - "@locationCreateDetail": {}, - "locationNotSet": "Belirtilmiş konum yok", - "@locationNotSet": {}, - "locationUpdated": "Stok lokasyonu güncellendi", - "@locationUpdated": {}, - "link": "Bağlantı", - "@link": {}, - "lost": "Kayıp", - "@lost": {}, - "manufacturers": "Üreticiler", - "@manufacturers": {}, - "missingData": "Eksik Veri", - "@missingData": {}, - "name": "Adı", - "@name": {}, - "notConnected": "Bağlı değil", - "@notConnected": {}, - "notes": "Notlar", - "@notes": { - "description": "Notes" - }, - "noResponse": "Sunucudan yanıt yok", - "@noResponse": {}, - "noResults": "Sonuç Yok", - "@noResults": {}, - "noSubcategories": "Alt kategori yok", - "@noSubcategories": {}, - "noSubcategoriesAvailable": "Uygun alt kategori yok", - "@noSubcategoriesAvailable": {}, - "numberInvalid": "Geçersiz numara", - "@numberInvalid": {}, - "onOrder": "Siparişte", - "@onOrder": {}, - "onOrderDetails": "Parça şuan siparişte", - "@onOrderDetails": {}, - "packaging": "Paketleme", - "@packaging": {}, - "packageName": "Paket İsmi", - "@packageName": {}, - "parent": "Üst", - "@parent": {}, - "parentCategory": "Üst Kategori", - "@parentCategory": {}, - "parentLocation": "Bağlı lokasyon", - "@parentLocation": {}, - "part": "Parça", - "@part": { - "description": "Part (single)" - }, - "partCreate": "Yeni Parça", - "@partCreate": {}, - "partCreateDetail": "Yeni parça kategorisi oluştur", - "@partCreateDetail": {}, - "partEdited": "Parça Güncellendi", - "@partEdited": {}, - "parts": "Parçalar", - "@parts": { - "description": "Part (multiple)" - }, - "partsNone": "Parça Yok", - "@partsNone": {}, - "partNoResults": "Sorguyla eşleşen parça yok", - "@partNoResults": {}, - "partsStarred": "Sürekli Gelen parçalar", - "@partsStarred": {}, - "partsStarredNone": "Yıldızlı parça yok", - "@partsStarredNone": {}, - "partSuppliers": "Parça Tedarikçileri", - "@partSuppliers": {}, - "partCategory": "Parça Kategorileri", - "@partCategory": {}, - "partCategoryTopLevel": "Üst seviye parça kategorisi", - "@partCategoryTopLevel": {}, - "partCategories": "Parça Kategorileri", - "@partCategories": {}, - "partDetails": "Parça detayları", - "@partDetails": {}, - "partNotes": "Parça notları", - "@partNotes": {}, - "partStock": "Parça stok", - "@partStock": { - "description": "part stock" - }, - "password": "Parola", - "@password": {}, - "passwordEmpty": "Parola boş bırakılamaz", - "@passwordEmpty": {}, - "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", - "@permissionAccountDenied": {}, - "permissionRequired": "İzin Gerekli", - "@permissionRequired": {}, - "printLabel": "Etiket Yazdır", - "@printLabel": {}, - "printLabelFailure": "Etiket yazdırılamadı", - "@printLabelFailure": {}, - "printLabelSuccess": "Etiket yazıcıya gönderildi", - "@printLabelSuccess": {}, - "profile": "Profil", - "@profile": {}, - "profileAdd": "Yeni Sunucu Profili Ekle", - "@profileAdd": {}, - "profileConnect": "Sunucuya bağlan", - "@profileConnect": {}, - "profileEdit": "Sunucu Profilini düzenle", - "@profileEdit": {}, - "profileDelete": "Sunucu profilini sil", - "@profileDelete": {}, - "profileName": "Profil Adı", - "@profileName": {}, - "profileNone": "Kullanılabiir profil yok", - "@profileNone": {}, - "profileNotSelected": "Profil seçilmedi", - "@profileNotSelected": {}, - "profileSelect": "InvenTree sunucusu seç", - "@profileSelect": {}, - "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", - "@profileTapToCreate": {}, - "purchaseOrder": "Satınalma Siparişi", - "@purchaseOrder": {}, - "purchaseOrderEdit": "Satın Alma siparişini düzenle", - "@purchaseOrderEdit": {}, - "purchaseOrders": "Satınalma Siparişleri", - "@purchaseOrders": {}, - "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", - "@purchaseOrderUpdated": {}, - "purchasePrice": "Alış Fiyatı", - "@purchasePrice": {}, - "quantity": "Adet", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "Adet boş", - "@quantityEmpty": {}, - "quantityInvalid": "Adet geçersiz", - "@quantityInvalid": {}, - "quantityPositive": "Adet pozitif bir sayı olmalı", - "@quantityPositive": {}, - "queryNoResults": "Sorgu için sonuç yok", - "@queryNoResults": {}, - "received": "Alınan", - "@received": {}, - "receiveItem": "Alınan Öğeler", - "@receiveItem": {}, - "receivedItem": "Alınan stok parçaları", - "@receivedItem": {}, - "refresh": "Yenile", - "@refresh": {}, - "refreshing": "Yenileniyor", - "@refreshing": {}, - "rejected": "Reddedildi", - "@rejected": {}, - "releaseNotes": "Sürüm notları", - "@releaseNotes": {}, - "remove": "Kaldır", - "@remove": { - "description": "remove" - }, - "removeStock": "Stok Kaldır", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "Hata Bildir", - "@reportBug": {}, - "reportBugDescription": "Hata raporla ( github hesabı gerektirir)", - "@reportBugDescription": {}, - "results": "Sonuçlar", - "@results": {}, - "request": "Talep", - "@request": {}, - "requestingData": "Veri Talep Ediliyor", - "@requestingData": {}, - "required": "Gerekli", - "@required": { - "description": "This field is required" - }, - "response400": "Hatalı İstek", - "@response400": {}, - "response401": "Yetkisiz", - "@response401": {}, - "response403": "İzin Engellendi", - "@response403": {}, - "response404": "Kaynak bulunamadı", - "@response404": {}, - "response405": "İzin Verilmeyen Yöntem", - "@response405": {}, - "response429": "Çok Fazla İstek", - "@response429": {}, - "response500": "İç Sunucu Hatası", - "@response500": {}, - "response501": "Uygulanamadı", - "@response501": {}, - "response502": "Hatalı Ağ Geçidi", - "@response502": {}, - "response503": "Hizmet Kullanılamıyor", - "@response503": {}, - "response504": "Ağ Geçidi Zaman Aşımı", - "@response504": {}, - "response505": "HTTP Sürümü Desteklenmiyor", - "@response505": {}, - "responseData": "Yanıt verileri", - "@responseData": {}, - "responseInvalid": "Geçersiz yanıt kodu.", - "@responseInvalid": {}, - "responseUnknown": "Bilinmeyen yanıt", - "@responseUnknown": {}, - "result": "Sonuç", - "@result": { - "description": "" - }, - "returned": "Geri Dönen", - "@returned": {}, - "salesOrders": "Satış Siparişleri", - "@salesOrders": {}, - "save": "Kaydet", - "@save": { - "description": "Save" - }, - "scanBarcode": "Barkod Tara", - "@scanBarcode": {}, - "scanIntoLocation": "Konuma Tara", - "@scanIntoLocation": {}, - "search": "Ara", - "@search": { - "description": "search" - }, - "searchLocation": "Konum için Ara", - "@searchLocation": {}, - "searchParts": "Parçaları Ara", - "@searchParts": {}, - "searchStock": "Stok Ara", - "@searchStock": {}, - "select": "Seç", - "@select": {}, - "selectFile": "Dosya Seç", - "@selectFile": {}, - "selectImage": "Resim Seç", - "@selectImage": {}, - "selectLocation": "Bir yer seçin", - "@selectLocation": {}, - "send": "Gönder", - "@send": {}, - "serialNumber": "Seri Numara", - "@serialNumber": {}, - "server": "Sunucu", - "@server": {}, - "serverAddress": "Sunucu Adresi", - "@serverAddress": {}, - "serverApiRequired": "Gerekli API Sürümü", - "@serverApiRequired": {}, - "serverApiVersion": "Sunucu API Sürümü", - "@serverApiVersion": {}, - "serverAuthenticationError": "Doğrulama Hatası", - "@serverAuthenticationError": {}, - "serverCertificateError": "Sertifika Hatası", - "@serverCertificateError": {}, - "serverCertificateInvalid": "Sunucunun sertifikası geçersiz", - "@serverCertificateInvalid": {}, - "serverConnected": "Sunucuya bağlanıldı", - "@serverConnected": {}, - "serverConnecting": "Sunucuya bağlanıyor", - "@serverConnecting": {}, - "serverCouldNotConnect": "Sunucuya bağlanılamadı", - "@serverCouldNotConnect": {}, - "serverEmpty": "Sunucu boş olamaz", - "@serverEmpty": {}, - "serverError": "Sunucu Hatası", - "@serverError": {}, - "serverDetails": "Sunucu Detayları", - "@serverDetails": {}, - "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", - "@serverMissingData": {}, - "serverOld": "Eski Sunucu Sürümü", - "@serverOld": {}, - "serverSettings": "Sunucu Ayarları", - "@serverSettings": {}, - "serverStart": "Sunucu http(s) ile başlamalı", - "@serverStart": {}, - "settings": "Ayarlar", - "@settings": {}, - "serverInstance": "Sunucu örneği", - "@serverInstance": {}, - "serverNotConnected": "Sunucu bağlı değil", - "@serverNotConnected": {}, - "sounds": "Sesler", - "@sounds": {}, - "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", - "@soundOnBarcodeAction": {}, - "soundOnServerError": "Sunucu hatasında sesli ton çal", - "@soundOnServerError": {}, - "status": "Durum", - "@status": {}, - "statusCode": "Durum Kodu", - "@statusCode": {}, - "stock": "Stok", - "@stock": { - "description": "stock" - }, - "stockItem": "Stok Kalemi", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "Stok Kalemleri", - "@stockItems": {}, - "stockItemCreate": "Yeni Stok Kalemi", - "@stockItemCreate": {}, - "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", - "@stockItemCreateDetail": {}, - "stockItemDelete": "Stok parçasını sil", - "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", - "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Stok parçası silinemedi", - "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stok parçası silindi", - "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stok Geçmişi", - "@stockItemHistory": {}, - "stockItemHistoryDetail": "Stok takip bilgisini göster", - "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stok kalemi transfer edildi", - "@stockItemTransferred": {}, - "stockItemUpdated": "Stok kalemi güncellendi", - "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Uygun stok kalemi yok", - "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stok Kalemi Notları", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stok kalemi güncellendi", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stok kalemi güncelleme hatası", - "@stockItemUpdateFailure": {}, - "stockLocation": "Stok Konumu", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "Stok Konumları", - "@stockLocations": {}, - "stockTopLevel": "Üst seviye stok konumu", - "@stockTopLevel": {}, - "subcategory": "Alt kategori", - "@subcategory": {}, - "subcategories": "Alt kategoriler", - "@subcategories": {}, - "sublocation": "Alt konumlar", - "@sublocation": {}, - "sublocations": "Alt konumlar", - "@sublocations": {}, - "sublocationNone": "Alt konum yok", - "@sublocationNone": {}, - "sublocationNoneDetail": "Uygun alt kategori yok", - "@sublocationNoneDetail": {}, - "submitFeedback": "Geri Bildirim Gönder", - "@submitFeedback": {}, - "suppliedParts": "Sağlanan Parçalar", - "@suppliedParts": {}, - "supplier": "Tedarikçi", - "@supplier": {}, - "suppliers": "Tedarikçiler", - "@suppliers": {}, - "supplierReference": "Tedarikçi Referansı", - "@supplierReference": {}, - "takePicture": "Resim Çek", - "@takePicture": {}, - "targetDate": "Hedeflenen Tarih", - "@targetDate": {}, - "testName": "Test Adı", - "@testName": {}, - "testPassedOrFailed": "Test başarılı veya hatalı", - "@testPassedOrFailed": {}, - "testsRequired": "Gerekli Testler", - "@testsRequired": {}, - "testResults": "Test Sonuçları", - "@testResults": { - "description": "" - }, - "testResultAdd": "Test Sonucu Ekle", - "@testResultAdd": {}, - "testResultNone": "Test Sonucu Yok", - "@testResultNone": {}, - "testResultNoneDetail": "Uygun test sonucu yok", - "@testResultNoneDetail": {}, - "testResultUploadFail": "Hatalı yüklenen test sonucu", - "@testResultUploadFail": {}, - "testResultUploadPass": "Test sonucu yüklendi", - "@testResultUploadPass": {}, - "timeout": "Zaman Aşımı", - "@timeout": { - "description": "" - }, - "tokenError": "Token Hatası", - "@tokenError": {}, - "tokenMissing": "Eksik Token", - "@tokenMissing": {}, - "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", - "@tokenMissingFromResponse": {}, - "transfer": "Aktarım", - "@transfer": { - "description": "transfer" - }, - "transferStock": "Stok Aktar", - "@transferStock": { - "description": "transfer stock" - }, - "translate": "Çeviri", - "@translate": {}, - "translateHelp": "Çeviriye yardım et", - "@translateHelp": {}, - "units": "Birim", - "@units": {}, - "unknownResponse": "Bilinmeyen Yanıt", - "@unknownResponse": {}, - "upload": "Yükle", - "@upload": {}, - "uploadFailed": "Dosya yüklenemedi", - "@uploadFailed": {}, - "uploadSuccess": "Dosya yüklendi", - "@uploadSuccess": {}, - "usedIn": "Burada Kullanıldı", - "@usedIn": {}, - "usedInDetails": "Bu parçayı gerektiren montajlar", - "@usedInDetails": {}, - "username": "Kullanıcı Adı", - "@username": {}, - "usernameEmpty": "Kullanıcı adı boş bırakılamaz", - "@usernameEmpty": {}, - "value": "Değer", - "@value": { - "description": "value" - }, - "valueCannotBeEmpty": "Değer boş olamaz", - "@valueCannotBeEmpty": {}, - "valueRequired": "Değer gereklidir", - "@valueRequired": {}, - "version": "Sürüm", - "@version": {}, - "viewSupplierPart": "Tedarikçi Parçası Görüntüle", - "@viewSupplierPart": {}, - "website": "Web sitesi", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb deleted file mode 100644 index 08adba6..0000000 --- a/lib/l10n/app_vi.arb +++ /dev/null @@ -1,5 +0,0 @@ -{ - "@@locale": "vi", - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} -} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb deleted file mode 100644 index a94ee5b..0000000 --- a/lib/l10n/app_zh.arb +++ /dev/null @@ -1,341 +0,0 @@ -{ - "@@locale": "zh", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "好", - "@ok": { - "description": "OK" - }, - "about": "关于", - "@about": {}, - "accountDetails": "账户详情", - "@accountDetails": {}, - "actions": "操作", - "@actions": { - "description": "" - }, - "add": "添加", - "@add": { - "description": "add" - }, - "addStock": "添加库存", - "@addStock": { - "description": "add stock" - }, - "address": "地址", - "@address": {}, - "appAbout": "关于 InventTree", - "@appAbout": {}, - "appDetails": "应用详情", - "@appDetails": {}, - "appSettings": "应用设置", - "@appSettings": {}, - "attention": "注意", - "@attention": {}, - "barcodeAssign": "分配条码", - "@barcodeAssign": {}, - "barcodeAssigned": "条码已分配", - "@barcodeAssigned": {}, - "barcodeError": "条形码扫描出错", - "@barcodeError": {}, - "barcodeInUse": "条码已经被分配", - "@barcodeInUse": {}, - "barcodeNoMatch": "无匹配条码", - "@barcodeNoMatch": {}, - "barcodeNotAssigned": "未分配条码", - "@barcodeNotAssigned": {}, - "barcodeScanAssign": "扫描以分配条码", - "@barcodeScanAssign": {}, - "barcodeScanGeneral": "扫描 InvenTree 条码", - "@barcodeScanGeneral": {}, - "barcodeScanLocation": "扫描库存地点", - "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "已扫描至位置", - "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanItem": "扫描库存项", - "@barcodeScanItem": {}, - "barcodeUnassign": "取消分配条码", - "@barcodeUnassign": {}, - "barcodeUnknown": "无法识别条码", - "@barcodeUnknown": {}, - "build": "生产", - "@build": {}, - "cancel": "取消", - "@cancel": { - "description": "Cancel" - }, - "category": "分类", - "@category": {}, - "categoryCreate": "新建分类", - "@categoryCreate": {}, - "categoryCreateDetail": "新建商品类别", - "@categoryCreateDetail": {}, - "company": "公司", - "@company": {}, - "companyEdit": "编辑公司信息", - "@companyEdit": {}, - "companies": "公司", - "@companies": {}, - "connectionRefused": "连接被拒绝", - "@connectionRefused": {}, - "count": "数量", - "@count": { - "description": "Count" - }, - "countStock": "库存数量", - "@countStock": { - "description": "Count Stock" - }, - "credits": "致谢", - "@credits": {}, - "damaged": "破损", - "@damaged": {}, - "delete": "删除", - "@delete": {}, - "description": "描述", - "@description": {}, - "destroyed": "销毁", - "@destroyed": {}, - "details": "详细信息", - "@details": { - "description": "details" - }, - "documentation": "文档", - "@documentation": {}, - "edit": "编辑", - "@edit": { - "description": "edit" - }, - "editCategory": "编辑分类", - "@editCategory": {}, - "editLocation": "编辑位置", - "@editLocation": {}, - "editPart": "编辑部件", - "@editPart": { - "description": "edit part" - }, - "error": "错误", - "@error": { - "description": "Error" - }, - "errorDetails": "c w错误详情", - "@errorDetails": {}, - "history": "历史", - "@history": { - "description": "history" - }, - "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {}, - "internalPartNumber": "内部部件号", - "@internalPartNumber": {}, - "info": "信息", - "@info": {}, - "invalidPart": "无效部件", - "@invalidPart": {}, - "invalidPartCategory": "无效部件分类", - "@invalidPartCategory": {}, - "invalidStockLocation": "无效库存位置", - "@invalidStockLocation": {}, - "invalidStockItem": "无效库存项", - "@invalidStockItem": {}, - "keywords": "关键词", - "@keywords": {}, - "link": "链接", - "@link": {}, - "lost": "丢失", - "@lost": {}, - "name": "名称", - "@name": {}, - "notConnected": "未连接", - "@notConnected": {}, - "notes": "注释", - "@notes": { - "description": "Notes" - }, - "noResponse": "服务器未响应", - "@noResponse": {}, - "parent": "父级", - "@parent": {}, - "parentCategory": "父类别", - "@parentCategory": {}, - "part": "部件", - "@part": { - "description": "Part (single)" - }, - "parts": "部件", - "@parts": { - "description": "Part (multiple)" - }, - "partCategory": "部件分类", - "@partCategory": {}, - "partCategories": "部件分类", - "@partCategories": {}, - "partDetails": "部件详情", - "@partDetails": {}, - "partNotes": "部件注释", - "@partNotes": {}, - "partStock": "部件库存", - "@partStock": { - "description": "part stock" - }, - "password": "密码", - "@password": {}, - "profile": "档案", - "@profile": {}, - "quantity": "数量", - "@quantity": { - "description": "Quantity" - }, - "quantityEmpty": "容量为空", - "@quantityEmpty": {}, - "quantityInvalid": "数量无效", - "@quantityInvalid": {}, - "quantityPositive": "数量必须大于0", - "@quantityPositive": {}, - "refresh": "刷新", - "@refresh": {}, - "refreshing": "正在刷新", - "@refreshing": {}, - "rejected": "已拒绝", - "@rejected": {}, - "releaseNotes": "更新日志", - "@releaseNotes": {}, - "remove": "移除", - "@remove": { - "description": "remove" - }, - "removeStock": "移除库存", - "@removeStock": { - "description": "remove stock" - }, - "reportBug": "反馈问题", - "@reportBug": {}, - "request": "请求", - "@request": {}, - "requestingData": "正在请求数据", - "@requestingData": {}, - "required": "必填", - "@required": { - "description": "This field is required" - }, - "responseInvalid": "无效响应码", - "@responseInvalid": {}, - "responseUnknown": "未知响应", - "@responseUnknown": {}, - "result": "结果", - "@result": { - "description": "" - }, - "save": "保存", - "@save": { - "description": "Save" - }, - "scanBarcode": "扫描条码", - "@scanBarcode": {}, - "scanIntoLocation": "已扫描至位置", - "@scanIntoLocation": {}, - "search": "搜索", - "@search": { - "description": "search" - }, - "searchParts": "搜索部件", - "@searchParts": {}, - "searchStock": "搜索库存", - "@searchStock": {}, - "select": "选择", - "@select": {}, - "send": "发送", - "@send": {}, - "serialNumber": "序列号", - "@serialNumber": {}, - "server": "服务器", - "@server": {}, - "serverAddress": "服务器地址", - "@serverAddress": {}, - "serverConnected": "已连接至服务器", - "@serverConnected": {}, - "serverError": "服务器错误", - "@serverError": {}, - "serverDetails": "服务器详情", - "@serverDetails": {}, - "serverOld": "过时的服务器版本", - "@serverOld": {}, - "serverSettings": "服务器设置", - "@serverSettings": {}, - "settings": "设置", - "@settings": {}, - "serverInstance": "服务器实例", - "@serverInstance": {}, - "serverNotConnected": "未连接至服务器", - "@serverNotConnected": {}, - "status": "状态", - "@status": {}, - "statusCode": "状态码", - "@statusCode": {}, - "stock": "库存", - "@stock": { - "description": "stock" - }, - "stockItem": "库存项", - "@stockItem": { - "description": "stock item title" - }, - "stockItems": "库存项", - "@stockItems": {}, - "stockItemNotes": "库存项注释", - "@stockItemNotes": {}, - "stockItemUpdateSuccess": "库存项已更新", - "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "库存项更新失败", - "@stockItemUpdateFailure": {}, - "stockLocation": "库存位置", - "@stockLocation": { - "description": "stock location" - }, - "stockLocations": "库存位置", - "@stockLocations": {}, - "subcategory": "子类别", - "@subcategory": {}, - "subcategories": "子类别", - "@subcategories": {}, - "sublocation": "次级位置", - "@sublocation": {}, - "sublocations": "次级位置", - "@sublocations": {}, - "testResults": "测试结果", - "@testResults": { - "description": "" - }, - "timeout": "超时", - "@timeout": { - "description": "" - }, - "tokenError": "令牌错误", - "@tokenError": {}, - "tokenMissing": "缺少令牌", - "@tokenMissing": {}, - "transfer": "转移", - "@transfer": { - "description": "transfer" - }, - "transferStock": "转移库存", - "@transferStock": { - "description": "transfer stock" - }, - "unknownResponse": "未知响应", - "@unknownResponse": {}, - "upload": "上传", - "@upload": {}, - "username": "用户名", - "@username": {}, - "value": "值", - "@value": { - "description": "value" - }, - "version": "版本", - "@version": {}, - "website": "网站", - "@website": {} -} \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 36d80aa..1aeae1d 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "cs", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 36d80aa..ec3b2b6 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1,5 +1,745 @@ { - "@@locale": "en", + "@@locale": "de", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Über", + "@about": {}, + "accountDetails": "Konto Details", + "@accountDetails": {}, + "actions": "Aktionen", + "@actions": { + "description": "" + }, + "actionsNone": "Keine Aktionen verfügbar", + "@actionsNone": {}, + "add": "Hinzufügen", + "@add": { + "description": "add" + }, + "addStock": "Bestand hinzufügen", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "Über InvenTree", + "@appAbout": {}, + "appCredits": "Weitere App-Danksagungen", + "@appCredits": {}, + "appDetails": "App-Informationen", + "@appDetails": {}, + "appReleaseNotes": "App-Versionshinweise anzeigen", + "@appReleaseNotes": {}, + "appSettings": "App-Einstellungen", + "@appSettings": {}, + "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", + "@appSettingsDetails": {}, + "attachments": "Anhänge", + "@attachments": {}, + "attachImage": "Bild hinzufügen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Keine Anhänge gefunden", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Anhang auswählen", + "@attachmentSelect": {}, + "attention": "Achtung", + "@attention": {}, + "availableStock": "Verfügbarer Lagerbestand", + "@availableStock": {}, + "barcodeAssign": "Barcode zuweisen", + "@barcodeAssign": {}, + "barcodeAssigned": "Barcode zugewiesen", + "@barcodeAssigned": {}, + "barcodeError": "Fehler beim Scannen des Barcodes", + "@barcodeError": {}, + "barcodeInUse": "Barcode wurde bereits zugewiesen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Prüfsumme fehlt in Antwort", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Keine Übereinstimmung für den Barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode nicht zugewiesen", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scannen um Barcode zuzuweisen", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Einen InvenTree Barcode scannen", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Artikel per Barcode-Scan zu Lagerort hinzufügen", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Lagerort scannen", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Artikel scannen", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode-Ton", + "@barcodeTones": {}, + "barcodeUnassign": "Barcode entfernen", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode wurde nicht erkannt", + "@barcodeUnknown": {}, + "batchCode": "Losnummer", + "@batchCode": {}, + "billOfMaterials": "Stückliste", + "@billOfMaterials": {}, + "bom": "Stückliste", + "@bom": {}, + "build": "Bauauftrag", + "@build": {}, + "building": "Gebäude", + "@building": {}, + "cancel": "Abbrechen", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategorie", + "@category": {}, + "categoryCreate": "Neue Kategorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Teile-Kategorie anlegen", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategorie aktualisiert", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Firma bearbeiten", + "@companyEdit": {}, + "companyNoResults": "Keine Firmen entsprechen der Anfrage", + "@companyNoResults": {}, + "companyUpdated": "Firmendetails aktualisiert", + "@companyUpdated": {}, + "companies": "Firmen", + "@companies": {}, + "configureServer": "Server-Einstellungen konfigurieren", + "@configureServer": {}, + "connectionRefused": "Verbindung verweigert", + "@connectionRefused": {}, + "count": "Zählen", + "@count": { + "description": "Count" + }, + "countStock": "Bestand zählen", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Danksagungen", + "@credits": {}, + "customers": "Kunden", + "@customers": {}, + "damaged": "Beschädigt", + "@damaged": {}, + "delete": "Löschen", + "@delete": {}, + "deletePart": "Teil löschen", + "@deletePart": {}, + "deletePartDetail": "Dieses Teil aus der Datenbank löschen", + "@deletePartDetail": {}, + "description": "Beschreibung", + "@description": {}, + "destroyed": "Vernichtet", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloading": "Datei wird heruntergeladen", + "@downloading": {}, + "downloadError": "Fehler beim Herunterladen", + "@downloadError": {}, + "edit": "Bearbeiten", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategorie bearbeiten", + "@editCategory": {}, + "editLocation": "Ort bearbeiten", + "@editLocation": {}, + "editNotes": "Notizen bearbeiten", + "@editNotes": {}, + "editPart": "Teil bearbeiten", + "@editPart": { + "description": "edit part" + }, + "editItem": "Artikel bearbeiten", + "@editItem": {}, + "enterPassword": "Passwort eingeben", + "@enterPassword": {}, + "enterUsername": "Benutzername eingeben", + "@enterUsername": {}, + "error": "Fehler", + "@error": { + "description": "Error" + }, + "errorCreate": "Fehler beim Erstellen des Datenbankeintrages", + "@errorCreate": {}, + "errorDelete": "Fehler beim Löschen von Datenbankeintrag", + "@errorDelete": {}, + "errorDetails": "Fehlerdetails", + "@errorDetails": {}, + "errorFetch": "Fehler beim Abrufen der Daten vom Server", + "@errorFetch": {}, + "errorReporting": "Fehlerberichterstattung", + "@errorReporting": {}, + "errorReportUpload": "Fehlerberichte hochladen", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fehler beim Senden des Feedbacks", + "@feedbackError": {}, + "feedbackSuccess": "Feedback gesendet", + "@feedbackSuccess": {}, + "formatException": "Formatfehler", + "@formatException": {}, + "formatExceptionJson": "Format-Fehler im JSON", + "@formatExceptionJson": {}, + "formError": "Formular-Fehler", + "@formError": {}, + "history": "Verlauf", + "@history": { + "description": "history" + }, + "homeScreen": "Startseite", + "@homeScreen": {}, + "homeScreenSettings": "Einstellungen für Startseite konfigurieren", + "@homeScreenSettings": {}, + "homeShowPo": "Bestellungen anzeigen", + "@homeShowPo": {}, + "homeShowSubscribed": "Abonnierte Teile", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Lieferanten anzeigen", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Hersteller anzeigen", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Hersteller auf Startseite anzeigen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Kunden anzeigen", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Kunden auf Startseite anzeigen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Das Bild konnte nicht hochgeladen werden", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Bild hochgeladen", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveDetail": "Teil als inaktiv gekennzeichnet", + "@inactiveDetail": {}, + "includeSubcategories": "Unter-Kategorien einschließen", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Teile aus Unter-Kategorien anzeigen", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Unter-Lagerorte einschließen", + "@includeSublocations": {}, + "includeSublocationsDetail": "Liste der Unter-Lagerorte anzeigen", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil unvollständig", + "@incompleteDetails": {}, + "internalPartNumber": "Interne Teilenummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Produktion", + "@inProduction": {}, + "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", + "@inProductionDetail": {}, + "invalidHost": "Ungültiger Hostname", + "@invalidHost": {}, + "invalidHostDetails": "Der angegebener Hostname ist ungültig", + "@invalidHostDetails": {}, + "invalidPart": "Ungültiges Teil", + "@invalidPart": {}, + "invalidPartCategory": "Ungültige Teil-Kategorie", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ungültiger Lagerort", + "@invalidStockLocation": {}, + "invalidStockItem": "Ungültiger Artikel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", + "@invalidUsernamePassword": {}, + "issueDate": "Ausstellungsdatum", + "@issueDate": {}, + "itemInLocation": "Artikel ist bereits in diesem Lagerort", + "@itemInLocation": {}, + "keywords": "Schlüsselwörter", + "@keywords": {}, + "lastStocktake": "Letzte Inventur", + "@lastStocktake": {}, + "lastUpdated": "Letzte Änderung", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Positionen", + "@lineItems": {}, + "locationCreate": "Neuer Lagerort", + "@locationCreate": {}, + "locationCreateDetail": "Neuen Lagerort erstellen", + "@locationCreateDetail": {}, + "locationNotSet": "Lagerort nicht angegeben", + "@locationNotSet": {}, + "locationUpdated": "Lagerort aktualisiert", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "manufacturers": "Hersteller", + "@manufacturers": {}, + "missingData": "Fehlende Daten", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Nicht verbunden", + "@notConnected": {}, + "notes": "Notizen", + "@notes": { + "description": "Notes" + }, + "noResponse": "Keine Antwort vom Server", + "@noResponse": {}, + "noResults": "Keine Ergebnisse", + "@noResults": {}, + "noSubcategories": "Keine Unter-Kategorien", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Keine gültige Zahl", + "@numberInvalid": {}, + "onOrder": "Bestellt", + "@onOrder": {}, + "onOrderDetails": "Artikel wurde bestellt", + "@onOrderDetails": {}, + "packaging": "Paket", + "@packaging": {}, + "packageName": "Paket-Name", + "@packageName": {}, + "parent": "Übergeordnetes", + "@parent": {}, + "parentCategory": "Übergeordnete Kategorie", + "@parentCategory": {}, + "parentLocation": "Übergeordneter Lagerort", + "@parentLocation": {}, + "part": "Teil", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Teil anlegen", + "@partCreate": {}, + "partCreateDetail": "Teil in dieser Kategorie anlegen", + "@partCreateDetail": {}, + "partEdited": "Teil aktualisiert", + "@partEdited": {}, + "parts": "Teile", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Keine Teile", + "@partsNone": {}, + "partNoResults": "Keine Teile entsprechen der Anfrage", + "@partNoResults": {}, + "partsStarred": "Abonnierte Teile", + "@partsStarred": {}, + "partsStarredNone": "Keine Teile abonniert", + "@partsStarredNone": {}, + "partSuppliers": "Teile-Lieferanten", + "@partSuppliers": {}, + "partCategory": "Teil-Kategorie", + "@partCategory": {}, + "partCategoryTopLevel": "Oberste Teile-Kategorie", + "@partCategoryTopLevel": {}, + "partCategories": "Teil-Kategorien", + "@partCategories": {}, + "partDetails": "Teil-Details", + "@partDetails": {}, + "partNotes": "Teil-Bemerkungen", + "@partNotes": {}, + "partStock": "Teilbestand", + "@partStock": { + "description": "part stock" + }, + "password": "Passwort", + "@password": {}, + "passwordEmpty": "Passwort darf nicht leer sein", + "@passwordEmpty": {}, + "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", + "@permissionAccountDenied": {}, + "permissionRequired": "Berechtigung erforderlich", + "@permissionRequired": {}, + "printLabel": "Label drucken", + "@printLabel": {}, + "printLabelFailure": "Labeldruck fehlgeschlagen", + "@printLabelFailure": {}, + "printLabelSuccess": "Label an den Drucker gesendet", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Server-Profil anlegen", + "@profileAdd": {}, + "profileConnect": "Mit Server verbinden", + "@profileConnect": {}, + "profileEdit": "Server-Profil bearbeiten", + "@profileEdit": {}, + "profileDelete": "Server-Profil löschen", + "@profileDelete": {}, + "profileName": "Profil-Name", + "@profileName": {}, + "profileNone": "Keine Profile angelegt", + "@profileNone": {}, + "profileNotSelected": "Kein Profil ausgewählt", + "@profileNotSelected": {}, + "profileSelect": "InvenTree-Server auswählen", + "@profileSelect": {}, + "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", + "@profileTapToCreate": {}, + "purchaseOrder": "Bestellung", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Bestellung bearbeiten", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Bestellungen", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bestellung aktualisiert", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Einkaufspreis", + "@purchasePrice": {}, + "quantity": "Anzahl", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Menge ist leer", + "@quantityEmpty": {}, + "quantityInvalid": "Menge ist ungültig", + "@quantityInvalid": {}, + "quantityPositive": "Menge muss positiv sein", + "@quantityPositive": {}, + "queryNoResults": "Keine Ergebnisse für die Anfrage", + "@queryNoResults": {}, + "received": "Empfangen", + "@received": {}, + "receiveItem": "Artikel erhalten", + "@receiveItem": {}, + "receivedItem": "Artikel wurde erhalten", + "@receivedItem": {}, + "refresh": "Neu laden", + "@refresh": {}, + "refreshing": "Aktualisiere", + "@refreshing": {}, + "rejected": "Zurückgewiesen", + "@rejected": {}, + "releaseNotes": "Versionshinweise", + "@releaseNotes": {}, + "remove": "Entfernen", + "@remove": { + "description": "remove" + }, + "removeStock": "Bestand entfernen", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Fehler melden", + "@reportBug": {}, + "reportBugDescription": "Fehlerbericht senden (erfordert GitHub Konto)", + "@reportBugDescription": {}, + "results": "Ergebnisse", + "@results": {}, + "request": "Anfrage", + "@request": {}, + "requestingData": "Daten werden angefordert", + "@requestingData": {}, + "required": "Erforderlich", + "@required": { + "description": "This field is required" + }, + "response400": "Ungültige Anfrage", + "@response400": {}, + "response401": "Nicht autorisiert", + "@response401": {}, + "response403": "Zugriff verweigert", + "@response403": {}, + "response404": "Ressource nicht gefunden", + "@response404": {}, + "response405": "Methode nicht erlaubt", + "@response405": {}, + "response429": "Zu viele Anfragen", + "@response429": {}, + "response500": "Interner Serverfehler", + "@response500": {}, + "response501": "Nicht Implementiert", + "@response501": {}, + "response502": "Fehlerhaftes Gateway", + "@response502": {}, + "response503": "Dienst nicht verfügbar", + "@response503": {}, + "response504": "Gateway-Zeitüberschreitung", + "@response504": {}, + "response505": "HTTP-Version wird nicht unterstützt", + "@response505": {}, + "responseData": "Antwort-Daten", + "@responseData": {}, + "responseInvalid": "Ungültiger Antwort-Code", + "@responseInvalid": {}, + "responseUnknown": "Unbekannte Antwort", + "@responseUnknown": {}, + "result": "Ergebnis", + "@result": { + "description": "" + }, + "returned": "Retourniert", + "@returned": {}, + "salesOrders": "Kundenauftrag", + "@salesOrders": {}, + "save": "Speichern", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barcode scannen", + "@scanBarcode": {}, + "scanIntoLocation": "In Lagerorten buchen", + "@scanIntoLocation": {}, + "search": "Suchen", + "@search": { + "description": "search" + }, + "searchLocation": "Lagerort suchen", + "@searchLocation": {}, + "searchParts": "Teile suchen", + "@searchParts": {}, + "searchStock": "Bestand durchsuchen", + "@searchStock": {}, + "select": "Auswählen", + "@select": {}, + "selectFile": "Datei auswählen", + "@selectFile": {}, + "selectImage": "Bild auswählen", + "@selectImage": {}, + "selectLocation": "Wähle einen Lagerort", + "@selectLocation": {}, + "send": "Senden", + "@send": {}, + "serialNumber": "Seriennummer", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradresse", + "@serverAddress": {}, + "serverApiRequired": "Erforderliche API-Version", + "@serverApiRequired": {}, + "serverApiVersion": "API-Version des Servers", + "@serverApiVersion": {}, + "serverAuthenticationError": "Anmeldung fehlgeschlagen", + "@serverAuthenticationError": {}, + "serverCertificateError": "Zertifikatsfehler", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Zertifikat des Servers ist ungültig", + "@serverCertificateInvalid": {}, + "serverConnected": "Verbunden mit Server", + "@serverConnected": {}, + "serverConnecting": "Verbindung zum Server wird aufgebaut", + "@serverConnecting": {}, + "serverCouldNotConnect": "Verbindung zum Server nicht möglich", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server darf nicht leer sein", + "@serverEmpty": {}, + "serverError": "Serverfehler", + "@serverError": {}, + "serverDetails": "Serverdetails", + "@serverDetails": {}, + "serverMissingData": "In der Server-Antwort fehlen erforderliche Felder", + "@serverMissingData": {}, + "serverOld": "Alte Server Version", + "@serverOld": {}, + "serverSettings": "Server Einstellungen", + "@serverSettings": {}, + "serverStart": "Server muss mit http[s] beginnen", + "@serverStart": {}, + "settings": "Einstellungen", + "@settings": {}, + "serverInstance": "Server Instanz", + "@serverInstance": {}, + "serverNotConnected": "Server nicht verbunden", + "@serverNotConnected": {}, + "sounds": "Töne", + "@sounds": {}, + "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Ton bei Serverfehler abspielen", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuscode", + "@statusCode": {}, + "stock": "Bestand", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktuell verfügbare Lagermenge", + "@stockDetails": {}, + "stockItem": "Artikel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Artikel", + "@stockItems": {}, + "stockItemCreate": "Neuen Artikel anlegen", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Neuen Artikel an diesem Lagerort erstellen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Lagerartikel löschen", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Sind Sie sicher, dass Sie diesen Lagerartikel löschen wollen?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Lagerbestand konnte nicht gelöscht werden", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagerbestand gelöscht", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historie des Artikels", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Zeige historische Bestandsverfolgungsdaten", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Artikel umgezogen", + "@stockItemTransferred": {}, + "stockItemUpdated": "Artikel aktualisiert", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Keine Artikel verfügbar", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notizen zum Artikel", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Artikel aktualisiert", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Fehler bei Artikel-Aktualisierung", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerort", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerorte", + "@stockLocations": {}, + "stockTopLevel": "Oberster Lagerort", + "@stockTopLevel": {}, + "strictHttps": "Striktes HTTPS verwenden", + "@strictHttps": {}, + "strictHttpsDetails": "Erzwinge strenge Überprüfung von HTTPs-Zertifikaten", + "@strictHttpsDetails": {}, + "subcategory": "Unterkategorie", + "@subcategory": {}, + "subcategories": "Unterkategorien", + "@subcategories": {}, + "sublocation": "Unter-Lagerort", + "@sublocation": {}, + "sublocations": "Unter-Lagerorte", + "@sublocations": {}, + "sublocationNone": "Keine Unter-Lagerorte", + "@sublocationNone": {}, + "sublocationNoneDetail": "Keine Unter-Lagerorte verfügbar", + "@sublocationNoneDetail": {}, + "submitFeedback": "Feedback geben", + "@submitFeedback": {}, + "suppliedParts": "Gelieferte Teile", + "@suppliedParts": {}, + "supplier": "Lieferant", + "@supplier": {}, + "suppliers": "Lieferanten", + "@suppliers": {}, + "supplierReference": "Lieferanten-Referenz", + "@supplierReference": {}, + "takePicture": "Foto aufnehmen", + "@takePicture": {}, + "targetDate": "Zieldatum", + "@targetDate": {}, + "templatePart": "Übergeordnetes Vorlagenteil", + "@templatePart": {}, + "testName": "Test-Name", + "@testName": {}, + "testPassedOrFailed": "Test erfolgreich oder fehlgeschlagen", + "@testPassedOrFailed": {}, + "testsRequired": "Erforderliche Tests", + "@testsRequired": {}, + "testResults": "Testergebnisse", + "@testResults": { + "description": "" + }, + "testResultAdd": "Testergebnis hinzufügen", + "@testResultAdd": {}, + "testResultNone": "Keine Testergebnisse", + "@testResultNone": {}, + "testResultNoneDetail": "Keine Testergebnisse vorhanden", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fehler beim Hochladen des Testergebnisses", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testergebnis hochgeladen", + "@testResultUploadPass": {}, + "timeout": "Zeitüberschreitung", + "@timeout": { + "description": "" + }, + "tokenError": "Token-Fehler", + "@tokenError": {}, + "tokenMissing": "Token fehlt", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", + "@tokenMissingFromResponse": {}, + "transfer": "Verschieben", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Bestand verschieben", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Übersetzen", + "@translate": {}, + "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", + "@translateHelp": {}, + "units": "Einheiten", + "@units": {}, + "unknownResponse": "Unbekannte Antwort", + "@unknownResponse": {}, + "upload": "Hochladen", + "@upload": {}, + "uploadFailed": "Datei hochladen fehlgeschlagen", + "@uploadFailed": {}, + "uploadSuccess": "Datei hochgeladen", + "@uploadSuccess": {}, + "usedIn": "Verwendet in", + "@usedIn": {}, + "usedInDetails": "Baugruppen, die dieses Teil benötigen", + "@usedInDetails": {}, + "username": "Benutzername", + "@username": {}, + "usernameEmpty": "Der Benutzername darf nicht leer sein", + "@usernameEmpty": {}, + "value": "Wert", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Dieser Wert darf nicht leer sein", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wert erforderlich", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Zulieferer-Teil anzeigen", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 36d80aa..2ae9e43 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "el", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 36d80aa..17a7a62 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -1,5 +1,17 @@ { - "@@locale": "en", + "@@locale": "es", + "barcodeScanInItems": "Escanear artículos de stock en su ubicación", + "@barcodeScanInItems": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "includeSublocationsDetail": "Mostrar elementos de sub-ubicación en vista de lista", + "@includeSublocationsDetail": {}, + "lineItems": "Ítems de línea", + "@lineItems": {}, + "onOrderDetails": "Artículos actualmente en pedido", + "@onOrderDetails": {}, + "stockItems": "Elementos de stock", + "@stockItems": {}, + "stockItemsNotAvailable": "No hay artículos de stock disponibles", + "@stockItemsNotAvailable": {} } \ No newline at end of file diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 36d80aa..f17cd61 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "fa", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 36d80aa..b4ded9e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1,5 +1,743 @@ { - "@@locale": "en", + "@@locale": "fr", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "À propos", + "@about": {}, + "accountDetails": "Détails du compte", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "Aucune action disponible", + "@actionsNone": {}, + "add": "Ajouter", + "@add": { + "description": "add" + }, + "addStock": "Ajouter un stock", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "À propos d'InvenTree", + "@appAbout": {}, + "appCredits": "Crédits d'application supplémentaires", + "@appCredits": {}, + "appDetails": "Détails de l'application", + "@appDetails": {}, + "appReleaseNotes": "Afficher les notes de version de l'application", + "@appReleaseNotes": {}, + "appSettings": "Réglages de l'application", + "@appSettings": {}, + "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", + "@appSettingsDetails": {}, + "attachments": "Pieces jointes", + "@attachments": {}, + "attachImage": "Ajouter une image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Aucune pièce jointe trouvée", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Sélectionner une pièce jointe", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "availableStock": "Stock disponible", + "@availableStock": {}, + "barcodeAssign": "Affecter un code-barres", + "@barcodeAssign": {}, + "barcodeAssigned": "Code-barres affecté", + "@barcodeAssigned": {}, + "barcodeError": "Erreur lors du scan du code-barres", + "@barcodeError": {}, + "barcodeInUse": "Le code-barres est déjà en cours d’utilisation", + "@barcodeInUse": {}, + "barcodeMissingHash": "Les données de hachage du code-barres sont manquantes dans la réponse", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Pas de correspondance pour ce code-barres", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Code-barres non assigné", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scanner pour attribuer un code-barres", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scanner un code-barres InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scannez les items de stock à l'emplacement", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scanner la localisation du stock", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item non scanné dans", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scanner l'article en stock", + "@barcodeScanItem": {}, + "barcodeTones": "Types de code-barre", + "@barcodeTones": {}, + "barcodeUnassign": "Désaffecter le code-barres", + "@barcodeUnassign": {}, + "barcodeUnknown": "Code-barres non reconnu", + "@barcodeUnknown": {}, + "batchCode": "Code de lot", + "@batchCode": {}, + "billOfMaterials": "Liste des matériaux", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Assemblage", + "@build": {}, + "building": "Assemblage en cours", + "@building": {}, + "cancel": "Annuler", + "@cancel": { + "description": "Cancel" + }, + "category": "Catégorie", + "@category": {}, + "categoryCreate": "Nouvelle catégorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Créer une nouvelle catégorie de pièce", + "@categoryCreateDetail": {}, + "categoryUpdated": "Catégorie de pièce mise à jour", + "@categoryUpdated": {}, + "company": "Société", + "@company": {}, + "companyEdit": "Modifier la société", + "@companyEdit": {}, + "companyNoResults": "Aucune société ne correspond à la requête", + "@companyNoResults": {}, + "companyUpdated": "Détails de la société mis à jour", + "@companyUpdated": {}, + "companies": "Sociétés", + "@companies": {}, + "configureServer": "Configurer les paramètres serveur", + "@configureServer": {}, + "connectionRefused": "Connexion refusée", + "@connectionRefused": {}, + "count": "Nombre", + "@count": { + "description": "Count" + }, + "countStock": "Nombre de stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Crédits", + "@credits": {}, + "customers": "Clients", + "@customers": {}, + "damaged": "Endommagé", + "@damaged": {}, + "delete": "Supprimer", + "@delete": {}, + "deletePart": "Supprimer la pièce", + "@deletePart": {}, + "deletePartDetail": "Supprimer cette pièce de la base de données", + "@deletePartDetail": {}, + "description": "Description", + "@description": {}, + "destroyed": "Détruit", + "@destroyed": {}, + "details": "Détails", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Téléchargement du fichier", + "@downloading": {}, + "downloadError": "Erreur lors du téléchargement", + "@downloadError": {}, + "edit": "Modifier", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifier la catégorie", + "@editCategory": {}, + "editLocation": "Modifier l’emplacement", + "@editLocation": {}, + "editNotes": "Modifier les notes", + "@editNotes": {}, + "editPart": "Modifier la pièce", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editer l'article en stock", + "@editItem": {}, + "enterPassword": "Saisissez le mot de passe", + "@enterPassword": {}, + "enterUsername": "Saisissez le nom d'utilisateur", + "@enterUsername": {}, + "error": "Erreur", + "@error": { + "description": "Error" + }, + "errorCreate": "Erreur lors de la création de l'entrée de la base de données", + "@errorCreate": {}, + "errorDelete": "Erreur lors de la suppression de l'entrée de la base de données", + "@errorDelete": {}, + "errorDetails": "Détails de l'erreur", + "@errorDetails": {}, + "errorFetch": "Erreur de récupération des données du serveur", + "@errorFetch": {}, + "errorReporting": "Rapport d'erreur", + "@errorReporting": {}, + "errorReportUpload": "Envoyer le rapport d 'erreur", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", + "@errorReportUploadDetails": {}, + "feedback": "Donner votre avis", + "@feedback": {}, + "feedbackError": "Erreur lors de l'envoi du commentaire", + "@feedbackError": {}, + "feedbackSuccess": "Commentaire envoyé", + "@feedbackSuccess": {}, + "formatException": "Exception de format", + "@formatException": {}, + "formatExceptionJson": "Exception de format de données JSON", + "@formatExceptionJson": {}, + "formError": "Erreur de formulaire", + "@formError": {}, + "history": "Historique", + "@history": { + "description": "history" + }, + "homeScreen": "Ecran d'accueil", + "@homeScreen": {}, + "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", + "@homeScreenSettings": {}, + "homeShowPo": "Afficher les commandes d'achat", + "@homeShowPo": {}, + "homeShowSubscribed": "Pièces suivies", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Afficher les fournisseurs", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Afficher les fabriquants", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Afficher le bouton fabriquant sur l'écran d'accueil", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Afficher les clients", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Afficher le bouton clients sur l'écran d'accueil", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Échec de l'envoi de l'image", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image transférée", + "@imageUploadSuccess": {}, + "inactive": "Inactif", + "@inactive": {}, + "inactiveDetail": "Cette pièce est marquée comme inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Inclure les sous-catégories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Afficher les sous-catégories dans la vue liste", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclure les sous-emplacements", + "@includeSublocations": {}, + "includeSublocationsDetail": "Afficher les sous-emplacements des articles dans la vue liste", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Profil incomplet", + "@incompleteDetails": {}, + "internalPartNumber": "Numéro de pièce interne", + "@internalPartNumber": {}, + "info": "Information", + "@info": {}, + "inProduction": "En production", + "@inProduction": {}, + "inProductionDetail": "Cet article de stock est en production", + "@inProductionDetail": {}, + "invalidHost": "Nom d’hôte invalide", + "@invalidHost": {}, + "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", + "@invalidHostDetails": {}, + "invalidPart": "Article non valide", + "@invalidPart": {}, + "invalidPartCategory": "Catégorie d'article invalide", + "@invalidPartCategory": {}, + "invalidStockLocation": "Emplacement invalide", + "@invalidStockLocation": {}, + "invalidStockItem": "Article en stock non valide", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", + "@invalidUsernamePassword": {}, + "issueDate": "Date d'émission", + "@issueDate": {}, + "itemInLocation": "Article déjà dans l'emplacement", + "@itemInLocation": {}, + "keywords": "Mots clés", + "@keywords": {}, + "lastStocktake": "Dernier inventaire", + "@lastStocktake": {}, + "lastUpdated": "Dernière mise à jour", + "@lastUpdated": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Position", + "@lineItems": {}, + "locationCreate": "Nouvel emplacement", + "@locationCreate": {}, + "locationCreateDetail": "Créer un nouvel emplacement de stock", + "@locationCreateDetail": {}, + "locationNotSet": "Aucun emplacement spécifié", + "@locationNotSet": {}, + "locationUpdated": "Emplacement du stock mis à jour", + "@locationUpdated": {}, + "link": "Lien", + "@link": {}, + "lost": "Perdu", + "@lost": {}, + "manufacturers": "Fabricants", + "@manufacturers": {}, + "missingData": "Données manquantes", + "@missingData": {}, + "name": "Nom", + "@name": {}, + "notConnected": "Non connecté", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "noResponse": "Aucune réponse du serveur", + "@noResponse": {}, + "noResults": "Aucun résultat", + "@noResults": {}, + "noSubcategories": "Pas de sous-catégorie", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nombre invalide", + "@numberInvalid": {}, + "onOrder": "Sur Commande", + "@onOrder": {}, + "onOrderDetails": "Articles en cours de commande", + "@onOrderDetails": {}, + "packaging": "Emballage", + "@packaging": {}, + "packageName": "Nom du package", + "@packageName": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Catégorie parent", + "@parentCategory": {}, + "parentLocation": "Emplacement parent", + "@parentLocation": {}, + "part": "Pièce", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nouvelle pièce", + "@partCreate": {}, + "partCreateDetail": "Créer une nouvelle pièce dans cette catégorie", + "@partCreateDetail": {}, + "partEdited": "Pièce mise à jour", + "@partEdited": {}, + "parts": "Pièces", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Aucune pièces", + "@partsNone": {}, + "partNoResults": "Pas de pièces correspondant à la requête", + "@partNoResults": {}, + "partsStarred": "Pièces suivies", + "@partsStarred": {}, + "partsStarredNone": "Aucune pièce favorite disponible", + "@partsStarredNone": {}, + "partSuppliers": "Fournisseurs de pièces", + "@partSuppliers": {}, + "partCategory": "Catégorie de la pièce", + "@partCategory": {}, + "partCategoryTopLevel": "Catégorie de pièce parente", + "@partCategoryTopLevel": {}, + "partCategories": "Catégories de pièce", + "@partCategories": {}, + "partDetails": "Détails de la pièce", + "@partDetails": {}, + "partNotes": "Notes de la pièce", + "@partNotes": {}, + "partStock": "Stock de la pièce", + "@partStock": { + "description": "part stock" + }, + "password": "Mot de passe", + "@password": {}, + "passwordEmpty": "Le mot de passe peut pas être vide", + "@passwordEmpty": {}, + "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorisation requise", + "@permissionRequired": {}, + "printLabel": "Imprimer l'étiquette", + "@printLabel": {}, + "printLabelFailure": "Echec de l'impression", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiquette envoyée à l'imprimante", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Ajouter un profil serveur", + "@profileAdd": {}, + "profileConnect": "Se connecter au serveur", + "@profileConnect": {}, + "profileEdit": "Editer le profil du serveur", + "@profileEdit": {}, + "profileDelete": "Supprimer le profil du serveur", + "@profileDelete": {}, + "profileName": "Nom du profil", + "@profileName": {}, + "profileNone": "Aucun profil disponible", + "@profileNone": {}, + "profileNotSelected": "Aucun profil sélectionné", + "@profileNotSelected": {}, + "profileSelect": "Sélectionner le serveur InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Commande d’achat", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifier la commande d'achat", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Commandes d'achat", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bon de commande mis à jour", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Prix d'achat", + "@purchasePrice": {}, + "quantity": "Quantité", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "La quantité est vide", + "@quantityEmpty": {}, + "quantityInvalid": "La quantité n'est pas valide", + "@quantityInvalid": {}, + "quantityPositive": "La quantité doit être positive", + "@quantityPositive": {}, + "queryNoResults": "Pas de résultat pour votre requête", + "@queryNoResults": {}, + "received": "Reçu", + "@received": {}, + "receiveItem": "Articles reçus", + "@receiveItem": {}, + "receivedItem": "Article de stock reçu", + "@receivedItem": {}, + "refresh": "Actualiser", + "@refresh": {}, + "refreshing": "Actualisation en cours", + "@refreshing": {}, + "rejected": "Rejeté", + "@rejected": {}, + "releaseNotes": "Notes de Version", + "@releaseNotes": {}, + "remove": "Supprimer", + "@remove": { + "description": "remove" + }, + "removeStock": "Supprimer le stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Signaler un bug", + "@reportBug": {}, + "reportBugDescription": "Envoyer un rapport de bug (nécessite un compte GitHub)", + "@reportBugDescription": {}, + "results": "Résultats", + "@results": {}, + "request": "Requête", + "@request": {}, + "requestingData": "Demande de données", + "@requestingData": {}, + "required": "Requis", + "@required": { + "description": "This field is required" + }, + "response400": "Mauvaise requête", + "@response400": {}, + "response401": "Non autorisé", + "@response401": {}, + "response403": "Autorisation refusée", + "@response403": {}, + "response404": "Ressource non trouvée", + "@response404": {}, + "response405": "Méthode non autorisé", + "@response405": {}, + "response429": "Trop de requêtes", + "@response429": {}, + "response500": "Erreur interne du serveur", + "@response500": {}, + "response501": "Non implémenté", + "@response501": {}, + "response502": "Mauvaise passerelle", + "@response502": {}, + "response503": "Service indisponible", + "@response503": {}, + "response504": "Délai d'attente de la passerelle expiré", + "@response504": {}, + "response505": "Version HTTP non prise en charge", + "@response505": {}, + "responseData": "Données de la réponse", + "@responseData": {}, + "responseInvalid": "Code de réponse invalide", + "@responseInvalid": {}, + "responseUnknown": "Réponse inconnue", + "@responseUnknown": {}, + "result": "Résultat ", + "@result": { + "description": "" + }, + "returned": "Retourné", + "@returned": {}, + "salesOrders": "Ventes", + "@salesOrders": {}, + "save": "Enregistrer", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanner un code-barres", + "@scanBarcode": {}, + "scanIntoLocation": "Scanner vers l'emplacement", + "@scanIntoLocation": {}, + "search": "Rechercher", + "@search": { + "description": "search" + }, + "searchLocation": "Rechercher un emplacement", + "@searchLocation": {}, + "searchParts": "Rechercher de pièces", + "@searchParts": {}, + "searchStock": "Rechercher un stock", + "@searchStock": {}, + "select": "Sélectionner", + "@select": {}, + "selectFile": "Sélectionner un fichier", + "@selectFile": {}, + "selectImage": "Sélectionner une image", + "@selectImage": {}, + "selectLocation": "Sélectionnez un emplacement", + "@selectLocation": {}, + "send": "Envoyer", + "@send": {}, + "serialNumber": "Numéro de série", + "@serialNumber": {}, + "server": "Serveur", + "@server": {}, + "serverAddress": "Adresse du serveur", + "@serverAddress": {}, + "serverApiRequired": "Version de l'API requise", + "@serverApiRequired": {}, + "serverApiVersion": "Version de l'API du serveur", + "@serverApiVersion": {}, + "serverAuthenticationError": "Erreur lors de l'authentification", + "@serverAuthenticationError": {}, + "serverCertificateError": "Erreur de certificat", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Le certificat HTTPS du serveur n'est pas valide", + "@serverCertificateInvalid": {}, + "serverConnected": "Connecté au serveur", + "@serverConnected": {}, + "serverConnecting": "Connexion au serveur", + "@serverConnecting": {}, + "serverCouldNotConnect": "Connexion au serveur impossible", + "@serverCouldNotConnect": {}, + "serverEmpty": "Le serveur ne peut pas être vide", + "@serverEmpty": {}, + "serverError": "Erreur serveur", + "@serverError": {}, + "serverDetails": "Détails du serveur", + "@serverDetails": {}, + "serverMissingData": "La réponse du serveur ne possède pas les champs obligatoires", + "@serverMissingData": {}, + "serverOld": "Ancienne version du serveur", + "@serverOld": {}, + "serverSettings": "Paramètres du serveur", + "@serverSettings": {}, + "serverStart": "Le serveur doit débuter par http[s]", + "@serverStart": {}, + "settings": "Réglages", + "@settings": {}, + "serverInstance": "Instance du serveur", + "@serverInstance": {}, + "serverNotConnected": "Le serveur n'est pas connecté", + "@serverNotConnected": {}, + "sounds": "Sons", + "@sounds": {}, + "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Jouer une tonalité sonore en cas d'erreur du serveur", + "@soundOnServerError": {}, + "status": "État", + "@status": {}, + "statusCode": "Code d'état", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Quantité actuelle de stock disponible", + "@stockDetails": {}, + "stockItem": "Article en stock", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Articles en stock", + "@stockItems": {}, + "stockItemCreate": "Nouvel article en stock", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Créer un nouvel article en stock dans cet emplacement", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Supprimer l'article du stock", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Êtes-vous certain de vouloir supprimer cet article ?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Impossible de supprmer cet article", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Article supprimé", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historique du stock", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Afficher les informations de suivi de stock", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Article en stock transféré", + "@stockItemTransferred": {}, + "stockItemUpdated": "Article en stock mis à jour", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Aucun article en stock", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notes de l'article en stock", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Article en stock mis à jour", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Echec de la mise à jour de l'article en stock", + "@stockItemUpdateFailure": {}, + "stockLocation": "Emplacement du stock", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Emplacements du stock", + "@stockLocations": {}, + "stockTopLevel": "Emplacement de stock de premier niveau", + "@stockTopLevel": {}, + "strictHttps": "Utiliser HTTPS strict", + "@strictHttps": {}, + "strictHttpsDetails": "Obliger une vérification stricte des certificats HTTP", + "@strictHttpsDetails": {}, + "subcategory": "Sous-catégorie", + "@subcategory": {}, + "subcategories": "Sous-catégories", + "@subcategories": {}, + "sublocation": "Sous-emplacement", + "@sublocation": {}, + "sublocations": "Sous-emplacements", + "@sublocations": {}, + "sublocationNone": "Aucun sous-emplacement", + "@sublocationNone": {}, + "sublocationNoneDetail": "Aucun sous-emplacement disponible", + "@sublocationNoneDetail": {}, + "submitFeedback": "Soumettre le commentaire", + "@submitFeedback": {}, + "suppliedParts": "Composants fournis", + "@suppliedParts": {}, + "supplier": "Fournisseur", + "@supplier": {}, + "suppliers": "Fournisseurs", + "@suppliers": {}, + "supplierReference": "Référence du fournisseur", + "@supplierReference": {}, + "takePicture": "Prendre une photo", + "@takePicture": {}, + "targetDate": "Date Cible", + "@targetDate": {}, + "testName": "Nom de test", + "@testName": {}, + "testPassedOrFailed": "Test réussi ou échoué", + "@testPassedOrFailed": {}, + "testsRequired": "Tests requis", + "@testsRequired": {}, + "testResults": "Résultats du test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Ajouter un résultat de test", + "@testResultAdd": {}, + "testResultNone": "Aucun résultat de test", + "@testResultNone": {}, + "testResultNoneDetail": "Aucun résultat de test disponible", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Erreur lors de l'envoi du résultat du test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Résultats du test chargés", + "@testResultUploadPass": {}, + "timeout": "Délai dépassé", + "@timeout": { + "description": "" + }, + "tokenError": "Erreur du jeton", + "@tokenError": {}, + "tokenMissing": "Jeton manquant", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", + "@tokenMissingFromResponse": {}, + "transfer": "Transfert", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transférer le stock", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Traduire", + "@translate": {}, + "translateHelp": "Aidez à traduire l'application InvenTree", + "@translateHelp": {}, + "units": "Unités", + "@units": {}, + "unknownResponse": "Réponse inconnue", + "@unknownResponse": {}, + "upload": "Importer le fichier", + "@upload": {}, + "uploadFailed": "Échec du chargement du fichier", + "@uploadFailed": {}, + "uploadSuccess": "Fichier transféré", + "@uploadSuccess": {}, + "usedIn": "Utilisé dans", + "@usedIn": {}, + "usedInDetails": "Assemblages qui requièrent ce composant", + "@usedInDetails": {}, + "username": "Nom d'utilisateur", + "@username": {}, + "usernameEmpty": "Le nom d'utilisateur peut pas être vide", + "@usernameEmpty": {}, + "value": "Valeur", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "La valeur ne peut pas être vide", + "@valueCannotBeEmpty": {}, + "valueRequired": "La valeur est requise", + "@valueRequired": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Voir la pièce du fournisseur", + "@viewSupplierPart": {}, + "website": "Site web", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 36d80aa..2d1bbf1 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "he", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 36d80aa..98a69b4 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -1,5 +1,745 @@ { - "@@locale": "en", + "@@locale": "hu", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Névjegy", + "@about": {}, + "accountDetails": "Felhasználó adatok", + "@accountDetails": {}, + "actions": "Műveletek", + "@actions": { + "description": "" + }, + "actionsNone": "Nincsenek műveletek", + "@actionsNone": {}, + "add": "Hozzáadás", + "@add": { + "description": "add" + }, + "addStock": "Készlet növelése", + "@addStock": { + "description": "add stock" + }, + "address": "Cím", + "@address": {}, + "appAbout": "InvenTree névjegy", + "@appAbout": {}, + "appCredits": "További közreműködők", + "@appCredits": {}, + "appDetails": "App részletek", + "@appDetails": {}, + "appReleaseNotes": "Kiadási közlemények", + "@appReleaseNotes": {}, + "appSettings": "Alkalmazásbeállítások", + "@appSettings": {}, + "appSettingsDetails": "Inventree alkalmazás beállításai", + "@appSettingsDetails": {}, + "attachments": "Mellékletek", + "@attachments": {}, + "attachImage": "Kép csatolása", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nem találhatók mellékletek", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Melléklet kiválasztása", + "@attachmentSelect": {}, + "attention": "Figyelem", + "@attention": {}, + "availableStock": "Elérhető készlet", + "@availableStock": {}, + "barcodeAssign": "Vonalkód hozzárendelése", + "@barcodeAssign": {}, + "barcodeAssigned": "Vonalkód hozzárendelve", + "@barcodeAssigned": {}, + "barcodeError": "Vonalkód olvasási hiba", + "@barcodeError": {}, + "barcodeInUse": "Vonalkód már hozzárendelve", + "@barcodeInUse": {}, + "barcodeMissingHash": "Vonalkód hash hiányzik a válaszból", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nincs egyezés vonalkódra", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Készlet bevételezése az adott helyre", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Hely beolvasása", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Készlet tétel beolvasása", + "@barcodeScanItem": {}, + "barcodeTones": "Vonalkód hangszín", + "@barcodeTones": {}, + "barcodeUnassign": "Vonalkód leválasztása", + "@barcodeUnassign": {}, + "barcodeUnknown": "Vonalkód nem ismerhető fel", + "@barcodeUnknown": {}, + "batchCode": "Batch kód", + "@batchCode": {}, + "billOfMaterials": "Alkatrészjegyzék", + "@billOfMaterials": {}, + "bom": "Alkatrészjegyzék", + "@bom": {}, + "build": "Gyártás", + "@build": {}, + "building": "Gyártásban", + "@building": {}, + "cancel": "Mégsem", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategória", + "@category": {}, + "categoryCreate": "Új kategória", + "@categoryCreate": {}, + "categoryCreateDetail": "Alkatrész kategória létrehozása", + "@categoryCreateDetail": {}, + "categoryUpdated": "Alkatrész kategória módosítva", + "@categoryUpdated": {}, + "company": "Cég", + "@company": {}, + "companyEdit": "Cég szerkesztése", + "@companyEdit": {}, + "companyNoResults": "Nincs a lekérdezésnek megfelelő cég", + "@companyNoResults": {}, + "companyUpdated": "Cég adatai frissítve", + "@companyUpdated": {}, + "companies": "Cégek", + "@companies": {}, + "configureServer": "Kiszolgáló beállítások konfigurálása", + "@configureServer": {}, + "connectionRefused": "A kapcsolat visszautasítva", + "@connectionRefused": {}, + "count": "Mennyiség", + "@count": { + "description": "Count" + }, + "countStock": "Leltározás", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Közreműködők", + "@credits": {}, + "customers": "Vevők", + "@customers": {}, + "damaged": "Sérült", + "@damaged": {}, + "delete": "Törlés", + "@delete": {}, + "deletePart": "Alkatrész törlése", + "@deletePart": {}, + "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", + "@deletePartDetail": {}, + "description": "Leírás", + "@description": {}, + "destroyed": "Megsemmisült", + "@destroyed": {}, + "details": "Részletek", + "@details": { + "description": "details" + }, + "documentation": "Dokumentáció", + "@documentation": {}, + "downloading": "Fájl letöltése", + "@downloading": {}, + "downloadError": "Letöltési hiba", + "@downloadError": {}, + "edit": "Szerkesztés", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategória szerkesztése", + "@editCategory": {}, + "editLocation": "Hely szerkesztése", + "@editLocation": {}, + "editNotes": "Megjegyzések szerkesztése", + "@editNotes": {}, + "editPart": "Alkatrész szerkesztése", + "@editPart": { + "description": "edit part" + }, + "editItem": "Készlet tétel szerkesztése", + "@editItem": {}, + "enterPassword": "Jelszó megadása", + "@enterPassword": {}, + "enterUsername": "Felhasználó megadása", + "@enterUsername": {}, + "error": "Hiba", + "@error": { + "description": "Error" + }, + "errorCreate": "Hiba az adatbázis bejegyzés létrehozása közben", + "@errorCreate": {}, + "errorDelete": "Hiba az adatbázis bejegyzés törlése közben", + "@errorDelete": {}, + "errorDetails": "Hiba részletei", + "@errorDetails": {}, + "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", + "@errorFetch": {}, + "errorReporting": "Hibajelentés", + "@errorReporting": {}, + "errorReportUpload": "Hibajelentések feltöltése", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", + "@errorReportUploadDetails": {}, + "feedback": "Visszajelzés", + "@feedback": {}, + "feedbackError": "Visszajelzés küldése sikertelen", + "@feedbackError": {}, + "feedbackSuccess": "Visszajelzés elküldve", + "@feedbackSuccess": {}, + "formatException": "Formátum hiba", + "@formatException": {}, + "formatExceptionJson": "JSON adatformátum hiba", + "@formatExceptionJson": {}, + "formError": "Form hiba", + "@formError": {}, + "history": "Előzmények", + "@history": { + "description": "history" + }, + "homeScreen": "Főképernyő", + "@homeScreen": {}, + "homeScreenSettings": "Főképernyő beállítások konfigurálása", + "@homeScreenSettings": {}, + "homeShowPo": "Beszerzési rendelések megjelenítése", + "@homeShowPo": {}, + "homeShowSubscribed": "Értesítésre beállított alkatrészek", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Beszállítók megjelenítése", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Gyártók megjelenítése", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Gyártók gomb megjelenítése a főoldalon", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Vevők megjelenítése", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Vevők gomb megjelenítése a főoldalon", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Kép feltöltése sikertelen", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Kép feltöltve", + "@imageUploadSuccess": {}, + "inactive": "Inaktív", + "@inactive": {}, + "inactiveDetail": "Ez az alkatrész inaktív lett", + "@inactiveDetail": {}, + "includeSubcategories": "Alkategóriákkal együtt", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Al-kategóriájú alkatrészek megjelenítése a lista nézetben", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alhelyekkel együtt", + "@includeSublocations": {}, + "includeSublocationsDetail": "Al-helyen lévő alkatrészek megjelenítése a lista nézetben", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Nem teljes profil adatok", + "@incompleteDetails": {}, + "internalPartNumber": "Belső alkatrész azonosító", + "@internalPartNumber": {}, + "info": "Infó", + "@info": {}, + "inProduction": "Gyártásban", + "@inProduction": {}, + "inProductionDetail": "Ez a készlet tétel gyártásban van", + "@inProductionDetail": {}, + "invalidHost": "Érvénytelen hostnév", + "@invalidHost": {}, + "invalidHostDetails": "A megadott hostnév nem érvényes", + "@invalidHostDetails": {}, + "invalidPart": "Érvénytelen alkatrész", + "@invalidPart": {}, + "invalidPartCategory": "Érvénytelen kategória", + "@invalidPartCategory": {}, + "invalidStockLocation": "Érvénytelen készlet hely", + "@invalidStockLocation": {}, + "invalidStockItem": "Érvénytelen készlet tétel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", + "@invalidUsernamePassword": {}, + "issueDate": "Kiállítás dátuma", + "@issueDate": {}, + "itemInLocation": "A tétel már a megadott helyen van", + "@itemInLocation": {}, + "keywords": "Kulcsszavak", + "@keywords": {}, + "lastStocktake": "Utolsó leltár", + "@lastStocktake": {}, + "lastUpdated": "Utoljára módosítva", + "@lastUpdated": {}, + "lineItem": "Sortétel", + "@lineItem": {}, + "lineItems": "Sortételek", + "@lineItems": {}, + "locationCreate": "Új hely", + "@locationCreate": {}, + "locationCreateDetail": "Új készlet hely létrehozása", + "@locationCreateDetail": {}, + "locationNotSet": "Nincs megadva hely", + "@locationNotSet": {}, + "locationUpdated": "Készlet hely adatai frissítve", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Elveszett", + "@lost": {}, + "manufacturers": "Gyártók", + "@manufacturers": {}, + "missingData": "Hiányzó adatok", + "@missingData": {}, + "name": "Név", + "@name": {}, + "notConnected": "Nincs kapcsolódva", + "@notConnected": {}, + "notes": "Megjegyzések", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nincs válasz a kiszolgálótól", + "@noResponse": {}, + "noResults": "Nincs találat", + "@noResults": {}, + "noSubcategories": "Nincsenek alkategóriák", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nincsenek alkategóriák", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Érvénytelen szám", + "@numberInvalid": {}, + "onOrder": "Beszállítás alatt", + "@onOrder": {}, + "onOrderDetails": "Alaktrészek beszállítás alatt", + "@onOrderDetails": {}, + "packaging": "Csomagolás", + "@packaging": {}, + "packageName": "Csomag neve", + "@packageName": {}, + "parent": "Szülő", + "@parent": {}, + "parentCategory": "Szülő kategória", + "@parentCategory": {}, + "parentLocation": "Szülő hely", + "@parentLocation": {}, + "part": "Alkatrész", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Új alkatrész", + "@partCreate": {}, + "partCreateDetail": "Alkatrész létrehozása ebben a kategóriában", + "@partCreateDetail": {}, + "partEdited": "Alkatrész frissítve", + "@partEdited": {}, + "parts": "Alkatrészek", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Nincsenek alkatrészek", + "@partsNone": {}, + "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", + "@partNoResults": {}, + "partsStarred": "Értesítésre beállított alkatrészek", + "@partsStarred": {}, + "partsStarredNone": "Nincsenek csillagozott alkatrészek", + "@partsStarredNone": {}, + "partSuppliers": "Alkatrész beszállítók", + "@partSuppliers": {}, + "partCategory": "Alkatrész kategória", + "@partCategory": {}, + "partCategoryTopLevel": "Legfelső szintű alkatrész kategória", + "@partCategoryTopLevel": {}, + "partCategories": "Alkatrész kategóriák", + "@partCategories": {}, + "partDetails": "Alkatrész részletei", + "@partDetails": {}, + "partNotes": "Alkatrész megjegyzések", + "@partNotes": {}, + "partStock": "Alkatrész készlet", + "@partStock": { + "description": "part stock" + }, + "password": "Jelszó", + "@password": {}, + "passwordEmpty": "Jelszó nem lehet üres", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", + "@permissionAccountDenied": {}, + "permissionRequired": "Engedély szükséges", + "@permissionRequired": {}, + "printLabel": "Címke nyomtatása", + "@printLabel": {}, + "printLabelFailure": "Címkenyomtatás sikertelen", + "@printLabelFailure": {}, + "printLabelSuccess": "Címke nyomtatónak elküldve", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Kiszolgáló profil hozzáadása", + "@profileAdd": {}, + "profileConnect": "Kapcsolódás a kiszolgálóhoz", + "@profileConnect": {}, + "profileEdit": "Kiszolgáló profil szerkesztése", + "@profileEdit": {}, + "profileDelete": "Kiszolgáló profil törlése", + "@profileDelete": {}, + "profileName": "Profil neve", + "@profileName": {}, + "profileNone": "Nincsenek profilok", + "@profileNone": {}, + "profileNotSelected": "Nincs kiválasztva profil", + "@profileNotSelected": {}, + "profileSelect": "Válassz InvenTree kiszolgálót", + "@profileSelect": {}, + "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", + "@profileTapToCreate": {}, + "purchaseOrder": "Beszerzési rendelés", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Beszerzési rendelések", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Beszerzési rendelés frissítve", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Beszerzési ár", + "@purchasePrice": {}, + "quantity": "Mennyiség", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Mennyiség üres", + "@quantityEmpty": {}, + "quantityInvalid": "Mennyiség érvénytelen", + "@quantityInvalid": {}, + "quantityPositive": "Mennyiség pozitív kell legyen", + "@quantityPositive": {}, + "queryNoResults": "Nincs találat", + "@queryNoResults": {}, + "received": "Beérkezett", + "@received": {}, + "receiveItem": "Bevételezés", + "@receiveItem": {}, + "receivedItem": "Beérkezett készlet", + "@receivedItem": {}, + "refresh": "Frissítés", + "@refresh": {}, + "refreshing": "Frissítés...", + "@refreshing": {}, + "rejected": "Elutasított", + "@rejected": {}, + "releaseNotes": "Kiadási közlemények", + "@releaseNotes": {}, + "remove": "Törlés", + "@remove": { + "description": "remove" + }, + "removeStock": "Készlet csökkentése", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hibabejelentés", + "@reportBug": {}, + "reportBugDescription": "Hibabejelentés küldése (GitHub fiók szükséges)", + "@reportBugDescription": {}, + "results": "Eredmények", + "@results": {}, + "request": "Kérés", + "@request": {}, + "requestingData": "Adatok lekérése", + "@requestingData": {}, + "required": "Kötelező", + "@required": { + "description": "This field is required" + }, + "response400": "Rossz kérés", + "@response400": {}, + "response401": "Jogosulatlan", + "@response401": {}, + "response403": "Hozzáférés megtagadva", + "@response403": {}, + "response404": "Erőforrás nem található", + "@response404": {}, + "response405": "Metódus nincs engedélyezve", + "@response405": {}, + "response429": "Túl sok kérés", + "@response429": {}, + "response500": "Belső kiszolgáló hiba", + "@response500": {}, + "response501": "Nincs implementálva", + "@response501": {}, + "response502": "Rossz átjáró", + "@response502": {}, + "response503": "A szolgáltatás nem érhető el", + "@response503": {}, + "response504": "Átjáró időtúllépés", + "@response504": {}, + "response505": "HTTP verzió nem támogatott", + "@response505": {}, + "responseData": "Válasz adatok", + "@responseData": {}, + "responseInvalid": "Érvénytelen válasz kód", + "@responseInvalid": {}, + "responseUnknown": "Ismeretlen válasz", + "@responseUnknown": {}, + "result": "Eredmény", + "@result": { + "description": "" + }, + "returned": "Visszaküldve", + "@returned": {}, + "salesOrders": "Vevői rendelések", + "@salesOrders": {}, + "save": "Mentés", + "@save": { + "description": "Save" + }, + "scanBarcode": "Vonalkód beolvasása", + "@scanBarcode": {}, + "scanIntoLocation": "Beolvasás helyre", + "@scanIntoLocation": {}, + "search": "Keresés", + "@search": { + "description": "search" + }, + "searchLocation": "Hely keresése", + "@searchLocation": {}, + "searchParts": "Alkatrészek keresése", + "@searchParts": {}, + "searchStock": "Készlet keresése", + "@searchStock": {}, + "select": "Kiválaszt", + "@select": {}, + "selectFile": "Fájl kiválasztása", + "@selectFile": {}, + "selectImage": "Válassz képet", + "@selectImage": {}, + "selectLocation": "Válassz helyet", + "@selectLocation": {}, + "send": "Küldés", + "@send": {}, + "serialNumber": "Sorozatszám", + "@serialNumber": {}, + "server": "Kiszolgáló", + "@server": {}, + "serverAddress": "Kiszolgáló címe", + "@serverAddress": {}, + "serverApiRequired": "Szükséges API verzió", + "@serverApiRequired": {}, + "serverApiVersion": "Szerver API verzió", + "@serverApiVersion": {}, + "serverAuthenticationError": "Hitelesítési hiba", + "@serverAuthenticationError": {}, + "serverCertificateError": "Tanúsítvány hiba", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Érvénytelen kiszolgáló HTTPS tanúsítvány", + "@serverCertificateInvalid": {}, + "serverConnected": "Kapcsolódva a kiszolgálóhoz", + "@serverConnected": {}, + "serverConnecting": "Kapcsolódás a kiszolgálóhoz", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nem sikerült kapcsolódni a kiszolgálóhoz", + "@serverCouldNotConnect": {}, + "serverEmpty": "A kiszolgálónév nem lehet üres", + "@serverEmpty": {}, + "serverError": "Kiszolgálóhiba", + "@serverError": {}, + "serverDetails": "Kiszolgáló részletei", + "@serverDetails": {}, + "serverMissingData": "A kiszolgáló válaszából szükséges mezők hiányoznak", + "@serverMissingData": {}, + "serverOld": "Régi kiszolgáló verzió", + "@serverOld": {}, + "serverSettings": "Kiszolgáló beállítások", + "@serverSettings": {}, + "serverStart": "A kiszolgálónak http(s) kezdetűnek kell lennie", + "@serverStart": {}, + "settings": "Beállítások", + "@settings": {}, + "serverInstance": "Kiszolgáló példány", + "@serverInstance": {}, + "serverNotConnected": "Kiszolgáló nem csatlakozik", + "@serverNotConnected": {}, + "sounds": "Hangok", + "@sounds": {}, + "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", + "@soundOnServerError": {}, + "status": "Állapot", + "@status": {}, + "statusCode": "Állapot kód", + "@statusCode": {}, + "stock": "Készlet", + "@stock": { + "description": "stock" + }, + "stockDetails": "Jelenleg elérhető készlet mennyiség", + "@stockDetails": {}, + "stockItem": "Készlet tétel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Készlet tételek", + "@stockItems": {}, + "stockItemCreate": "Új készlet tétel", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Új készlet tétel létrehozása ezen a helyen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Készlet tétel törlése", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Biztosan törölni szeretnéd ezt a készlet tételt?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Készlet tétel nem törölhető", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Készlet tétel törölve", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Készlettörténet", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Készlettörténet megjelenítése", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Készlet áthelyezve", + "@stockItemTransferred": {}, + "stockItemUpdated": "Készlet tétel feltöltve", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nincs elérhető készlet", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Készlet tétel megjegyzések", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Készlet tétel feltöltve", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Készlet tétel módosítása sikertelen", + "@stockItemUpdateFailure": {}, + "stockLocation": "Készlet hely", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Készlethelyek", + "@stockLocations": {}, + "stockTopLevel": "Legfelső szintű készlet hely", + "@stockTopLevel": {}, + "strictHttps": "Kizárólag HTTPS használata", + "@strictHttps": {}, + "strictHttpsDetails": "HTTPS tanúsítványok szigorú ellenőrzése", + "@strictHttpsDetails": {}, + "subcategory": "Alkategória", + "@subcategory": {}, + "subcategories": "Alkategóriák", + "@subcategories": {}, + "sublocation": "Alhely", + "@sublocation": {}, + "sublocations": "Alhelyek", + "@sublocations": {}, + "sublocationNone": "Nincsenek alhelyek", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nincsenek elérhető alhelyek", + "@sublocationNoneDetail": {}, + "submitFeedback": "Visszajelzés Küldése", + "@submitFeedback": {}, + "suppliedParts": "Szállított alkatrészek", + "@suppliedParts": {}, + "supplier": "Beszállító", + "@supplier": {}, + "suppliers": "Beszállítók", + "@suppliers": {}, + "supplierReference": "Beszállítói azonosító", + "@supplierReference": {}, + "takePicture": "Fotó készítése", + "@takePicture": {}, + "targetDate": "Cél dátum", + "@targetDate": {}, + "templatePart": "Szülő sablon alkatrész", + "@templatePart": {}, + "testName": "Teszt neve", + "@testName": {}, + "testPassedOrFailed": "Teszt sikeres vagy sikertelen", + "@testPassedOrFailed": {}, + "testsRequired": "Szükséges tesztek", + "@testsRequired": {}, + "testResults": "Teszt eredmények", + "@testResults": { + "description": "" + }, + "testResultAdd": "Teszt eredmény hozzáadása", + "@testResultAdd": {}, + "testResultNone": "Nincsenek teszt eredmények", + "@testResultNone": {}, + "testResultNoneDetail": "Teszt eredmény nem áll rendelkezésre", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hiba a teszt eredmény feltöltése közben", + "@testResultUploadFail": {}, + "testResultUploadPass": "Teszt eredmény feltöltve", + "@testResultUploadPass": {}, + "timeout": "Időtúllépés", + "@timeout": { + "description": "" + }, + "tokenError": "Token hiba", + "@tokenError": {}, + "tokenMissing": "Hiányzó token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", + "@tokenMissingFromResponse": {}, + "transfer": "Áthelyezés", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Készlet áthelyezése", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Fordítás", + "@translate": {}, + "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", + "@translateHelp": {}, + "units": "Mértékegységek", + "@units": {}, + "unknownResponse": "Ismeretlen válasz", + "@unknownResponse": {}, + "upload": "Feltöltés", + "@upload": {}, + "uploadFailed": "Fájl feltöltése sikertelen", + "@uploadFailed": {}, + "uploadSuccess": "Fájl feltöltve", + "@uploadSuccess": {}, + "usedIn": "Felhasználva ebben", + "@usedIn": {}, + "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", + "@usedInDetails": {}, + "username": "Felhasználónév", + "@username": {}, + "usernameEmpty": "Felhasználónév nem lehet üres", + "@usernameEmpty": {}, + "value": "Érték", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Az érték nem lehet üres", + "@valueCannotBeEmpty": {}, + "valueRequired": "Érték megadása szükséges", + "@valueRequired": {}, + "version": "Verzió", + "@version": {}, + "viewSupplierPart": "Beszállítói alkatrész megtekintése", + "@viewSupplierPart": {}, + "website": "Weboldal", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 36d80aa..c917076 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "id", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 36d80aa..4df3b7d 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -1,5 +1,505 @@ { - "@@locale": "en", + "@@locale": "it", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Info", + "@about": {}, + "accountDetails": "Dettagli account", + "@accountDetails": {}, + "actions": "Azioni", + "@actions": { + "description": "" + }, + "actionsNone": "Nessuna azione disponibile", + "@actionsNone": {}, + "add": "Aggiungi", + "@add": { + "description": "add" + }, + "address": "Indirizzo", + "@address": {}, + "appAbout": "Info su InvenTree", + "@appAbout": {}, + "appCredits": "Riconoscimenti addizionali", + "@appCredits": {}, + "appDetails": "Dettagli App", + "@appDetails": {}, + "appReleaseNotes": "Mostra le note di rilascio dell'app", + "@appReleaseNotes": {}, + "appSettings": "Impostazioni App", + "@appSettings": {}, + "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", + "@appSettingsDetails": {}, + "attachments": "Allegati", + "@attachments": {}, + "attachImage": "Allega Immagine", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nessun allegato trovato", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Seleziona allegato", + "@attachmentSelect": {}, + "attention": "Attenzione", + "@attention": {}, + "barcodeAssign": "Assegna Codice A Barre", + "@barcodeAssign": {}, + "barcodeAssigned": "Codice a barre assegnato", + "@barcodeAssigned": {}, + "barcodeError": "Errore scansione codice a barre", + "@barcodeError": {}, + "barcodeInUse": "Codice a barre già in uso", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dati hash codice a barre mancanti dalla risposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nessuna corrispondenza per il codice a barre", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Codice a barre non assegnato", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scansiona per assegnare codice a barre", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeTones": "Toni Codice a Barre", + "@barcodeTones": {}, + "barcodeUnassign": "Deseleziona Il Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Codice a barre non leggibile", + "@barcodeUnknown": {}, + "batchCode": "Codice Lotto", + "@batchCode": {}, + "billOfMaterials": "Distinta materiali", + "@billOfMaterials": {}, + "bom": "Distinta materiali", + "@bom": {}, + "build": "Crea", + "@build": {}, + "cancel": "Annulla", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nuova categoria", + "@categoryCreate": {}, + "company": "Azienda", + "@company": {}, + "companyEdit": "Modifica azienda", + "@companyEdit": {}, + "companyNoResults": "Nessuna azienda corrispondente alla query", + "@companyNoResults": {}, + "companies": "Aziende", + "@companies": {}, + "connectionRefused": "Connessione rifiutata", + "@connectionRefused": {}, + "count": "Quantità", + "@count": { + "description": "Count" + }, + "credits": "Riconoscimenti", + "@credits": {}, + "customers": "Clienti", + "@customers": {}, + "damaged": "Danneggiato", + "@damaged": {}, + "delete": "Cancella", + "@delete": {}, + "description": "Descrizione", + "@description": {}, + "destroyed": "Distrutto", + "@destroyed": {}, + "details": "Dettagli", + "@details": { + "description": "details" + }, + "documentation": "Documentazione", + "@documentation": {}, + "downloading": "File in download", + "@downloading": {}, + "downloadError": "Errore download", + "@downloadError": {}, + "edit": "Modifica", + "@edit": { + "description": "edit" + }, + "editCategory": "Modifica Categoria", + "@editCategory": {}, + "enterPassword": "Inserire la password", + "@enterPassword": {}, + "enterUsername": "Inserisci nome utente", + "@enterUsername": {}, + "error": "Errore", + "@error": { + "description": "Error" + }, + "errorCreate": "Errore nella creazione della voce del database", + "@errorCreate": {}, + "errorDetails": "Dettagli errore", + "@errorDetails": {}, + "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", + "@errorFetch": {}, + "feedback": "Commenti e suggerimenti", + "@feedback": {}, + "feedbackError": "Errore nell'invio del feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback inviato", + "@feedbackSuccess": {}, + "formatException": "Eccezione Formato", + "@formatException": {}, + "formatExceptionJson": "Eccezione formato dati JSON", + "@formatExceptionJson": {}, + "formError": "Errore Modulo", + "@formError": {}, + "history": "Cronologia", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Il caricamento della foto è fallito", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Immagine caricata", + "@imageUploadSuccess": {}, + "inactive": "Inattivo", + "@inactive": {}, + "includeSubcategories": "Includi sottocategorie", + "@includeSubcategories": {}, + "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", + "@incompleteDetails": {}, + "info": "Info", + "@info": {}, + "invalidHost": "Nome host non valido", + "@invalidHost": {}, + "invalidHostDetails": "Il nome host fornito non è valido", + "@invalidHostDetails": {}, + "invalidUsernamePassword": "Combinazione nome utente e password non valida", + "@invalidUsernamePassword": {}, + "issueDate": "Data di emissione", + "@issueDate": {}, + "itemInLocation": "Elemento già in posizione", + "@itemInLocation": {}, + "keywords": "Parole Chiave", + "@keywords": {}, + "lastUpdated": "Ultimo aggiornamento", + "@lastUpdated": {}, + "lost": "Perso", + "@lost": {}, + "manufacturers": "Produttori", + "@manufacturers": {}, + "missingData": "Dati mancanti", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "notConnected": "Non connesso", + "@notConnected": {}, + "notes": "Note", + "@notes": { + "description": "Notes" + }, + "noResponse": "Nessuna risposta dal server", + "@noResponse": {}, + "noResults": "Nessun risultato", + "@noResults": {}, + "noSubcategories": "Nessuna sotto categoria", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Numero non valido", + "@numberInvalid": {}, + "onOrderDetails": "Articoli attualmente in ordine", + "@onOrderDetails": {}, + "packaging": "Confezionamento", + "@packaging": {}, + "packageName": "Nome pacchetto", + "@packageName": {}, + "parent": "Superiore", + "@parent": {}, + "parentCategory": "Categoria Superiore", + "@parentCategory": {}, + "parts": "Articoli", + "@parts": { + "description": "Part (multiple)" + }, + "partSuppliers": "Fornitori articoli", + "@partSuppliers": {}, + "password": "Password", + "@password": {}, + "passwordEmpty": "La password non può essere vuota", + "@passwordEmpty": {}, + "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorizzazione necessaria", + "@permissionRequired": {}, + "profile": "Profilo", + "@profile": {}, + "profileAdd": "Aggiungi Profilo Server", + "@profileAdd": {}, + "profileConnect": "Connetti al Server", + "@profileConnect": {}, + "profileEdit": "Modifica il profilo del Server", + "@profileEdit": {}, + "profileDelete": "Elimina Profilo Del Server", + "@profileDelete": {}, + "profileName": "Nome Profilo", + "@profileName": {}, + "profileNone": "Nessun profilo disponibile", + "@profileNone": {}, + "profileNotSelected": "Nessun profilo selezionato", + "@profileNotSelected": {}, + "profileSelect": "Seleziona Server InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Tocca per creare o selezionare un profilo", + "@profileTapToCreate": {}, + "purchaseOrder": "Ordine d'acquisto", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Modifica ordine d'acquisto", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Ordini d'acquisto", + "@purchaseOrders": {}, + "purchasePrice": "Prezzo d'acquisto", + "@purchasePrice": {}, + "quantity": "Quantità", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Quantità vuota", + "@quantityEmpty": {}, + "quantityInvalid": "La quantità non è valida", + "@quantityInvalid": {}, + "quantityPositive": "La quantità deve essere positiva", + "@quantityPositive": {}, + "queryNoResults": "Nessun risultato per la tua ricerca", + "@queryNoResults": {}, + "received": "Ricevuto", + "@received": {}, + "receiveItem": "Ricevi Articolo", + "@receiveItem": {}, + "refresh": "Aggiorna", + "@refresh": {}, + "refreshing": "In aggiornamento", + "@refreshing": {}, + "rejected": "Respinto", + "@rejected": {}, + "releaseNotes": "Note di Rilascio", + "@releaseNotes": {}, + "remove": "Rimuovi", + "@remove": { + "description": "remove" + }, + "reportBug": "Segnala un bug", + "@reportBug": {}, + "results": "Risultati", + "@results": {}, + "request": "Richiesta", + "@request": {}, + "requestingData": "Dati in richiesta", + "@requestingData": {}, + "required": "Richiesto", + "@required": { + "description": "This field is required" + }, + "response400": "Richiesta non valida", + "@response400": {}, + "response401": "Non Autorizzato", + "@response401": {}, + "response403": "Permesso negato", + "@response403": {}, + "response404": "Risorsa non trovata", + "@response404": {}, + "response405": "Metodo non consentito", + "@response405": {}, + "response429": "Troppe richieste", + "@response429": {}, + "response500": "Errore Interno del Server", + "@response500": {}, + "response501": "Non implementato", + "@response501": {}, + "response502": "Gateway Errato", + "@response502": {}, + "response503": "Servizio Non Disponibile", + "@response503": {}, + "response504": "Timeout del gateway", + "@response504": {}, + "response505": "Versione HTTP non supportata", + "@response505": {}, + "responseData": "Dati risposta", + "@responseData": {}, + "responseInvalid": "Codice Risposta Non Valido", + "@responseInvalid": {}, + "responseUnknown": "Risposta Sconosciuta", + "@responseUnknown": {}, + "result": "Risultato", + "@result": { + "description": "" + }, + "returned": "Restituito", + "@returned": {}, + "salesOrders": "Ordini di vendita", + "@salesOrders": {}, + "save": "Salva", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scansiona codice a barre", + "@scanBarcode": {}, + "search": "Cerca", + "@search": { + "description": "search" + }, + "select": "Seleziona", + "@select": {}, + "selectFile": "Seleziona file", + "@selectFile": {}, + "selectImage": "Seleziona un'immagine", + "@selectImage": {}, + "send": "Invia", + "@send": {}, + "serialNumber": "Numero seriale", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Indirizzo del server", + "@serverAddress": {}, + "serverApiRequired": "Versione API Richiesta", + "@serverApiRequired": {}, + "serverApiVersion": "Versione API Server", + "@serverApiVersion": {}, + "serverAuthenticationError": "Errore di autenticazione", + "@serverAuthenticationError": {}, + "serverCertificateError": "Errore certificato", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Il certificato del server non è valido", + "@serverCertificateInvalid": {}, + "serverConnected": "Connesso al Server", + "@serverConnected": {}, + "serverConnecting": "Connessione al server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Impossibile connettersi al server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Nome server non può essere vuoto", + "@serverEmpty": {}, + "serverError": "Errore del server", + "@serverError": {}, + "serverDetails": "Dettagli del server", + "@serverDetails": {}, + "serverMissingData": "Dati mancanti nella risposta del server", + "@serverMissingData": {}, + "serverOld": "Versione Vecchia Del Server", + "@serverOld": {}, + "serverSettings": "Impostazioni Server", + "@serverSettings": {}, + "serverStart": "Il server deve iniziare con http[s]", + "@serverStart": {}, + "settings": "Impostazioni", + "@settings": {}, + "serverInstance": "Istanza Del Server", + "@serverInstance": {}, + "serverNotConnected": "Server non connesso", + "@serverNotConnected": {}, + "sounds": "Audio", + "@sounds": {}, + "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Riproduci il tono sonoro su un errore del server", + "@soundOnServerError": {}, + "status": "Stato", + "@status": {}, + "statusCode": "Codice di stato", + "@statusCode": {}, + "stock": "Magazzino", + "@stock": { + "description": "stock" + }, + "subcategory": "Sottocategoria", + "@subcategory": {}, + "subcategories": "Sottocategorie", + "@subcategories": {}, + "submitFeedback": "Invia feedback", + "@submitFeedback": {}, + "supplier": "Fornitore", + "@supplier": {}, + "suppliers": "Fornitori", + "@suppliers": {}, + "supplierReference": "Riferimento fornitore", + "@supplierReference": {}, + "takePicture": "Scatta Foto", + "@takePicture": {}, + "testName": "Nome del test", + "@testName": {}, + "testPassedOrFailed": "Test superato o fallito", + "@testPassedOrFailed": {}, + "testsRequired": "Test Richiesti", + "@testsRequired": {}, + "testResults": "Risultati del test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Aggiungi Risultato Test", + "@testResultAdd": {}, + "testResultNone": "Nessun Risultato Del Test", + "@testResultNone": {}, + "testResultNoneDetail": "Nessun risultato del test disponibile", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Errore nel caricamento del risultato del test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Risultato del test caricato", + "@testResultUploadPass": {}, + "timeout": "Tempo Scaduto", + "@timeout": { + "description": "" + }, + "tokenError": "Errore Token", + "@tokenError": {}, + "tokenMissing": "Token Mancante", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", + "@tokenMissingFromResponse": {}, + "transfer": "Trasferisci", + "@transfer": { + "description": "transfer" + }, + "translate": "Traduci", + "@translate": {}, + "translateHelp": "Aiuta a tradurre l'app InvenTree", + "@translateHelp": {}, + "units": "Unità", + "@units": {}, + "unknownResponse": "Risposta Sconosciuta", + "@unknownResponse": {}, + "upload": "Carica", + "@upload": {}, + "uploadFailed": "Caricamento di file non riuscito", + "@uploadFailed": {}, + "uploadSuccess": "File caricato", + "@uploadSuccess": {}, + "usedIn": "Viene utilizzato in", + "@usedIn": {}, + "username": "Nome utente", + "@username": {}, + "usernameEmpty": "Il nome utente non può essere vuoto", + "@usernameEmpty": {}, + "value": "Valore", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Il valore non può essere vuoto", + "@valueCannotBeEmpty": {}, + "valueRequired": "È richiesto un valore", + "@valueRequired": {}, + "version": "Versione", + "@version": {}, + "viewSupplierPart": "Visualizza Fornitore", + "@viewSupplierPart": {}, + "website": "Sito Web", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 36d80aa..c55ad78 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,5 +1,682 @@ { - "@@locale": "en", + "@@locale": "ja", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "概要", + "@about": {}, + "accountDetails": "アカウントの詳細", + "@accountDetails": {}, + "actions": "アクション", + "@actions": { + "description": "" + }, + "actionsNone": "利用可能なアクションはありません", + "@actionsNone": {}, + "add": "追加", + "@add": { + "description": "add" + }, + "addStock": "在庫を追加", + "@addStock": { + "description": "add stock" + }, + "address": "アドレス", + "@address": {}, + "appAbout": "InvenTree について", + "@appAbout": {}, + "appCredits": "すぺしゃる★さんくす!", + "@appCredits": {}, + "appDetails": "アプリ詳細", + "@appDetails": {}, + "appReleaseNotes": "アプリのリリースノートを表示", + "@appReleaseNotes": {}, + "appSettings": "アプリ設定", + "@appSettings": {}, + "appSettingsDetails": "アプリ設定を構成します", + "@appSettingsDetails": {}, + "attachments": "添付ファイル", + "@attachments": {}, + "attachImage": "画像を添付", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "添付ファイルが見つかりません。", + "@attachmentNone": {}, + "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "添付ファイルを選択", + "@attachmentSelect": {}, + "attention": "注意", + "@attention": {}, + "availableStock": "在庫あり", + "@availableStock": {}, + "barcodeAssign": "バーコードを割り当てる", + "@barcodeAssign": {}, + "barcodeAssigned": "バーコードが割り当てられました", + "@barcodeAssigned": {}, + "barcodeError": "バーコードのスキャンエラー", + "@barcodeError": {}, + "barcodeInUse": "バーコードは既に割り当てられています", + "@barcodeInUse": {}, + "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "バーコードが一致しません", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "バーコードが割り当てられていません", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "スキャンしてバーコードを割り当てます", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "InvenTree バーコードをスキャンする", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "在庫アイテムを在庫場所にスキャン", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "在庫場所をスキャン", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "在庫アイテムをスキャン", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "バーコードの割り当てを解除", + "@barcodeUnassign": {}, + "barcodeUnknown": "バーコードが認識されません", + "@barcodeUnknown": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "ビルド", + "@build": {}, + "building": "ビルド", + "@building": {}, + "cancel": "キャンセル", + "@cancel": { + "description": "Cancel" + }, + "category": "カテゴリ", + "@category": {}, + "categoryCreate": "新規カテゴリ", + "@categoryCreate": {}, + "categoryCreateDetail": "新しい部品カテゴリを作成", + "@categoryCreateDetail": {}, + "categoryUpdated": "部品カテゴリを更新しました", + "@categoryUpdated": {}, + "company": "会社", + "@company": {}, + "companyEdit": "会社を編集", + "@companyEdit": {}, + "companyNoResults": "検索条件に一致する会社はありません", + "@companyNoResults": {}, + "companyUpdated": "会社の詳細を更新しました", + "@companyUpdated": {}, + "companies": "会社", + "@companies": {}, + "configureServer": "サーバー設定", + "@configureServer": {}, + "connectionRefused": "接続を拒否しました", + "@connectionRefused": {}, + "count": "カウント", + "@count": { + "description": "Count" + }, + "countStock": "在庫数", + "@countStock": { + "description": "Count Stock" + }, + "credits": "謝辞", + "@credits": {}, + "customers": "顧客", + "@customers": {}, + "damaged": "破損", + "@damaged": {}, + "delete": "削除", + "@delete": {}, + "deletePart": "部品を削除", + "@deletePart": {}, + "deletePartDetail": "データベースからこの部品を削除します", + "@deletePartDetail": {}, + "description": "説明", + "@description": {}, + "destroyed": "破壊", + "@destroyed": {}, + "details": "詳細", + "@details": { + "description": "details" + }, + "documentation": "ドキュメント", + "@documentation": {}, + "downloading": "ファイルをダウンロード中", + "@downloading": {}, + "downloadError": "ダウンロードエラー", + "@downloadError": {}, + "edit": "編集", + "@edit": { + "description": "edit" + }, + "editCategory": "カテゴリの編集", + "@editCategory": {}, + "editLocation": "在庫場所を編集", + "@editLocation": {}, + "editNotes": "メモを編集", + "@editNotes": {}, + "editPart": "パートの編集", + "@editPart": { + "description": "edit part" + }, + "editItem": "在庫商品を編集", + "@editItem": {}, + "enterPassword": "パスワードを入力してください", + "@enterPassword": {}, + "enterUsername": "ユーザー名を入力してください", + "@enterUsername": {}, + "error": "エラー", + "@error": { + "description": "Error" + }, + "errorCreate": "データベースの作成中にエラーが発生しました", + "@errorCreate": {}, + "errorDelete": "データベースの削除中にエラーが発生しました", + "@errorDelete": {}, + "errorDetails": "エラーの詳細", + "@errorDetails": {}, + "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", + "@errorFetch": {}, + "errorReporting": "エラー報告", + "@errorReporting": {}, + "errorReportUpload": "エラー報告をアップロード", + "@errorReportUpload": {}, + "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", + "@errorReportUploadDetails": {}, + "feedback": "フィードバック", + "@feedback": {}, + "feedbackError": "フィードバックの送信エラー", + "@feedbackError": {}, + "feedbackSuccess": "フィードバックが送信されました", + "@feedbackSuccess": {}, + "formatException": "フォーマットの例外エラー", + "@formatException": {}, + "formatExceptionJson": "JSONデータフォーマット例外エラー", + "@formatExceptionJson": {}, + "formError": "フォームエラー", + "@formError": {}, + "history": "履歴", + "@history": { + "description": "history" + }, + "homeScreen": "ホーム画面", + "@homeScreen": {}, + "homeScreenSettings": "ホーム画面の設定", + "@homeScreenSettings": {}, + "homeShowPo": "注文書を表示", + "@homeShowPo": {}, + "homeShowSubscribed": "購読済みのパーツ", + "@homeShowSubscribed": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowSuppliers": "仕入先を表示", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "メーカーを表示", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "顧客を表示", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "画像のアップロードに失敗しました", + "@imageUploadFailure": {}, + "imageUploadSuccess": "アップロードされた画像", + "@imageUploadSuccess": {}, + "inactive": "無効", + "@inactive": {}, + "inactiveDetail": "この部品は無効としてマークされています", + "@inactiveDetail": {}, + "includeSubcategories": "サブカテゴリを含む", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "サブカテゴリをリストビューに表示します", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "サブ在庫場所を含める", + "@includeSublocations": {}, + "includeSublocationsDetail": "サブ在庫場所を表示します", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完全なプロフィールの詳細", + "@incompleteDetails": {}, + "internalPartNumber": "内部パーツ番号", + "@internalPartNumber": {}, + "info": "情報", + "@info": {}, + "inProduction": "生産中", + "@inProduction": {}, + "inProductionDetail": "この在庫品は生産中です", + "@inProductionDetail": {}, + "invalidHost": "無効なホスト名", + "@invalidHost": {}, + "invalidHostDetails": "このホスト名は無効です。", + "@invalidHostDetails": {}, + "invalidPart": "無効なパーツ", + "@invalidPart": {}, + "invalidPartCategory": "無効なパーツカテゴリー", + "@invalidPartCategory": {}, + "invalidStockLocation": "無効な在庫場所", + "@invalidStockLocation": {}, + "invalidStockItem": "無効な在庫アイテム", + "@invalidStockItem": {}, + "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", + "@invalidUsernamePassword": {}, + "issueDate": "発行日", + "@issueDate": {}, + "itemInLocation": "アイテムは既に在庫場所にあります", + "@itemInLocation": {}, + "keywords": "キーワード", + "@keywords": {}, + "lastUpdated": "最終更新", + "@lastUpdated": {}, + "locationCreate": "新しい場所", + "@locationCreate": {}, + "locationCreateDetail": "新しい在庫場所を作成", + "@locationCreateDetail": {}, + "locationNotSet": "在庫場所が指定されていません", + "@locationNotSet": {}, + "locationUpdated": "在庫場所を更新しました", + "@locationUpdated": {}, + "link": "リンク", + "@link": {}, + "lost": "損失", + "@lost": {}, + "missingData": "データ消失", + "@missingData": {}, + "name": "名前", + "@name": {}, + "notConnected": "接続されていません", + "@notConnected": {}, + "notes": "メモ", + "@notes": { + "description": "Notes" + }, + "noResponse": "サーバーからの応答がありません", + "@noResponse": {}, + "noResults": "一致する結果なし", + "@noResults": {}, + "noSubcategories": "サブカテゴリはありません", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "無効な値", + "@numberInvalid": {}, + "onOrder": "注文中", + "@onOrder": {}, + "packaging": "梱包中", + "@packaging": {}, + "packageName": "パッケージ名", + "@packageName": {}, + "parent": "親", + "@parent": {}, + "parentCategory": "親カテゴリ", + "@parentCategory": {}, + "parentLocation": "上位の場所", + "@parentLocation": {}, + "part": "パーツ", + "@part": { + "description": "Part (single)" + }, + "parts": "パーツ", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "パーツがありません", + "@partsNone": {}, + "partsStarredNone": "お気に入りのパーツはありません", + "@partsStarredNone": {}, + "partCategory": "パーツカテゴリー", + "@partCategory": {}, + "partCategoryTopLevel": "トップレベルのパーツカテゴリ", + "@partCategoryTopLevel": {}, + "partCategories": "パーツカテゴリー", + "@partCategories": {}, + "partDetails": "パーツ詳細", + "@partDetails": {}, + "partNotes": "パーツメモ", + "@partNotes": {}, + "partStock": "パーツ在庫:", + "@partStock": { + "description": "part stock" + }, + "password": "パスワード", + "@password": {}, + "passwordEmpty": "パスワードは空欄にできません。", + "@passwordEmpty": {}, + "permissionAccountDenied": "操作を行う権限がありません", + "@permissionAccountDenied": {}, + "permissionRequired": "権限が必要です", + "@permissionRequired": {}, + "printLabel": "ラベルを印刷", + "@printLabel": {}, + "printLabelFailure": "ラベルの印刷に失敗しました", + "@printLabelFailure": {}, + "printLabelSuccess": "ラベルをプリンタに送信しました", + "@printLabelSuccess": {}, + "profile": "プロフィール", + "@profile": {}, + "profileAdd": "サーバープロファイルを追加", + "@profileAdd": {}, + "profileConnect": "サーバーに接続", + "@profileConnect": {}, + "profileEdit": "サーバープロファイルを編集", + "@profileEdit": {}, + "profileDelete": "サーバープロファイルの削除", + "@profileDelete": {}, + "profileName": "プロファイル名", + "@profileName": {}, + "profileNone": "利用可能なプロファイルがありません", + "@profileNone": {}, + "profileNotSelected": "プロフィールが選択されていません", + "@profileNotSelected": {}, + "profileSelect": "InvenTreeサーバーを選択", + "@profileSelect": {}, + "profileTapToCreate": "タップしてプロフィールを作成または選択します", + "@profileTapToCreate": {}, + "purchaseOrder": "発注書", + "@purchaseOrder": {}, + "purchaseOrderEdit": "発注書の更新", + "@purchaseOrderEdit": {}, + "purchaseOrders": "発注書", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "発注書が更新されました", + "@purchaseOrderUpdated": {}, + "purchasePrice": "購入金額", + "@purchasePrice": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "数量が空です", + "@quantityEmpty": {}, + "quantityInvalid": "数量が無効です", + "@quantityInvalid": {}, + "quantityPositive": "数量は1以上", + "@quantityPositive": {}, + "queryNoResults": "検索結果はありません", + "@queryNoResults": {}, + "refresh": "更新", + "@refresh": {}, + "refreshing": "更新中", + "@refreshing": {}, + "rejected": "却下済み", + "@rejected": {}, + "releaseNotes": "リリースノート", + "@releaseNotes": {}, + "remove": "削除", + "@remove": { + "description": "remove" + }, + "removeStock": "在庫を削除", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "不具合の報告", + "@reportBug": {}, + "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", + "@reportBugDescription": {}, + "results": "結果", + "@results": {}, + "request": "リクエスト", + "@request": {}, + "requestingData": "データをリクエスト中", + "@requestingData": {}, + "required": "必須", + "@required": { + "description": "This field is required" + }, + "response400": "不正なリクエスト", + "@response400": {}, + "response401": "認証されていません", + "@response401": {}, + "response403": "権限がありません", + "@response403": {}, + "response404": "リソースが見つかりません", + "@response404": {}, + "response405": "メソッドが許可されていません", + "@response405": {}, + "response429": "リクエストが多すぎます", + "@response429": {}, + "response501": "未実装", + "@response501": {}, + "response503": "サービスは利用できません", + "@response503": {}, + "response505": "このHTTP バージョンはサポートされていません", + "@response505": {}, + "responseData": "応答データ", + "@responseData": {}, + "responseInvalid": "無効な応答", + "@responseInvalid": {}, + "responseUnknown": "不明な応答コード", + "@responseUnknown": {}, + "result": "結果", + "@result": { + "description": "" + }, + "returned": "返品済", + "@returned": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "バーコードをスキャン", + "@scanBarcode": {}, + "scanIntoLocation": "スキャンされた在庫場所", + "@scanIntoLocation": {}, + "search": "検索", + "@search": { + "description": "search" + }, + "searchLocation": "在庫場所場所を検索", + "@searchLocation": {}, + "searchParts": "パーツの検索", + "@searchParts": {}, + "searchStock": "在庫を検索", + "@searchStock": {}, + "select": "選択", + "@select": {}, + "selectFile": "ファイルを選択", + "@selectFile": {}, + "selectImage": "画像を選択", + "@selectImage": {}, + "selectLocation": "在庫場所を選択", + "@selectLocation": {}, + "send": "送信", + "@send": {}, + "serialNumber": "シリアルナンバー", + "@serialNumber": {}, + "server": "サーバー", + "@server": {}, + "serverAddress": "サーバーアドレス:", + "@serverAddress": {}, + "serverApiRequired": "必要なAPIバージョン", + "@serverApiRequired": {}, + "serverApiVersion": "サーバー API バージョン", + "@serverApiVersion": {}, + "serverAuthenticationError": "認証エラー", + "@serverAuthenticationError": {}, + "serverCertificateError": "認証エラー", + "@serverCertificateError": {}, + "serverCertificateInvalid": "サーバー HTTPS 証明書が無効です", + "@serverCertificateInvalid": {}, + "serverConnected": "サーバへ接続しました\n", + "@serverConnected": {}, + "serverConnecting": "サーバに接続中", + "@serverConnecting": {}, + "serverCouldNotConnect": "サーバーに接続できませんでした", + "@serverCouldNotConnect": {}, + "serverError": "サーバーエラー", + "@serverError": {}, + "serverDetails": "サーバの詳細", + "@serverDetails": {}, + "serverOld": "旧サーバーのバージョン", + "@serverOld": {}, + "serverSettings": "サーバー設定:", + "@serverSettings": {}, + "serverStart": "サーバーは http[s] で開始する必要があります", + "@serverStart": {}, + "settings": "設定", + "@settings": {}, + "serverInstance": "サーバインスタンス", + "@serverInstance": {}, + "serverNotConnected": "サーバーに接続されていません", + "@serverNotConnected": {}, + "sounds": "サウンド", + "@sounds": {}, + "soundOnBarcodeAction": "バーコード動作で音を鳴らす", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "サーバーのエラー時に音を鳴らす", + "@soundOnServerError": {}, + "status": "ステータス", + "@status": {}, + "statusCode": "ステータスコード", + "@statusCode": {}, + "stock": "在庫", + "@stock": { + "description": "stock" + }, + "stockItem": "在庫アイテム", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "在庫アイテム", + "@stockItems": {}, + "stockItemCreate": "新しい在庫アイテム", + "@stockItemCreate": {}, + "stockItemCreateDetail": "この場所に新しい在庫アイテムを作成", + "@stockItemCreateDetail": {}, + "stockItemDelete": "在庫アイテムを削除", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "この在庫アイテムを削除しますか?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "在庫アイテムを削除できませんでした。", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "在庫アイテムを削除しました", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "在庫履歴", + "@stockItemHistory": {}, + "stockItemTransferred": "在庫アイテムが転送されました", + "@stockItemTransferred": {}, + "stockItemUpdated": "在庫アイテムが更新されました", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "在庫アイテムがありません", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "在庫アイテムメモ", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "在庫アイテムが更新されました", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", + "@stockItemUpdateFailure": {}, + "stockLocation": "在庫場所", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "在庫場所", + "@stockLocations": {}, + "stockTopLevel": "トップレベルの在庫場所", + "@stockTopLevel": {}, + "strictHttps": "厳格なHTTPSを使用", + "@strictHttps": {}, + "subcategory": "サブカテゴリー", + "@subcategory": {}, + "subcategories": "サブカテゴリー", + "@subcategories": {}, + "sublocation": "サブ在庫場所", + "@sublocation": {}, + "sublocations": "サブ在庫場所", + "@sublocations": {}, + "sublocationNone": "サブ在庫場所がありません", + "@sublocationNone": {}, + "sublocationNoneDetail": "利用可能なサブ在庫場所がありません", + "@sublocationNoneDetail": {}, + "submitFeedback": "フィードバックを送信", + "@submitFeedback": {}, + "supplier": "サプライヤー", + "@supplier": {}, + "suppliers": "サプライヤー", + "@suppliers": {}, + "takePicture": "画像を撮影", + "@takePicture": {}, + "templatePart": "上位テンプレートパーツ", + "@templatePart": {}, + "testName": "テスト名", + "@testName": {}, + "testPassedOrFailed": "テストの合格または失敗", + "@testPassedOrFailed": {}, + "testsRequired": "必須テスト", + "@testsRequired": {}, + "testResults": "テスト結果", + "@testResults": { + "description": "" + }, + "testResultAdd": "テスト結果を追加", + "@testResultAdd": {}, + "testResultNone": "テスト結果がありません", + "@testResultNone": {}, + "testResultNoneDetail": "利用可能なテスト結果がありません", + "@testResultNoneDetail": {}, + "testResultUploadFail": "テスト結果のアップロードエラー", + "@testResultUploadFail": {}, + "testResultUploadPass": "テスト結果がアップロードされました", + "@testResultUploadPass": {}, + "timeout": "タイムアウト", + "@timeout": { + "description": "" + }, + "tokenError": "トークンエラー", + "@tokenError": {}, + "tokenMissing": "トークンがありません", + "@tokenMissing": {}, + "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", + "@tokenMissingFromResponse": {}, + "transfer": "転送", + "@transfer": { + "description": "transfer" + }, + "transferStock": "在庫の転送", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "翻訳", + "@translate": {}, + "translateHelp": "InvenTree アプリの翻訳に協力する", + "@translateHelp": {}, + "units": "単位", + "@units": {}, + "unknownResponse": "不明な応答", + "@unknownResponse": {}, + "upload": "アップロード", + "@upload": {}, + "uploadFailed": "ファイルのアップロードに失敗しました。", + "@uploadFailed": {}, + "uploadSuccess": "アップロードされたファイル", + "@uploadSuccess": {}, + "username": "ユーザー名", + "@username": {}, + "usernameEmpty": "ユーザー名は空にできません。", + "@usernameEmpty": {}, + "value": "設定値", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "値を空にすることはできません。", + "@valueCannotBeEmpty": {}, + "valueRequired": "値が必要です", + "@valueRequired": {}, + "version": "バージョン", + "@version": {}, + "website": "Webサイト", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 36d80aa..0bc359b 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -1,5 +1,105 @@ { - "@@locale": "en", + "@@locale": "ko", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "add": "추가", + "@add": { + "description": "add" + }, + "address": "주소", + "@address": {}, + "appAbout": "InvenTree 소개", + "@appAbout": {}, + "appReleaseNotes": "앱 릴리즈 노트 표시", + "@appReleaseNotes": {}, + "appSettings": "앱 설정", + "@appSettings": {}, + "billOfMaterials": "부품 명세서", + "@billOfMaterials": {}, + "cancel": "취소", + "@cancel": { + "description": "Cancel" + }, + "company": "회사", + "@company": {}, + "companyEdit": "회사 수정", + "@companyEdit": {}, + "error": "오류", + "@error": { + "description": "Error" + }, + "errorDetails": "오류 세부 정보", + "@errorDetails": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "keywords": "키워드", + "@keywords": {}, + "noResults": "결과 없음", + "@noResults": {}, + "password": "비밀번호", + "@password": {}, + "passwordEmpty": "비밀번호는 비워둘 수 없습니다", + "@passwordEmpty": {}, + "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", + "@permissionAccountDenied": {}, + "profileConnect": "서버에 연결", + "@profileConnect": {}, + "quantity": "수량", + "@quantity": { + "description": "Quantity" + }, + "reportBug": "버그 신고", + "@reportBug": {}, + "response505": "지원되지 않는 HTTP 버전", + "@response505": {}, + "save": "저장", + "@save": { + "description": "Save" + }, + "select": "선택", + "@select": {}, + "selectFile": "파일 선택", + "@selectFile": {}, + "server": "서버", + "@server": {}, + "serverAddress": "서버 주소", + "@serverAddress": {}, + "serverApiRequired": "필요한 API 버전", + "@serverApiRequired": {}, + "serverApiVersion": "서버 API 버전", + "@serverApiVersion": {}, + "serverAuthenticationError": "인증 오류", + "@serverAuthenticationError": {}, + "serverConnecting": "서버에 연결하는 중", + "@serverConnecting": {}, + "serverError": "서버 오류", + "@serverError": {}, + "serverOld": "오래된 서버 버전", + "@serverOld": {}, + "serverSettings": "서버 설정", + "@serverSettings": {}, + "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", + "@serverStart": {}, + "status": "상태", + "@status": {}, + "statusCode": "상태 코드", + "@statusCode": {}, + "targetDate": "목표 날짜", + "@targetDate": {}, + "timeout": "시간 초과", + "@timeout": { + "description": "" + }, + "tokenError": "토큰 오류", + "@tokenError": {}, + "translate": "번역", + "@translate": {}, + "translateHelp": "InvenTree 앱의 번역을 도와주세요", + "@translateHelp": {}, + "version": "버전", + "@version": {}, + "website": "웹사이트", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 36d80aa..40c32de 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "nl", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 36d80aa..34df543 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "no", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 36d80aa..4274486 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1,5 +1,739 @@ { - "@@locale": "en", + "@@locale": "pl", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "O nas", + "@about": {}, + "accountDetails": "Szczegóły konta", + "@accountDetails": {}, + "actions": "Działania", + "@actions": { + "description": "" + }, + "actionsNone": "Brak dostępnych działań", + "@actionsNone": {}, + "add": "Dodaj", + "@add": { + "description": "add" + }, + "addStock": "Dodaj stan", + "@addStock": { + "description": "add stock" + }, + "address": "Adresy", + "@address": {}, + "appAbout": "O InvenTree", + "@appAbout": {}, + "appCredits": "Dodatkowe podziękowania autorskie", + "@appCredits": {}, + "appDetails": "Szczegóły aplikacji", + "@appDetails": {}, + "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", + "@appReleaseNotes": {}, + "appSettings": "Ustawienia aplikacji", + "@appSettings": {}, + "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", + "@appSettingsDetails": {}, + "attachments": "Załączniki", + "@attachments": {}, + "attachImage": "Dodaj zdjęcie", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nie znaleziono załączników", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Brak załączników dla tego komponentu", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Wybierz załącznik", + "@attachmentSelect": {}, + "attention": "Uwaga", + "@attention": {}, + "barcodeAssign": "Przypisz kod kreskowy", + "@barcodeAssign": {}, + "barcodeAssigned": "Kod kreskowy przypisany", + "@barcodeAssigned": {}, + "barcodeError": "Błąd czytnika kodów kreskowych", + "@barcodeError": {}, + "barcodeInUse": "Kod kreskowy jest już przypisany", + "@barcodeInUse": {}, + "barcodeMissingHash": "Brak danych haszujących w odpowiedzi kodu kreskowego", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Brak dopasowania dla kodu kreskowego", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Kod kreskowy nieprzypisany", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Zeskanuj przedmioty do lokalizacji", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skanuj lokalizację zapasów", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skanuj element magazynowy", + "@barcodeScanItem": {}, + "barcodeTones": "Dźwięki kodów kreskowych", + "@barcodeTones": {}, + "barcodeUnassign": "Nieprzydzielony kod kreskowy", + "@barcodeUnassign": {}, + "barcodeUnknown": "Nie rozpoznano kodu kreskowego", + "@barcodeUnknown": {}, + "batchCode": "Kod partii", + "@batchCode": {}, + "billOfMaterials": "Zestawienie materiałów", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Budowa", + "@build": {}, + "building": "Budowanie", + "@building": {}, + "cancel": "Anuluj", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategoria", + "@category": {}, + "categoryCreate": "Nowa Kategoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Utwórz nową kategorię komponentu", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategoria części została zmieniona", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyEdit": "Edytuj Firmę", + "@companyEdit": {}, + "companyNoResults": "Brak firm pasujących do zapytania", + "@companyNoResults": {}, + "companyUpdated": "Szczegóły firmy zostały zaktualizowane", + "@companyUpdated": {}, + "companies": "Firmy", + "@companies": {}, + "configureServer": "Konfiguruj ustawienia serwera", + "@configureServer": {}, + "connectionRefused": "Połączenie odrzucone", + "@connectionRefused": {}, + "count": "Ilość", + "@count": { + "description": "Count" + }, + "countStock": "Przelicz stan", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Podziękowania", + "@credits": {}, + "customers": "Klienci", + "@customers": {}, + "damaged": "Uszkodzone", + "@damaged": {}, + "delete": "Usuń", + "@delete": {}, + "deletePart": "Usuń Komponent", + "@deletePart": {}, + "deletePartDetail": "Usuń ten komponent z bazy danych", + "@deletePartDetail": {}, + "description": "Opis", + "@description": {}, + "destroyed": "Zniszczony", + "@destroyed": {}, + "details": "Szczegóły", + "@details": { + "description": "details" + }, + "documentation": "Dokumentacja", + "@documentation": {}, + "downloading": "Pobieranie Pliku", + "@downloading": {}, + "downloadError": "Błąd Pobierania", + "@downloadError": {}, + "edit": "Edytuj", + "@edit": { + "description": "edit" + }, + "editCategory": "Edytuj kategorię", + "@editCategory": {}, + "editLocation": "Edytuj lokację", + "@editLocation": {}, + "editNotes": "Edytuj Notatki", + "@editNotes": {}, + "editPart": "Edytuj część", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edytuj Pozycję Magazynową", + "@editItem": {}, + "enterPassword": "Wprowadź hasło", + "@enterPassword": {}, + "enterUsername": "Wprowadź nazwę użytkownika", + "@enterUsername": {}, + "error": "Błąd", + "@error": { + "description": "Error" + }, + "errorCreate": "Błąd tworzenia wpisu w bazie danych", + "@errorCreate": {}, + "errorDelete": "Błąd podczas usuwania wpisu bazy danych", + "@errorDelete": {}, + "errorDetails": "Szczegóły błędu", + "@errorDetails": {}, + "errorFetch": "Błąd pobierania danych z serwea", + "@errorFetch": {}, + "errorReporting": "Raportowanie błędów", + "@errorReporting": {}, + "errorReportUpload": "Prześlij raport o błędach", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", + "@errorReportUploadDetails": {}, + "feedback": "Opinie", + "@feedback": {}, + "feedbackError": "Błąd dodawania opinii", + "@feedbackError": {}, + "feedbackSuccess": "Opinia przesłana", + "@feedbackSuccess": {}, + "formatException": "Wyjątek formatowania", + "@formatException": {}, + "formatExceptionJson": "Wyjątek formatu danych JSON", + "@formatExceptionJson": {}, + "formError": "Błąd Formularza", + "@formError": {}, + "history": "Historia", + "@history": { + "description": "history" + }, + "homeScreen": "Ekran główny", + "@homeScreen": {}, + "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", + "@homeScreenSettings": {}, + "homeShowPo": "Pokaż zamówienia zakupu", + "@homeShowPo": {}, + "homeShowSubscribed": "Obserwowane części", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Pokaż dostawców", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Pokaż producentów", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Pokaż przycisk producentów na ekranie głównym", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Pokaż klientów", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Pokaż przycisk klientów na ekranie głównym", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Przesyłanie zdjęcia nie powiodło się", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Obraz przesłany", + "@imageUploadSuccess": {}, + "inactive": "Nieaktywny", + "@inactive": {}, + "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", + "@inactiveDetail": {}, + "includeSubcategories": "Zawieraj podkategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Wyświetl części z podkategorii w widoku listy", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Zawieraj sublokacje", + "@includeSublocations": {}, + "includeSublocationsDetail": "Wyświetl części z sublokacji w widoku listy", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Niekompletne szczegóły profilu", + "@incompleteDetails": {}, + "internalPartNumber": "Wewnętrzny numer części", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "W produkcji", + "@inProduction": {}, + "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", + "@inProductionDetail": {}, + "invalidHost": "Nieprawidłowa nazwa hosta", + "@invalidHost": {}, + "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", + "@invalidHostDetails": {}, + "invalidPart": "Nieprawidłowa część", + "@invalidPart": {}, + "invalidPartCategory": "Nieprawidłowa kategoria części", + "@invalidPartCategory": {}, + "invalidStockLocation": "Nieprawidłowa lokacja magazynowa", + "@invalidStockLocation": {}, + "invalidStockItem": "Nieprawidłowa część magazynowa", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Nieprawidłowy login lub hasło", + "@invalidUsernamePassword": {}, + "issueDate": "Data Wystawienia", + "@issueDate": {}, + "itemInLocation": "Część jest już w lokacji", + "@itemInLocation": {}, + "keywords": "Słowa kluczowe", + "@keywords": {}, + "lastStocktake": "Ostatnia inwentaryzacja", + "@lastStocktake": {}, + "lastUpdated": "Ostatnia aktualizacja", + "@lastUpdated": {}, + "lineItem": "Pozycja", + "@lineItem": {}, + "lineItems": "Pozycje", + "@lineItems": {}, + "locationCreate": "Nowa Lokalizacja", + "@locationCreate": {}, + "locationCreateDetail": "Utwórz nową pozycję magazynową", + "@locationCreateDetail": {}, + "locationNotSet": "Nie określono lokacji", + "@locationNotSet": {}, + "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Zagubiono", + "@lost": {}, + "manufacturers": "Producenci", + "@manufacturers": {}, + "missingData": "Brakujące dane", + "@missingData": {}, + "name": "Nazwa", + "@name": {}, + "notConnected": "Nie połączony", + "@notConnected": {}, + "notes": "Notatki", + "@notes": { + "description": "Notes" + }, + "noResponse": "Brak odpowiedzi od serwera", + "@noResponse": {}, + "noResults": "Brak wyników", + "@noResults": {}, + "noSubcategories": "Brak podkategorii", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Brak dostępnych podkategorii", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Błędny numer", + "@numberInvalid": {}, + "onOrder": "W Zamówieniu", + "@onOrder": {}, + "onOrderDetails": "Pozycje obecnie w zamówieniu", + "@onOrderDetails": {}, + "packaging": "Opakowanie", + "@packaging": {}, + "packageName": "Nazwa pakietu", + "@packageName": {}, + "parent": "Nadrzędny", + "@parent": {}, + "parentCategory": "Kategoria nadrzędna", + "@parentCategory": {}, + "parentLocation": "Lokalizacja Nadrzędna", + "@parentLocation": {}, + "part": "Część", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nowy Komponent", + "@partCreate": {}, + "partCreateDetail": "Utwórz nowy komponent w tej kategorii", + "@partCreateDetail": {}, + "partEdited": "Część zaktualizowana", + "@partEdited": {}, + "parts": "Części", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Brak części", + "@partsNone": {}, + "partNoResults": "Brak komponentów pasujących do zapytania", + "@partNoResults": {}, + "partsStarred": "Obserwowane części", + "@partsStarred": {}, + "partsStarredNone": "Brak części oznaczonych gwiazdką", + "@partsStarredNone": {}, + "partSuppliers": "Dostawcy Części", + "@partSuppliers": {}, + "partCategory": "Kategoria części", + "@partCategory": {}, + "partCategoryTopLevel": "Kategoria części najwyższego poziomu", + "@partCategoryTopLevel": {}, + "partCategories": "Kategorie części", + "@partCategories": {}, + "partDetails": "Szczegóły części", + "@partDetails": {}, + "partNotes": "Notatki do części", + "@partNotes": {}, + "partStock": "Zapasy cześci", + "@partStock": { + "description": "part stock" + }, + "password": "Hasło", + "@password": {}, + "passwordEmpty": "Hasło nie może być puste", + "@passwordEmpty": {}, + "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", + "@permissionAccountDenied": {}, + "permissionRequired": "Wymagane uprawnienia", + "@permissionRequired": {}, + "printLabel": "Drukuj etykietę", + "@printLabel": {}, + "printLabelFailure": "Drukowanie etykiet nie powiodło się", + "@printLabelFailure": {}, + "printLabelSuccess": "Etykieta wysłana do drukarki", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Dodaj profil serwera", + "@profileAdd": {}, + "profileConnect": "Połącz się z serwerem", + "@profileConnect": {}, + "profileEdit": "Edytuj profil serwera", + "@profileEdit": {}, + "profileDelete": "Usuń profil serwera", + "@profileDelete": {}, + "profileName": "Nazwa Profilu", + "@profileName": {}, + "profileNone": "Brak dostępnych profili", + "@profileNone": {}, + "profileNotSelected": "Nie wybrano profilu", + "@profileNotSelected": {}, + "profileSelect": "Wybierz serwer InvenTree", + "@profileSelect": {}, + "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Zlecenie Zakupu", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Zlecenia zakupu", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Cena Zakupu", + "@purchasePrice": {}, + "quantity": "Ilość", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Ilość jest pusta", + "@quantityEmpty": {}, + "quantityInvalid": "Ilość jest nieprawidłowa", + "@quantityInvalid": {}, + "quantityPositive": "Ilość musi być dodatnia", + "@quantityPositive": {}, + "queryNoResults": "Nie znaleziono wyników dla zapytania", + "@queryNoResults": {}, + "received": "Odebrane", + "@received": {}, + "receiveItem": "Przyjmij artykuły", + "@receiveItem": {}, + "receivedItem": "Przyjęta Pozycja Magazynowa", + "@receivedItem": {}, + "refresh": "Odśwież", + "@refresh": {}, + "refreshing": "Odświeżanie", + "@refreshing": {}, + "rejected": "Odrzucono", + "@rejected": {}, + "releaseNotes": "Lista zmian", + "@releaseNotes": {}, + "remove": "Usuń", + "@remove": { + "description": "remove" + }, + "removeStock": "Usuń stan", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Zgłoś błąd", + "@reportBug": {}, + "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", + "@reportBugDescription": {}, + "results": "Wyniki", + "@results": {}, + "request": "Żądanie", + "@request": {}, + "requestingData": "Żądanie danych", + "@requestingData": {}, + "required": "Wymagane", + "@required": { + "description": "This field is required" + }, + "response400": "Błędne żądanie", + "@response400": {}, + "response401": "Nieautoryzowany", + "@response401": {}, + "response403": "Odmowa dostępu", + "@response403": {}, + "response404": "Nie znaleziono", + "@response404": {}, + "response405": "Metoda niedozwolona", + "@response405": {}, + "response429": "Zbyt wiele żądań", + "@response429": {}, + "response500": "Wewnętrzny błąd serwera", + "@response500": {}, + "response501": "Nie zaimplementowano", + "@response501": {}, + "response502": "Zła brama", + "@response502": {}, + "response503": "Usługa niedostępna", + "@response503": {}, + "response504": "Przekroczono limit czasu", + "@response504": {}, + "response505": "Wersja HTTP nie obsługiwana", + "@response505": {}, + "responseData": "Dane odpowiedzi", + "@responseData": {}, + "responseInvalid": "Nieprawidłowy kod odpowiedzi", + "@responseInvalid": {}, + "responseUnknown": "Nieznana odpowiedź", + "@responseUnknown": {}, + "result": "Wynik", + "@result": { + "description": "" + }, + "returned": "Zwrócono", + "@returned": {}, + "salesOrders": "Zlecenia Sprzedaży", + "@salesOrders": {}, + "save": "Zapisz", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skanuj kod kreskowy", + "@scanBarcode": {}, + "scanIntoLocation": "Skanuj do lokacji", + "@scanIntoLocation": {}, + "search": "Szukaj", + "@search": { + "description": "search" + }, + "searchLocation": "Wyszukaj lokalizację", + "@searchLocation": {}, + "searchParts": "Szukaj części", + "@searchParts": {}, + "searchStock": "Szukaj zapasów", + "@searchStock": {}, + "select": "Wybierz", + "@select": {}, + "selectFile": "Wybierz Plik", + "@selectFile": {}, + "selectImage": "Wybierz obraz", + "@selectImage": {}, + "selectLocation": "Wybierz lokację", + "@selectLocation": {}, + "send": "Wyślij", + "@send": {}, + "serialNumber": "Numer seryjny", + "@serialNumber": {}, + "server": "Serwer", + "@server": {}, + "serverAddress": "Adres serwera", + "@serverAddress": {}, + "serverApiRequired": "Wymagana wersja API", + "@serverApiRequired": {}, + "serverApiVersion": "Wersja API serwera", + "@serverApiVersion": {}, + "serverAuthenticationError": "Błąd uwierzytelniania", + "@serverAuthenticationError": {}, + "serverCertificateError": "Błąd certyfikatu", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Certyfikat serwera HTTPS jest nieprawidłowy", + "@serverCertificateInvalid": {}, + "serverConnected": "Połączony z serwerem", + "@serverConnected": {}, + "serverConnecting": "Łączenie z serwerem", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nie można połączyć się z serwerem", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serwer nie może być pusty", + "@serverEmpty": {}, + "serverError": "Błąd serwera", + "@serverError": {}, + "serverDetails": "Szczegóły serwera", + "@serverDetails": {}, + "serverMissingData": "Odpowiedź serwera nie ma wymaganych pól", + "@serverMissingData": {}, + "serverOld": "Stara wersja serwera", + "@serverOld": {}, + "serverSettings": "Ustawienia Serwera", + "@serverSettings": {}, + "serverStart": "Serwer musi zaczynać się od http[s]", + "@serverStart": {}, + "settings": "Ustawienia", + "@settings": {}, + "serverInstance": "Instancja serwera", + "@serverInstance": {}, + "serverNotConnected": "Serwer nie podłączony", + "@serverNotConnected": {}, + "sounds": "Dźwięki", + "@sounds": {}, + "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Kod statusu", + "@statusCode": {}, + "stock": "Stan", + "@stock": { + "description": "stock" + }, + "stockItem": "Element magazynowy", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Elementy magazynowe", + "@stockItems": {}, + "stockItemCreate": "Nowa Pozycja Magazynowa", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Utwórz nową pozycję magazynową w tej lokalizacji", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Usuń przedmiot magazynowy", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Czy jesteś pewien, że chcesz usunąć ten przedmiot magazynowy?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Nie można usunąć przedmiotu magazynowego", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Przedmiot magazynowy usunięty", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historia zapasów", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Wyświetl historyczne informacje o śledzeniu stanów magazynowych", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Element magazynowy przeniesiony", + "@stockItemTransferred": {}, + "stockItemUpdated": "Zaktualizowano element magazynowy", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Brak dostępnych elementów", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notatki przedmiotu magazynowego", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Zaktualizowano element magazynowy", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Nie zaktualizowano elementu magazynowego", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lokacja stanu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lokacje stanów", + "@stockLocations": {}, + "stockTopLevel": "Najwyższy poziom lokalizacji magazynu", + "@stockTopLevel": {}, + "strictHttps": "Ścisły HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Wymuś ścisłe sprawdzanie certyfikatów HTTPS", + "@strictHttpsDetails": {}, + "subcategory": "Podkategoria", + "@subcategory": {}, + "subcategories": "Podkategorie", + "@subcategories": {}, + "sublocation": "Sublokacja", + "@sublocation": {}, + "sublocations": "Subblokacje", + "@sublocations": {}, + "sublocationNone": "Brak subblokacji", + "@sublocationNone": {}, + "sublocationNoneDetail": "Brak dostępnych podlokalizacji", + "@sublocationNoneDetail": {}, + "submitFeedback": "Prześlij opinię", + "@submitFeedback": {}, + "suppliedParts": "Dostarczone Części", + "@suppliedParts": {}, + "supplier": "Dostawca", + "@supplier": {}, + "suppliers": "Dostawcy", + "@suppliers": {}, + "supplierReference": "Identyfikator Dostawcy", + "@supplierReference": {}, + "takePicture": "Zrób zdjęcie", + "@takePicture": {}, + "targetDate": "Data Docelowa", + "@targetDate": {}, + "testName": "Nazwa testu", + "@testName": {}, + "testPassedOrFailed": "Test zaliczony lub nieudany", + "@testPassedOrFailed": {}, + "testsRequired": "Wymagane testy", + "@testsRequired": {}, + "testResults": "Wyniki testu", + "@testResults": { + "description": "" + }, + "testResultAdd": "Dodaj wynik testu", + "@testResultAdd": {}, + "testResultNone": "Brak wyników testu", + "@testResultNone": {}, + "testResultNoneDetail": "Brak dostępnych wyników testu", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Błąd przesyłania wyniku testu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Wynik testu przesłany", + "@testResultUploadPass": {}, + "timeout": "Upłynął limit czasu", + "@timeout": { + "description": "" + }, + "tokenError": "Błąd tokenu", + "@tokenError": {}, + "tokenMissing": "Brakujący token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", + "@tokenMissingFromResponse": {}, + "transfer": "Przenieś", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Przenieś stan", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Przetłumacz", + "@translate": {}, + "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", + "@translateHelp": {}, + "units": "Jednostki", + "@units": {}, + "unknownResponse": "Nieznana odpowiedź", + "@unknownResponse": {}, + "upload": "Wyślij", + "@upload": {}, + "uploadFailed": "Błąd wysyłania pliku", + "@uploadFailed": {}, + "uploadSuccess": "Plik przesłany", + "@uploadSuccess": {}, + "usedIn": "Użyte w", + "@usedIn": {}, + "usedInDetails": "Złożenie, które wymagają tego komponentu", + "@usedInDetails": {}, + "username": "Nazwa użytkownika", + "@username": {}, + "usernameEmpty": "Nazwa użytkownika nie może być pusta", + "@usernameEmpty": {}, + "value": "Wartość", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Wartość nie może być pusta", + "@valueCannotBeEmpty": {}, + "valueRequired": "Wartość jest wymagana", + "@valueRequired": {}, + "version": "Wersja", + "@version": {}, + "viewSupplierPart": "Zobacz Dostawcę Części", + "@viewSupplierPart": {}, + "website": "Strona WWW", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 36d80aa..65bbe17 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -1,5 +1,193 @@ { - "@@locale": "en", + "@@locale": "pt", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Sobre", + "@about": {}, + "accountDetails": "Detalhes da Conta", + "@accountDetails": {}, + "actions": "Ações", + "@actions": { + "description": "" + }, + "actionsNone": "Nenhuma ação disponível", + "@actionsNone": {}, + "add": "Adicionar", + "@add": { + "description": "add" + }, + "addStock": "Adicionar ao estoque", + "@addStock": { + "description": "add stock" + }, + "address": "Endereço", + "@address": {}, + "appAbout": "Sobre o InvenTree", + "@appAbout": {}, + "appCredits": "Créditos adicionais do aplicativo", + "@appCredits": {}, + "appDetails": "Detalhes do App", + "@appDetails": {}, + "appReleaseNotes": "Exibir notas de versão do aplicativo", + "@appReleaseNotes": {}, + "appSettings": "Configurações do App", + "@appSettings": {}, + "appSettingsDetails": "Configurar os parâmetros do InvenTree", + "@appSettingsDetails": {}, + "attachments": "Anexos", + "@attachments": {}, + "attachImage": "Anexar Imagem", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Não foram encontrados quaisquer anexos", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Selecionar anexo", + "@attachmentSelect": {}, + "attention": "Aviso", + "@attention": {}, + "barcodeAssign": "Atribuir Código de Barras", + "@barcodeAssign": {}, + "barcodeAssigned": "Código de barras atribuído", + "@barcodeAssigned": {}, + "barcodeError": "Erro ao escanear código de barras", + "@barcodeError": {}, + "barcodeInUse": "Código de barras já atribuído", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Não corresponde a nenhum código de barras", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Código de barras não atribuído", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Escaneie para atribuir código de barras", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Escaneie itens de estoque no local", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear Localização", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Escaneado no local", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "Escanear ítem", + "@barcodeScanItem": {}, + "barcodeTones": "Tons do código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Remover código de barras pre-designado", + "@barcodeUnassign": {}, + "barcodeUnknown": "Código de barras não reconhecido", + "@barcodeUnknown": {}, + "batchCode": "Código de lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiais", + "@billOfMaterials": {}, + "bom": "Lista de Materiais", + "@bom": {}, + "build": "Compilar", + "@build": {}, + "building": "Compilando", + "@building": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nova Categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Criar nova categoria de peças", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria de peça atualizada", + "@categoryUpdated": {}, + "company": "Empresa", + "@company": {}, + "companyEdit": "Editar empresa", + "@companyEdit": {}, + "companyNoResults": "Nenhuma empresa corresponde a consulta", + "@companyNoResults": {}, + "companyUpdated": "Dados da empresa atualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "configureServer": "Configurar os parâmetros do servidor de email", + "@configureServer": {}, + "connectionRefused": "Conexão recusada", + "@connectionRefused": {}, + "count": "Contagem", + "@count": { + "description": "Count" + }, + "countStock": "Contagem de Estoque", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "customers": "Clientes", + "@customers": {}, + "damaged": "Danificado", + "@damaged": {}, + "delete": "Excluir", + "@delete": {}, + "deletePart": "Excluir esta parte", + "@deletePart": {}, + "deletePartDetail": "Remover esta peça da base de dados", + "@deletePartDetail": {}, + "description": "Descrição", + "@description": {}, + "destroyed": "Destruído", + "@destroyed": {}, + "details": "Detalhes", + "@details": { + "description": "details" + }, + "documentation": "Documentação", + "@documentation": {}, + "downloading": "Baixando arquivo", + "@downloading": {}, + "downloadError": "Erro de download", + "@downloadError": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editCategory": "Editar categoria", + "@editCategory": {}, + "editLocation": "Editar Localização", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editPart": "Editar a peça", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar Item do Estoque", + "@editItem": {}, + "enterPassword": "Digite a senha", + "@enterPassword": {}, + "enterUsername": "Inserir usuário", + "@enterUsername": {}, + "error": "Erro", + "@error": { + "description": "Error" + }, + "errorCreate": "Erro ao criar entrada de banco de dados", + "@errorCreate": {}, + "errorDelete": "Erro ao excluir entrada no banco de dados", + "@errorDelete": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "lastUpdated": "Ultima atualização", + "@lastUpdated": {}, + "lineItems": "Itens de linha", + "@lineItems": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 36d80aa..d89f472 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -1,5 +1,263 @@ { - "@@locale": "en", + "@@locale": "ru", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "ОК", + "@ok": { + "description": "OK" + }, + "about": "О проекте", + "@about": {}, + "accountDetails": "Данные аккаунта", + "@accountDetails": {}, + "actions": "Действия", + "@actions": { + "description": "" + }, + "actionsNone": "Действия недоступны", + "@actionsNone": {}, + "add": "Добавить", + "@add": { + "description": "add" + }, + "addStock": "Добавить запасы", + "@addStock": { + "description": "add stock" + }, + "address": "Адрес", + "@address": {}, + "appAbout": "О InvenTree", + "@appAbout": {}, + "appCredits": "Благодарности за помощь и поддержку", + "@appCredits": {}, + "appDetails": "Информация о приложении", + "@appDetails": {}, + "appReleaseNotes": "Показать заметки о выпуске приложения", + "@appReleaseNotes": {}, + "appSettings": "Настройки приложения", + "@appSettings": {}, + "companyNoResults": "Нет организаций, соответствующих запросу", + "@companyNoResults": {}, + "downloading": "Загрузка файла", + "@downloading": {}, + "downloadError": "Ошибка загрузки", + "@downloadError": {}, + "edit": "Изменить", + "@edit": { + "description": "edit" + }, + "editCategory": "Редактировать категорию", + "@editCategory": {}, + "editLocation": "Редактировать местонахождение", + "@editLocation": {}, + "editNotes": "Редактировать примечания", + "@editNotes": {}, + "editPart": "Ред. эту часть", + "@editPart": { + "description": "edit part" + }, + "editItem": "Отредактированный товар", + "@editItem": {}, + "enterPassword": "Введите пароль", + "@enterPassword": {}, + "enterUsername": "Введите имя пользователя", + "@enterUsername": {}, + "error": "Ошибка", + "@error": { + "description": "Error" + }, + "errorCreate": "Ошибка создания записи базы данных", + "@errorCreate": {}, + "errorDetails": "Подробнее об ошибке", + "@errorDetails": {}, + "errorFetch": "Ошибка при получении данных с сервера", + "@errorFetch": {}, + "feedback": "Обратная Связь", + "@feedback": {}, + "feedbackError": "Ошибка отправки отзыва", + "@feedbackError": {}, + "feedbackSuccess": "Отзыв отправлен", + "@feedbackSuccess": {}, + "formatException": "Формат исключения", + "@formatException": {}, + "formatExceptionJson": "Ошибка формата JSON", + "@formatExceptionJson": {}, + "formError": "Ошибка в форме", + "@formError": {}, + "history": "История", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "imageUploadFailure": "Не удалось загрузить изображение", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Изображение загружено", + "@imageUploadSuccess": {}, + "inactive": "Неактивный", + "@inactive": {}, + "inactiveDetail": "Эта часть помечена как неактивная", + "@inactiveDetail": {}, + "includeSubcategories": "Включить подкатегории", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Отображать подкатегории в виде списка", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Добавить доп. местоположения", + "@includeSublocations": {}, + "includeSublocationsDetail": "Отображать доп. местоположения в виде списка", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Неполные данные профиля", + "@incompleteDetails": {}, + "internalPartNumber": "Внутренний номер", + "@internalPartNumber": {}, + "info": "Информация", + "@info": {}, + "invalidHost": "Неверное имя хоста", + "@invalidHost": {}, + "invalidHostDetails": "Недопустимый пароль", + "@invalidHostDetails": {}, + "invalidPart": "Недопустимый элемент", + "@invalidPart": {}, + "invalidPartCategory": "Неверная категория элемента", + "@invalidPartCategory": {}, + "invalidStockLocation": "Неверное расположение склада", + "@invalidStockLocation": {}, + "invalidStockItem": "Недопустимый товарный пункт", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", + "@invalidUsernamePassword": {}, + "issueDate": "Дата проблемы", + "@issueDate": {}, + "itemInLocation": "Элемент уже находится на месте", + "@itemInLocation": {}, + "keywords": "Ключевые слова", + "@keywords": {}, + "lastStocktake": "Последняя инвентаризация", + "@lastStocktake": {}, + "lastUpdated": "Последние обновлённые", + "@lastUpdated": {}, + "lineItem": "Элемент строки", + "@lineItem": {}, + "lineItems": "Элементы строки", + "@lineItems": {}, + "locationCreate": "Новое местоположение", + "@locationCreate": {}, + "locationCreateDetail": "Создать новое расположение склада", + "@locationCreateDetail": {}, + "locationNotSet": "Не указано месторасположение", + "@locationNotSet": {}, + "link": "Ссылка", + "@link": {}, + "lost": "Потерян", + "@lost": {}, + "manufacturers": "Производители", + "@manufacturers": {}, + "missingData": "Отсутствующие данные", + "@missingData": {}, + "name": "Название", + "@name": {}, + "notConnected": "Соединение не установлено", + "@notConnected": {}, + "notes": "Заметки", + "@notes": { + "description": "Notes" + }, + "noResponse": "Нет ответа от сервера", + "@noResponse": {}, + "noResults": "Нет результатов", + "@noResults": {}, + "noSubcategories": "Нет подкатегории", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Нет доступных подкатегорий", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Неправильный номер", + "@numberInvalid": {}, + "onOrder": "Под заказ", + "@onOrder": {}, + "onOrderDetails": "Заказаные элементы", + "@onOrderDetails": {}, + "packaging": "Упаковка", + "@packaging": {}, + "packageName": "Название упаковки", + "@packageName": {}, + "parent": "Родитель", + "@parent": {}, + "parentCategory": "Родительская категория", + "@parentCategory": {}, + "parentLocation": "Родительское местоположение", + "@parentLocation": {}, + "part": "Компонент", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Новый компонент", + "@partCreate": {}, + "partCreateDetail": "Создать компонент в данной категории", + "@partCreateDetail": {}, + "parts": "Номенклатура", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Нет компонентов", + "@partsNone": {}, + "partNoResults": "Нет компонентов, соответствующих запросу", + "@partNoResults": {}, + "response405": "405 Метод не разрешен", + "@response405": {}, + "response429": "Слишком много запросов", + "@response429": {}, + "response500": "Внутренняя ошибка сервера", + "@response500": {}, + "response501": "Не реализовано", + "@response501": {}, + "response502": "Недопустимый шлюз", + "@response502": {}, + "response503": "Сервис недоступен", + "@response503": {}, + "response504": "504: тайм-аут шлюза", + "@response504": {}, + "response505": "505: версия не поддерживается", + "@response505": {}, + "responseData": "Информация об ответе", + "@responseData": {}, + "responseInvalid": "Неверный код ответа", + "@responseInvalid": {}, + "responseUnknown": "Неизвестный ответ", + "@responseUnknown": {}, + "result": "Результат", + "@result": { + "description": "" + }, + "returned": "Возвращено", + "@returned": {}, + "salesOrders": "Заказы на продажу", + "@salesOrders": {}, + "save": "Сохранить", + "@save": { + "description": "Save" + }, + "scanBarcode": "Сканировать штрихкод", + "@scanBarcode": {}, + "scanIntoLocation": "Сканировать в местоположение", + "@scanIntoLocation": {}, + "search": "Поиск", + "@search": { + "description": "search" + }, + "searchLocation": "Искать по месту", + "@searchLocation": {}, + "searchParts": "Найти номенклатуру", + "@searchParts": {}, + "searchStock": "Поиск в наличии", + "@searchStock": {}, + "select": "Выбрать", + "@select": {}, + "selectFile": "Выбрать файл", + "@selectFile": {}, + "selectImage": "Выбрать изображение", + "@selectImage": {}, + "website": "Сайт", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 36d80aa..e37c200 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "sv", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 36d80aa..5fdf211 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "th", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 36d80aa..447ecee 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -1,5 +1,735 @@ { - "@@locale": "en", + "@@locale": "tr", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "TAMAM", + "@ok": { + "description": "OK" + }, + "about": "Hakkında", + "@about": {}, + "accountDetails": "Hesap Detayları", + "@accountDetails": {}, + "actions": "Eylemler", + "@actions": { + "description": "" + }, + "actionsNone": "Kullanılabilir eylem yok", + "@actionsNone": {}, + "add": "Ekle", + "@add": { + "description": "add" + }, + "addStock": "Stok ekle", + "@addStock": { + "description": "add stock" + }, + "address": "Adres", + "@address": {}, + "appAbout": "InvenTree Hakkında", + "@appAbout": {}, + "appCredits": "Uygulama kredisi ekle", + "@appCredits": {}, + "appDetails": "Uygulama Detayları", + "@appDetails": {}, + "appReleaseNotes": "Uygulama yayınlama notları", + "@appReleaseNotes": {}, + "appSettings": "Uygulama Ayarları", + "@appSettings": {}, + "appSettingsDetails": "Uygulama ayarlarından yapılandır", + "@appSettingsDetails": {}, + "attachments": "Ekler", + "@attachments": {}, + "attachImage": "Resim ekle", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Hiçbir ek bulunamadı", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Ek seçin", + "@attachmentSelect": {}, + "attention": "Dikkat", + "@attention": {}, + "barcodeAssign": "Barkod Ata", + "@barcodeAssign": {}, + "barcodeAssigned": "Barkod atandı", + "@barcodeAssigned": {}, + "barcodeError": "Barkod tarama hatası", + "@barcodeError": {}, + "barcodeInUse": "Barkod zaten kullanımda", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash verisi alınamadı", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Barkod için eşleşme yok", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barkod atanmış değil", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Atanmış barkodu tara", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Bir Iventree barkodu tara", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Stok öğelerini konum içine tara", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Stok konumu tara", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Konuma tarandı", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Madde taranmış değil", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Stok öğesi tara", + "@barcodeScanItem": {}, + "barcodeTones": "Barkod Tonları", + "@barcodeTones": {}, + "barcodeUnassign": "Atanmamış barkod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barkod tanınmadı", + "@barcodeUnknown": {}, + "batchCode": "Grup kodu", + "@batchCode": {}, + "billOfMaterials": "Fatura materyalleri", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Oluştur", + "@build": {}, + "building": "Oluşturma", + "@building": {}, + "cancel": "İptal", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Yeni Kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Yeni parça kategorisi oluştur", + "@categoryCreateDetail": {}, + "categoryUpdated": "Parça Kategorisi güncellendi", + "@categoryUpdated": {}, + "company": "Şirket", + "@company": {}, + "companyEdit": "Şirketi Düzenle", + "@companyEdit": {}, + "companyNoResults": "Sorguyla eşleşen şirket yok", + "@companyNoResults": {}, + "companyUpdated": "Firma bilgileri güncellendi", + "@companyUpdated": {}, + "companies": "Şirketler", + "@companies": {}, + "configureServer": "Sunucu ayarlarınızı yapılandırın", + "@configureServer": {}, + "connectionRefused": "Bağlantı reddedildi", + "@connectionRefused": {}, + "count": "Sayım", + "@count": { + "description": "Count" + }, + "countStock": "Stok sayımı", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Katkıda Bulunanlar", + "@credits": {}, + "customers": "Müşteriler", + "@customers": {}, + "damaged": "Hasarlı", + "@damaged": {}, + "delete": "Sil", + "@delete": {}, + "deletePart": "Parça Sil", + "@deletePart": {}, + "deletePartDetail": "Bu parçayı veritabanından kaldır", + "@deletePartDetail": {}, + "description": "Açıklama", + "@description": {}, + "destroyed": "Yok edildi", + "@destroyed": {}, + "details": "Detaylar", + "@details": { + "description": "details" + }, + "documentation": "Dökümantasyon", + "@documentation": {}, + "downloading": "Dosya indiriliyor", + "@downloading": {}, + "downloadError": "İndirme Hatası", + "@downloadError": {}, + "edit": "Düzenle", + "@edit": { + "description": "edit" + }, + "editCategory": "Kategoriyi düzenle", + "@editCategory": {}, + "editLocation": "Konumu Düzenle", + "@editLocation": {}, + "editNotes": "Notları Düzenle", + "@editNotes": {}, + "editPart": "Parçayı Düzenle", + "@editPart": { + "description": "edit part" + }, + "editItem": "Parçayı Düzenle", + "@editItem": {}, + "enterPassword": "Şifrenizi girin", + "@enterPassword": {}, + "enterUsername": "Kullanıcı adını girin", + "@enterUsername": {}, + "error": "Hata", + "@error": { + "description": "Error" + }, + "errorCreate": "Veritabanı girdi oluşturma hatası", + "@errorCreate": {}, + "errorDelete": "Veritabanı girdisini silerken hata", + "@errorDelete": {}, + "errorDetails": "Hata Ayrıntıları", + "@errorDetails": {}, + "errorFetch": "Sunucudan veri alınırken hata oluştu", + "@errorFetch": {}, + "errorReporting": "Hata Raporlama", + "@errorReporting": {}, + "errorReportUpload": "Hata raporu yükle", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonim olarak hata ve log yükle", + "@errorReportUploadDetails": {}, + "feedback": "Geri Bildirim", + "@feedback": {}, + "feedbackError": "Geribildirim gönderme hatası", + "@feedbackError": {}, + "feedbackSuccess": "Geri bildirim gönderildi", + "@feedbackSuccess": {}, + "formatException": "Biçim İstisnası", + "@formatException": {}, + "formatExceptionJson": "JSON veri format istisnası", + "@formatExceptionJson": {}, + "formError": "Form hatası", + "@formError": {}, + "history": "Geçmiş", + "@history": { + "description": "history" + }, + "homeScreen": "Ana Ekran", + "@homeScreen": {}, + "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", + "@homeScreenSettings": {}, + "homeShowPo": "Satın Alma Siparişlerini Göster", + "@homeShowPo": {}, + "homeShowSubscribed": "Parça bildirimlerine abone ol", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Tedarikçileri Göster", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Üreticileri Göster", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Tedarikçi butonunu ana ekranda göster", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Müşterileri Göster", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Fotoğraf yükleme başarısız", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Resim yüklendi", + "@imageUploadSuccess": {}, + "inactive": "Pasif", + "@inactive": {}, + "inactiveDetail": "Bu parça pasif olarak işaretlendi", + "@inactiveDetail": {}, + "includeSubcategories": "Alt kategorileri dahil et", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Alt kategori parçalarını liste görünümünde göster", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alt konumları dahil et", + "@includeSublocations": {}, + "includeSublocationsDetail": "Alt konum parçalarını liste görünümünde göster", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Tamamlanmamış profil detayları", + "@incompleteDetails": {}, + "internalPartNumber": "İç Parça Numarası", + "@internalPartNumber": {}, + "info": "Bilgi", + "@info": {}, + "inProduction": "Yapım Aşamasında", + "@inProduction": {}, + "inProductionDetail": "Bu ürün üretim aşamasında", + "@inProductionDetail": {}, + "invalidHost": "Geçersiz alan adı", + "@invalidHost": {}, + "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", + "@invalidHostDetails": {}, + "invalidPart": "Geçersiz Parça", + "@invalidPart": {}, + "invalidPartCategory": "Geçersiz Parça Kategorisi", + "@invalidPartCategory": {}, + "invalidStockLocation": "Geçersiz Stok Konumu", + "@invalidStockLocation": {}, + "invalidStockItem": "Geçersiz Stok Parçası", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", + "@invalidUsernamePassword": {}, + "issueDate": "Sorun Tarihi", + "@issueDate": {}, + "itemInLocation": "Parça zaten konumda", + "@itemInLocation": {}, + "keywords": "Anahtar kelimeler", + "@keywords": {}, + "lastStocktake": "Son stok tutma", + "@lastStocktake": {}, + "lastUpdated": "Son güncelleme", + "@lastUpdated": {}, + "lineItem": "Parça Sırası", + "@lineItem": {}, + "lineItems": "Parçalar Sırası", + "@lineItems": {}, + "locationCreate": "Yeni Konum", + "@locationCreate": {}, + "locationCreateDetail": "Yeni stok konumu oluştur", + "@locationCreateDetail": {}, + "locationNotSet": "Belirtilmiş konum yok", + "@locationNotSet": {}, + "locationUpdated": "Stok lokasyonu güncellendi", + "@locationUpdated": {}, + "link": "Bağlantı", + "@link": {}, + "lost": "Kayıp", + "@lost": {}, + "manufacturers": "Üreticiler", + "@manufacturers": {}, + "missingData": "Eksik Veri", + "@missingData": {}, + "name": "Adı", + "@name": {}, + "notConnected": "Bağlı değil", + "@notConnected": {}, + "notes": "Notlar", + "@notes": { + "description": "Notes" + }, + "noResponse": "Sunucudan yanıt yok", + "@noResponse": {}, + "noResults": "Sonuç Yok", + "@noResults": {}, + "noSubcategories": "Alt kategori yok", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Uygun alt kategori yok", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Geçersiz numara", + "@numberInvalid": {}, + "onOrder": "Siparişte", + "@onOrder": {}, + "onOrderDetails": "Parça şuan siparişte", + "@onOrderDetails": {}, + "packaging": "Paketleme", + "@packaging": {}, + "packageName": "Paket İsmi", + "@packageName": {}, + "parent": "Üst", + "@parent": {}, + "parentCategory": "Üst Kategori", + "@parentCategory": {}, + "parentLocation": "Bağlı lokasyon", + "@parentLocation": {}, + "part": "Parça", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Yeni Parça", + "@partCreate": {}, + "partCreateDetail": "Yeni parça kategorisi oluştur", + "@partCreateDetail": {}, + "partEdited": "Parça Güncellendi", + "@partEdited": {}, + "parts": "Parçalar", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Parça Yok", + "@partsNone": {}, + "partNoResults": "Sorguyla eşleşen parça yok", + "@partNoResults": {}, + "partsStarred": "Sürekli Gelen parçalar", + "@partsStarred": {}, + "partsStarredNone": "Yıldızlı parça yok", + "@partsStarredNone": {}, + "partSuppliers": "Parça Tedarikçileri", + "@partSuppliers": {}, + "partCategory": "Parça Kategorileri", + "@partCategory": {}, + "partCategoryTopLevel": "Üst seviye parça kategorisi", + "@partCategoryTopLevel": {}, + "partCategories": "Parça Kategorileri", + "@partCategories": {}, + "partDetails": "Parça detayları", + "@partDetails": {}, + "partNotes": "Parça notları", + "@partNotes": {}, + "partStock": "Parça stok", + "@partStock": { + "description": "part stock" + }, + "password": "Parola", + "@password": {}, + "passwordEmpty": "Parola boş bırakılamaz", + "@passwordEmpty": {}, + "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", + "@permissionAccountDenied": {}, + "permissionRequired": "İzin Gerekli", + "@permissionRequired": {}, + "printLabel": "Etiket Yazdır", + "@printLabel": {}, + "printLabelFailure": "Etiket yazdırılamadı", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiket yazıcıya gönderildi", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Yeni Sunucu Profili Ekle", + "@profileAdd": {}, + "profileConnect": "Sunucuya bağlan", + "@profileConnect": {}, + "profileEdit": "Sunucu Profilini düzenle", + "@profileEdit": {}, + "profileDelete": "Sunucu profilini sil", + "@profileDelete": {}, + "profileName": "Profil Adı", + "@profileName": {}, + "profileNone": "Kullanılabiir profil yok", + "@profileNone": {}, + "profileNotSelected": "Profil seçilmedi", + "@profileNotSelected": {}, + "profileSelect": "InvenTree sunucusu seç", + "@profileSelect": {}, + "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", + "@profileTapToCreate": {}, + "purchaseOrder": "Satınalma Siparişi", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Satın Alma siparişini düzenle", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Satınalma Siparişleri", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Alış Fiyatı", + "@purchasePrice": {}, + "quantity": "Adet", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Adet boş", + "@quantityEmpty": {}, + "quantityInvalid": "Adet geçersiz", + "@quantityInvalid": {}, + "quantityPositive": "Adet pozitif bir sayı olmalı", + "@quantityPositive": {}, + "queryNoResults": "Sorgu için sonuç yok", + "@queryNoResults": {}, + "received": "Alınan", + "@received": {}, + "receiveItem": "Alınan Öğeler", + "@receiveItem": {}, + "receivedItem": "Alınan stok parçaları", + "@receivedItem": {}, + "refresh": "Yenile", + "@refresh": {}, + "refreshing": "Yenileniyor", + "@refreshing": {}, + "rejected": "Reddedildi", + "@rejected": {}, + "releaseNotes": "Sürüm notları", + "@releaseNotes": {}, + "remove": "Kaldır", + "@remove": { + "description": "remove" + }, + "removeStock": "Stok Kaldır", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Hata Bildir", + "@reportBug": {}, + "reportBugDescription": "Hata raporla ( github hesabı gerektirir)", + "@reportBugDescription": {}, + "results": "Sonuçlar", + "@results": {}, + "request": "Talep", + "@request": {}, + "requestingData": "Veri Talep Ediliyor", + "@requestingData": {}, + "required": "Gerekli", + "@required": { + "description": "This field is required" + }, + "response400": "Hatalı İstek", + "@response400": {}, + "response401": "Yetkisiz", + "@response401": {}, + "response403": "İzin Engellendi", + "@response403": {}, + "response404": "Kaynak bulunamadı", + "@response404": {}, + "response405": "İzin Verilmeyen Yöntem", + "@response405": {}, + "response429": "Çok Fazla İstek", + "@response429": {}, + "response500": "İç Sunucu Hatası", + "@response500": {}, + "response501": "Uygulanamadı", + "@response501": {}, + "response502": "Hatalı Ağ Geçidi", + "@response502": {}, + "response503": "Hizmet Kullanılamıyor", + "@response503": {}, + "response504": "Ağ Geçidi Zaman Aşımı", + "@response504": {}, + "response505": "HTTP Sürümü Desteklenmiyor", + "@response505": {}, + "responseData": "Yanıt verileri", + "@responseData": {}, + "responseInvalid": "Geçersiz yanıt kodu.", + "@responseInvalid": {}, + "responseUnknown": "Bilinmeyen yanıt", + "@responseUnknown": {}, + "result": "Sonuç", + "@result": { + "description": "" + }, + "returned": "Geri Dönen", + "@returned": {}, + "salesOrders": "Satış Siparişleri", + "@salesOrders": {}, + "save": "Kaydet", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barkod Tara", + "@scanBarcode": {}, + "scanIntoLocation": "Konuma Tara", + "@scanIntoLocation": {}, + "search": "Ara", + "@search": { + "description": "search" + }, + "searchLocation": "Konum için Ara", + "@searchLocation": {}, + "searchParts": "Parçaları Ara", + "@searchParts": {}, + "searchStock": "Stok Ara", + "@searchStock": {}, + "select": "Seç", + "@select": {}, + "selectFile": "Dosya Seç", + "@selectFile": {}, + "selectImage": "Resim Seç", + "@selectImage": {}, + "selectLocation": "Bir yer seçin", + "@selectLocation": {}, + "send": "Gönder", + "@send": {}, + "serialNumber": "Seri Numara", + "@serialNumber": {}, + "server": "Sunucu", + "@server": {}, + "serverAddress": "Sunucu Adresi", + "@serverAddress": {}, + "serverApiRequired": "Gerekli API Sürümü", + "@serverApiRequired": {}, + "serverApiVersion": "Sunucu API Sürümü", + "@serverApiVersion": {}, + "serverAuthenticationError": "Doğrulama Hatası", + "@serverAuthenticationError": {}, + "serverCertificateError": "Sertifika Hatası", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Sunucunun sertifikası geçersiz", + "@serverCertificateInvalid": {}, + "serverConnected": "Sunucuya bağlanıldı", + "@serverConnected": {}, + "serverConnecting": "Sunucuya bağlanıyor", + "@serverConnecting": {}, + "serverCouldNotConnect": "Sunucuya bağlanılamadı", + "@serverCouldNotConnect": {}, + "serverEmpty": "Sunucu boş olamaz", + "@serverEmpty": {}, + "serverError": "Sunucu Hatası", + "@serverError": {}, + "serverDetails": "Sunucu Detayları", + "@serverDetails": {}, + "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", + "@serverMissingData": {}, + "serverOld": "Eski Sunucu Sürümü", + "@serverOld": {}, + "serverSettings": "Sunucu Ayarları", + "@serverSettings": {}, + "serverStart": "Sunucu http(s) ile başlamalı", + "@serverStart": {}, + "settings": "Ayarlar", + "@settings": {}, + "serverInstance": "Sunucu örneği", + "@serverInstance": {}, + "serverNotConnected": "Sunucu bağlı değil", + "@serverNotConnected": {}, + "sounds": "Sesler", + "@sounds": {}, + "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Sunucu hatasında sesli ton çal", + "@soundOnServerError": {}, + "status": "Durum", + "@status": {}, + "statusCode": "Durum Kodu", + "@statusCode": {}, + "stock": "Stok", + "@stock": { + "description": "stock" + }, + "stockItem": "Stok Kalemi", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stok Kalemleri", + "@stockItems": {}, + "stockItemCreate": "Yeni Stok Kalemi", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Stok parçasını sil", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Stok parçası silinemedi", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stok parçası silindi", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stok Geçmişi", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Stok takip bilgisini göster", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stok kalemi transfer edildi", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stok kalemi güncellendi", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Uygun stok kalemi yok", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stok Kalemi Notları", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stok kalemi güncellendi", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stok kalemi güncelleme hatası", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stok Konumu", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stok Konumları", + "@stockLocations": {}, + "stockTopLevel": "Üst seviye stok konumu", + "@stockTopLevel": {}, + "subcategory": "Alt kategori", + "@subcategory": {}, + "subcategories": "Alt kategoriler", + "@subcategories": {}, + "sublocation": "Alt konumlar", + "@sublocation": {}, + "sublocations": "Alt konumlar", + "@sublocations": {}, + "sublocationNone": "Alt konum yok", + "@sublocationNone": {}, + "sublocationNoneDetail": "Uygun alt kategori yok", + "@sublocationNoneDetail": {}, + "submitFeedback": "Geri Bildirim Gönder", + "@submitFeedback": {}, + "suppliedParts": "Sağlanan Parçalar", + "@suppliedParts": {}, + "supplier": "Tedarikçi", + "@supplier": {}, + "suppliers": "Tedarikçiler", + "@suppliers": {}, + "supplierReference": "Tedarikçi Referansı", + "@supplierReference": {}, + "takePicture": "Resim Çek", + "@takePicture": {}, + "targetDate": "Hedeflenen Tarih", + "@targetDate": {}, + "testName": "Test Adı", + "@testName": {}, + "testPassedOrFailed": "Test başarılı veya hatalı", + "@testPassedOrFailed": {}, + "testsRequired": "Gerekli Testler", + "@testsRequired": {}, + "testResults": "Test Sonuçları", + "@testResults": { + "description": "" + }, + "testResultAdd": "Test Sonucu Ekle", + "@testResultAdd": {}, + "testResultNone": "Test Sonucu Yok", + "@testResultNone": {}, + "testResultNoneDetail": "Uygun test sonucu yok", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Hatalı yüklenen test sonucu", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test sonucu yüklendi", + "@testResultUploadPass": {}, + "timeout": "Zaman Aşımı", + "@timeout": { + "description": "" + }, + "tokenError": "Token Hatası", + "@tokenError": {}, + "tokenMissing": "Eksik Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", + "@tokenMissingFromResponse": {}, + "transfer": "Aktarım", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Stok Aktar", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Çeviri", + "@translate": {}, + "translateHelp": "Çeviriye yardım et", + "@translateHelp": {}, + "units": "Birim", + "@units": {}, + "unknownResponse": "Bilinmeyen Yanıt", + "@unknownResponse": {}, + "upload": "Yükle", + "@upload": {}, + "uploadFailed": "Dosya yüklenemedi", + "@uploadFailed": {}, + "uploadSuccess": "Dosya yüklendi", + "@uploadSuccess": {}, + "usedIn": "Burada Kullanıldı", + "@usedIn": {}, + "usedInDetails": "Bu parçayı gerektiren montajlar", + "@usedInDetails": {}, + "username": "Kullanıcı Adı", + "@username": {}, + "usernameEmpty": "Kullanıcı adı boş bırakılamaz", + "@usernameEmpty": {}, + "value": "Değer", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Değer boş olamaz", + "@valueCannotBeEmpty": {}, + "valueRequired": "Değer gereklidir", + "@valueRequired": {}, + "version": "Sürüm", + "@version": {}, + "viewSupplierPart": "Tedarikçi Parçası Görüntüle", + "@viewSupplierPart": {}, + "website": "Web sitesi", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 36d80aa..08adba6 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "vi", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 36d80aa..a94ee5b 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -1,5 +1,341 @@ { - "@@locale": "en", + "@@locale": "zh", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "好", + "@ok": { + "description": "OK" + }, + "about": "关于", + "@about": {}, + "accountDetails": "账户详情", + "@accountDetails": {}, + "actions": "操作", + "@actions": { + "description": "" + }, + "add": "添加", + "@add": { + "description": "add" + }, + "addStock": "添加库存", + "@addStock": { + "description": "add stock" + }, + "address": "地址", + "@address": {}, + "appAbout": "关于 InventTree", + "@appAbout": {}, + "appDetails": "应用详情", + "@appDetails": {}, + "appSettings": "应用设置", + "@appSettings": {}, + "attention": "注意", + "@attention": {}, + "barcodeAssign": "分配条码", + "@barcodeAssign": {}, + "barcodeAssigned": "条码已分配", + "@barcodeAssigned": {}, + "barcodeError": "条形码扫描出错", + "@barcodeError": {}, + "barcodeInUse": "条码已经被分配", + "@barcodeInUse": {}, + "barcodeNoMatch": "无匹配条码", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "未分配条码", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "扫描以分配条码", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "扫描 InvenTree 条码", + "@barcodeScanGeneral": {}, + "barcodeScanLocation": "扫描库存地点", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "已扫描至位置", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanItem": "扫描库存项", + "@barcodeScanItem": {}, + "barcodeUnassign": "取消分配条码", + "@barcodeUnassign": {}, + "barcodeUnknown": "无法识别条码", + "@barcodeUnknown": {}, + "build": "生产", + "@build": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "category": "分类", + "@category": {}, + "categoryCreate": "新建分类", + "@categoryCreate": {}, + "categoryCreateDetail": "新建商品类别", + "@categoryCreateDetail": {}, + "company": "公司", + "@company": {}, + "companyEdit": "编辑公司信息", + "@companyEdit": {}, + "companies": "公司", + "@companies": {}, + "connectionRefused": "连接被拒绝", + "@connectionRefused": {}, + "count": "数量", + "@count": { + "description": "Count" + }, + "countStock": "库存数量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "致谢", + "@credits": {}, + "damaged": "破损", + "@damaged": {}, + "delete": "删除", + "@delete": {}, + "description": "描述", + "@description": {}, + "destroyed": "销毁", + "@destroyed": {}, + "details": "详细信息", + "@details": { + "description": "details" + }, + "documentation": "文档", + "@documentation": {}, + "edit": "编辑", + "@edit": { + "description": "edit" + }, + "editCategory": "编辑分类", + "@editCategory": {}, + "editLocation": "编辑位置", + "@editLocation": {}, + "editPart": "编辑部件", + "@editPart": { + "description": "edit part" + }, + "error": "错误", + "@error": { + "description": "Error" + }, + "errorDetails": "c w错误详情", + "@errorDetails": {}, + "history": "历史", + "@history": { + "description": "history" + }, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "internalPartNumber": "内部部件号", + "@internalPartNumber": {}, + "info": "信息", + "@info": {}, + "invalidPart": "无效部件", + "@invalidPart": {}, + "invalidPartCategory": "无效部件分类", + "@invalidPartCategory": {}, + "invalidStockLocation": "无效库存位置", + "@invalidStockLocation": {}, + "invalidStockItem": "无效库存项", + "@invalidStockItem": {}, + "keywords": "关键词", + "@keywords": {}, + "link": "链接", + "@link": {}, + "lost": "丢失", + "@lost": {}, + "name": "名称", + "@name": {}, + "notConnected": "未连接", + "@notConnected": {}, + "notes": "注释", + "@notes": { + "description": "Notes" + }, + "noResponse": "服务器未响应", + "@noResponse": {}, + "parent": "父级", + "@parent": {}, + "parentCategory": "父类别", + "@parentCategory": {}, + "part": "部件", + "@part": { + "description": "Part (single)" + }, + "parts": "部件", + "@parts": { + "description": "Part (multiple)" + }, + "partCategory": "部件分类", + "@partCategory": {}, + "partCategories": "部件分类", + "@partCategories": {}, + "partDetails": "部件详情", + "@partDetails": {}, + "partNotes": "部件注释", + "@partNotes": {}, + "partStock": "部件库存", + "@partStock": { + "description": "part stock" + }, + "password": "密码", + "@password": {}, + "profile": "档案", + "@profile": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "容量为空", + "@quantityEmpty": {}, + "quantityInvalid": "数量无效", + "@quantityInvalid": {}, + "quantityPositive": "数量必须大于0", + "@quantityPositive": {}, + "refresh": "刷新", + "@refresh": {}, + "refreshing": "正在刷新", + "@refreshing": {}, + "rejected": "已拒绝", + "@rejected": {}, + "releaseNotes": "更新日志", + "@releaseNotes": {}, + "remove": "移除", + "@remove": { + "description": "remove" + }, + "removeStock": "移除库存", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "反馈问题", + "@reportBug": {}, + "request": "请求", + "@request": {}, + "requestingData": "正在请求数据", + "@requestingData": {}, + "required": "必填", + "@required": { + "description": "This field is required" + }, + "responseInvalid": "无效响应码", + "@responseInvalid": {}, + "responseUnknown": "未知响应", + "@responseUnknown": {}, + "result": "结果", + "@result": { + "description": "" + }, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "扫描条码", + "@scanBarcode": {}, + "scanIntoLocation": "已扫描至位置", + "@scanIntoLocation": {}, + "search": "搜索", + "@search": { + "description": "search" + }, + "searchParts": "搜索部件", + "@searchParts": {}, + "searchStock": "搜索库存", + "@searchStock": {}, + "select": "选择", + "@select": {}, + "send": "发送", + "@send": {}, + "serialNumber": "序列号", + "@serialNumber": {}, + "server": "服务器", + "@server": {}, + "serverAddress": "服务器地址", + "@serverAddress": {}, + "serverConnected": "已连接至服务器", + "@serverConnected": {}, + "serverError": "服务器错误", + "@serverError": {}, + "serverDetails": "服务器详情", + "@serverDetails": {}, + "serverOld": "过时的服务器版本", + "@serverOld": {}, + "serverSettings": "服务器设置", + "@serverSettings": {}, + "settings": "设置", + "@settings": {}, + "serverInstance": "服务器实例", + "@serverInstance": {}, + "serverNotConnected": "未连接至服务器", + "@serverNotConnected": {}, + "status": "状态", + "@status": {}, + "statusCode": "状态码", + "@statusCode": {}, + "stock": "库存", + "@stock": { + "description": "stock" + }, + "stockItem": "库存项", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "库存项", + "@stockItems": {}, + "stockItemNotes": "库存项注释", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "库存项已更新", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "库存项更新失败", + "@stockItemUpdateFailure": {}, + "stockLocation": "库存位置", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "库存位置", + "@stockLocations": {}, + "subcategory": "子类别", + "@subcategory": {}, + "subcategories": "子类别", + "@subcategories": {}, + "sublocation": "次级位置", + "@sublocation": {}, + "sublocations": "次级位置", + "@sublocations": {}, + "testResults": "测试结果", + "@testResults": { + "description": "" + }, + "timeout": "超时", + "@timeout": { + "description": "" + }, + "tokenError": "令牌错误", + "@tokenError": {}, + "tokenMissing": "缺少令牌", + "@tokenMissing": {}, + "transfer": "转移", + "@transfer": { + "description": "transfer" + }, + "transferStock": "转移库存", + "@transferStock": { + "description": "transfer stock" + }, + "unknownResponse": "未知响应", + "@unknownResponse": {}, + "upload": "上传", + "@upload": {}, + "username": "用户名", + "@username": {}, + "value": "值", + "@value": { + "description": "value" + }, + "version": "版本", + "@version": {}, + "website": "网站", + "@website": {} } \ No newline at end of file From f78002377045aa0ba9486af53ce869abbd47d01b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 12:05:52 +1000 Subject: [PATCH 040/746] Reintroduce translation file collection script --- lib/l10n/.gitignore | 2 + lib/l10n/collect_translations.py | 97 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 lib/l10n/.gitignore create mode 100644 lib/l10n/collect_translations.py diff --git a/lib/l10n/.gitignore b/lib/l10n/.gitignore new file mode 100644 index 0000000..1a05426 --- /dev/null +++ b/lib/l10n/.gitignore @@ -0,0 +1,2 @@ +# Do not track the collected translation files +collected/ \ No newline at end of file diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py new file mode 100644 index 0000000..f1987e3 --- /dev/null +++ b/lib/l10n/collect_translations.py @@ -0,0 +1,97 @@ +""" +Collect translation files into a single directory, +where they can be accessed by the flutter i18n library. + +Translations provided from crowdin are located in subdirectories, +but we need the .arb files to appear in this top level directory +to be accessed by the app. + +So, simply copy them here! + +""" + +import os +import shutil +import re +import json + +def process_locale_file(filename): + """ + Process a locale file after copying + + - Ensure the 'locale' matches + """ + + # Extract the locale name from the filename + f = os.path.basename(filename) + locale = re.search(r"^app\_(\w+)\.arb$", f).groups()[0] + + # TODO: Use JSON processing instead of manual + # Need to work out unicode issues for this to work + + with open(filename, 'r', encoding='utf-8') as input_file: + + lines = input_file.readlines() + + with open(filename, 'w', encoding='utf-8') as output_file: + # Using JSON processing would be simpler here, + # but it does not preserve unicode data! + for line in lines: + if '@@locale' in line: + new_line = f' "@@locale": "{locale}"' + + if ',' in line: + new_line += ',' + + new_line += '\n' + + line = new_line + + output_file.write(line) + + +def copy_locale_file(path): + """ + Locate and copy the locale file from the provided directory + """ + + here = os.path.abspath(os.path.dirname(__file__)) + + for f in os.listdir(path): + + src = os.path.join(path, f) + dst = os.path.join(here, 'collected', f) + + if os.path.exists(src) and os.path.isfile(src) and f.endswith('.arb'): + + shutil.copyfile(src, dst) + print(f"Copied file '{f}'") + + process_locale_file(dst) + + +if __name__ == '__main__': + + here = os.path.abspath(os.path.dirname(__file__)) + + # Ensure the 'collected' output directory exists + output_dir = os.path.join(here, 'collected') + os.makedirs(output_dir, exist_ok=True) + + for item in os.listdir(here): + + # Ignore the output directory + if item == 'collected': + continue + + f = os.path.join(here, item) + + if os.path.exists(f) and os.path.isdir(item): + copy_locale_file(f) + + # Ensure the translation source file ('app_en.arb') is copied also + # Note that this does not require any further processing + src = os.path.join(here, 'app_en.arb') + dst = os.path.join(here, 'collected', 'app_en.arb') + + shutil.copyfile(src, dst) From b6273287a930e21547ece022b2a80f30b81adf27 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 12:08:51 +1000 Subject: [PATCH 041/746] Update CI workflow scripts --- .github/workflows/ios.yaml | 4 ++++ .github/workflows/lint.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 202c684..039a6e9 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -28,6 +28,10 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' + - name: Collect Translation Files + run: | + cd lib/l10n + python3 collect_translations.py - name: Build for iOS run: | flutter pub get diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index a9d3fe7..44b1ed3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -31,6 +31,10 @@ jobs: uses: subosito/flutter-action@v1 with: flutter-version: '2.10.3' + - name: Collect Translation Files + run: | + cd lib/l10n + python3 collect_translations.py - run: flutter pub get - run: cp lib/dummy_dsn.dart lib/dsn.dart - run: flutter analyze From eac9da3bb79210cd6611cfeb8f6f4a888b891880 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:49 +1000 Subject: [PATCH 042/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index b4ded9e..81610da 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1,21 +1,9 @@ { - "@@locale": "fr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "À propos", "@about": {}, "accountDetails": "Détails du compte", "@accountDetails": {}, - "actions": "Actions", - "@actions": { - "description": "" - }, "actionsNone": "Aucune action disponible", "@actionsNone": {}, "add": "Ajouter", @@ -52,8 +40,6 @@ "@attachmentNonePartDetail": {}, "attachmentSelect": "Sélectionner une pièce jointe", "@attachmentSelect": {}, - "attention": "Attention", - "@attention": {}, "availableStock": "Stock disponible", "@availableStock": {}, "barcodeAssign": "Affecter un code-barres", @@ -94,8 +80,6 @@ "@batchCode": {}, "billOfMaterials": "Liste des matériaux", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Assemblage", "@build": {}, "building": "Assemblage en cours", @@ -146,16 +130,12 @@ "@deletePart": {}, "deletePartDetail": "Supprimer cette pièce de la base de données", "@deletePartDetail": {}, - "description": "Description", - "@description": {}, "destroyed": "Détruit", "@destroyed": {}, "details": "Détails", "@details": { "description": "details" }, - "documentation": "Documentation", - "@documentation": {}, "downloading": "Téléchargement du fichier", "@downloading": {}, "downloadError": "Erreur lors du téléchargement", @@ -312,10 +292,6 @@ "@name": {}, "notConnected": "Non connecté", "@notConnected": {}, - "notes": "Notes", - "@notes": { - "description": "Notes" - }, "noResponse": "Aucune réponse du serveur", "@noResponse": {}, "noResults": "Aucun résultat", @@ -334,8 +310,6 @@ "@packaging": {}, "packageName": "Nom du package", "@packageName": {}, - "parent": "Parent", - "@parent": {}, "parentCategory": "Catégorie parent", "@parentCategory": {}, "parentLocation": "Emplacement parent", @@ -588,10 +562,6 @@ "@status": {}, "statusCode": "Code d'état", "@statusCode": {}, - "stock": "Stock", - "@stock": { - "description": "stock" - }, "stockDetails": "Quantité actuelle de stock disponible", "@stockDetails": {}, "stockItem": "Article en stock", @@ -734,8 +704,6 @@ "@valueCannotBeEmpty": {}, "valueRequired": "La valeur est requise", "@valueRequired": {}, - "version": "Version", - "@version": {}, "viewSupplierPart": "Voir la pièce du fournisseur", "@viewSupplierPart": {}, "website": "Site web", From e13e2de7dd80eaa71356165df1c1100a788b1901 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:50 +1000 Subject: [PATCH 043/746] New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 65bbe17..1848474 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -1,13 +1,5 @@ { - "@@locale": "pt", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Sobre", "@about": {}, "accountDetails": "Detalhes da Conta", From 7ca05112dd4fc5260a0818012c2ec15955aced65 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:51 +1000 Subject: [PATCH 044/746] New translations app_en.arb (Persian) --- lib/l10n/fa_IR/app_fa_IR.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index f17cd61..36d80aa 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,5 @@ { - "@@locale": "fa", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 26dd45eca3d374ac3b2a20434420eec4c095783a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:52 +1000 Subject: [PATCH 045/746] New translations app_en.arb (Indonesian) --- lib/l10n/id_ID/app_id_ID.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index c917076..36d80aa 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,5 @@ { - "@@locale": "id", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 12b2c7f445f8bf9958c6c91d04efbf162390681d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:53 +1000 Subject: [PATCH 046/746] New translations app_en.arb (Vietnamese) --- lib/l10n/vi_VN/app_vi_VN.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 08adba6..36d80aa 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -1,5 +1,5 @@ { - "@@locale": "vi", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From b9ced1b03bf6a60b6861ecab4e917ea1f5c6bee6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:54 +1000 Subject: [PATCH 047/746] New translations app_en.arb (Chinese Simplified) --- lib/l10n/zh_CN/app_zh_CN.arb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index a94ee5b..b41d65d 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -1,9 +1,5 @@ { - "@@locale": "zh", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "好", "@ok": { "description": "OK" From 587ea41930c7f6157882625e364bb17a767c0c57 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:55 +1000 Subject: [PATCH 048/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 447ecee..d9aaa29 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -1,9 +1,5 @@ { - "@@locale": "tr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "TAMAM", "@ok": { "description": "OK" @@ -92,8 +88,6 @@ "@batchCode": {}, "billOfMaterials": "Fatura materyalleri", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Oluştur", "@build": {}, "building": "Oluşturma", From 546af967927130665dfaf7fdaa59843f928b9c34 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:56 +1000 Subject: [PATCH 049/746] New translations app_en.arb (Swedish) --- lib/l10n/sv_SE/app_sv_SE.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index e37c200..36d80aa 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -1,5 +1,5 @@ { - "@@locale": "sv", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 09565bd462bd9645af81c3d156ca376edb0da654 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:56 +1000 Subject: [PATCH 050/746] New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index d89f472..c71ac25 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -1,9 +1,5 @@ { - "@@locale": "ru", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "ОК", "@ok": { "description": "OK" From 831fe8d61d1423a4f0ae72dfcb65ca692bc37ab2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:58 +1000 Subject: [PATCH 051/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 4274486..7a403f3 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1,13 +1,5 @@ { - "@@locale": "pl", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "O nas", "@about": {}, "accountDetails": "Szczegóły konta", @@ -92,8 +84,6 @@ "@batchCode": {}, "billOfMaterials": "Zestawienie materiałów", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Budowa", "@build": {}, "building": "Budowanie", @@ -256,8 +246,6 @@ "@incompleteDetails": {}, "internalPartNumber": "Wewnętrzny numer części", "@internalPartNumber": {}, - "info": "Info", - "@info": {}, "inProduction": "W produkcji", "@inProduction": {}, "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", @@ -298,8 +286,6 @@ "@locationNotSet": {}, "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Zagubiono", "@lost": {}, "manufacturers": "Producenci", @@ -582,8 +568,6 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", "@soundOnServerError": {}, - "status": "Status", - "@status": {}, "statusCode": "Kod statusu", "@statusCode": {}, "stock": "Stan", From e661f6d6072287f4730b0caca9a95733f9c47cd2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:58 +1000 Subject: [PATCH 052/746] New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 17a7a62..91793f1 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -1,5 +1,5 @@ { - "@@locale": "es", + "@@locale": "en", "barcodeScanInItems": "Escanear artículos de stock en su ubicación", "@barcodeScanInItems": {}, "@homeShowSubscsribedDescription": {}, From 1585da0b6ffca31a6e908a8b9cd4cfbdc1a9c421 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:21:59 +1000 Subject: [PATCH 053/746] New translations app_en.arb (Norwegian) --- lib/l10n/no_NO/app_no_NO.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 34df543..36d80aa 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -1,5 +1,5 @@ { - "@@locale": "no", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From d571e25bc3721ad4b161465dfc5077328032a05f Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:00 +1000 Subject: [PATCH 054/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 40c32de..36d80aa 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -1,5 +1,5 @@ { - "@@locale": "nl", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From c4e90252e0d767469b2a35e41d7401e8beebf89a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:01 +1000 Subject: [PATCH 055/746] New translations app_en.arb (Korean) --- lib/l10n/ko_KR/app_ko_KR.arb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 0bc359b..2f42897 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -1,9 +1,5 @@ { - "@@locale": "ko", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "add": "추가", "@add": { "description": "add" From 95a9c21014f6267ab328dd1e282367624b6ff15d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:01 +1000 Subject: [PATCH 056/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index c55ad78..6c5a25e 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,13 +1,5 @@ { - "@@locale": "ja", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "概要", "@about": {}, "accountDetails": "アカウントの詳細", @@ -84,16 +76,10 @@ "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "在庫アイテムをスキャン", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", - "@barcodeTones": {}, "barcodeUnassign": "バーコードの割り当てを解除", "@barcodeUnassign": {}, "barcodeUnknown": "バーコードが認識されません", "@barcodeUnknown": {}, - "billOfMaterials": "Bill of Materials", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "ビルド", "@build": {}, "building": "ビルド", From e61949d1296f9d0ac02be79ba658b30217b2b5f8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:03 +1000 Subject: [PATCH 057/746] New translations app_en.arb (Italian) --- lib/l10n/it_IT/app_it_IT.arb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 4df3b7d..b9a1b84 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -1,13 +1,5 @@ { - "@@locale": "it", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Info", "@about": {}, "accountDetails": "Dettagli account", @@ -176,8 +168,6 @@ "@includeSubcategories": {}, "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", "@incompleteDetails": {}, - "info": "Info", - "@info": {}, "invalidHost": "Nome host non valido", "@invalidHost": {}, "invalidHostDetails": "Il nome host fornito non è valido", @@ -232,8 +222,6 @@ }, "partSuppliers": "Fornitori articoli", "@partSuppliers": {}, - "password": "Password", - "@password": {}, "passwordEmpty": "La password non può essere vuota", "@passwordEmpty": {}, "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", @@ -366,8 +354,6 @@ "@send": {}, "serialNumber": "Numero seriale", "@serialNumber": {}, - "server": "Server", - "@server": {}, "serverAddress": "Indirizzo del server", "@serverAddress": {}, "serverApiRequired": "Versione API Richiesta", From 4f4c8ad556f00cc0fc30349a29daa7caa2e901ec Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:04 +1000 Subject: [PATCH 058/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 98a69b4..b378a02 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -1,13 +1,5 @@ { - "@@locale": "hu", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Névjegy", "@about": {}, "accountDetails": "Felhasználó adatok", @@ -300,8 +292,6 @@ "@locationNotSet": {}, "locationUpdated": "Készlet hely adatai frissítve", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Elveszett", "@lost": {}, "manufacturers": "Gyártók", From 892ad353f468814673a181102c52f8b641843aec Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:04 +1000 Subject: [PATCH 059/746] New translations app_en.arb (Hebrew) --- lib/l10n/he_IL/app_he_IL.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 2d1bbf1..36d80aa 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,5 @@ { - "@@locale": "he", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 570daff7ff5bb22a1b231ef5df1686c420636d42 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:05 +1000 Subject: [PATCH 060/746] New translations app_en.arb (Greek) --- lib/l10n/el_GR/app_el_GR.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 2ae9e43..36d80aa 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -1,5 +1,5 @@ { - "@@locale": "el", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 62be205ab093b45f72b2d1c991b807d92784bfd2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:06 +1000 Subject: [PATCH 061/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index ec3b2b6..a4e0e6f 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1,13 +1,5 @@ { - "@@locale": "de", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Über", "@about": {}, "accountDetails": "Konto Details", @@ -150,10 +142,6 @@ "@description": {}, "destroyed": "Vernichtet", "@destroyed": {}, - "details": "Details", - "@details": { - "description": "details" - }, "documentation": "Dokumentation", "@documentation": {}, "downloading": "Datei wird heruntergeladen", @@ -198,8 +186,6 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", "@errorReportUploadDetails": {}, - "feedback": "Feedback", - "@feedback": {}, "feedbackError": "Fehler beim Senden des Feedbacks", "@feedbackError": {}, "feedbackSuccess": "Feedback gesendet", @@ -258,8 +244,6 @@ "@incompleteDetails": {}, "internalPartNumber": "Interne Teilenummer", "@internalPartNumber": {}, - "info": "Info", - "@info": {}, "inProduction": "In Produktion", "@inProduction": {}, "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", @@ -300,16 +284,12 @@ "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Verloren", "@lost": {}, "manufacturers": "Hersteller", "@manufacturers": {}, "missingData": "Fehlende Daten", "@missingData": {}, - "name": "Name", - "@name": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, "notes": "Notizen", @@ -538,8 +518,6 @@ "@send": {}, "serialNumber": "Seriennummer", "@serialNumber": {}, - "server": "Server", - "@server": {}, "serverAddress": "Serveradresse", "@serverAddress": {}, "serverApiRequired": "Erforderliche API-Version", @@ -584,8 +562,6 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Ton bei Serverfehler abspielen", "@soundOnServerError": {}, - "status": "Status", - "@status": {}, "statusCode": "Statuscode", "@statusCode": {}, "stock": "Bestand", @@ -736,10 +712,6 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Wert erforderlich", "@valueRequired": {}, - "version": "Version", - "@version": {}, "viewSupplierPart": "Zulieferer-Teil anzeigen", - "@viewSupplierPart": {}, - "website": "Website", - "@website": {} + "@viewSupplierPart": {} } \ No newline at end of file From 9ed7a9a224957b690ef1c04bb854258c1b8729d3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:06 +1000 Subject: [PATCH 062/746] New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 1aeae1d..36d80aa 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -1,5 +1,5 @@ { - "@@locale": "cs", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 9043ae3bf2cc7021081dc68d08c602550d473fe0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:22:07 +1000 Subject: [PATCH 063/746] New translations app_en.arb (Thai) --- lib/l10n/th_TH/app_th_TH.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 5fdf211..36d80aa 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,5 @@ { - "@@locale": "th", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file From 26e48f57ebb0147e4fa8e9f9471b8b3330c63319 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 May 2022 12:23:27 +1000 Subject: [PATCH 064/746] New Crowdin updates (#115) * New translations app_en.arb (French) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Persian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Turkish) * New translations app_en.arb (Swedish) * New translations app_en.arb (Russian) * New translations app_en.arb (Polish) * New translations app_en.arb (Spanish) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Korean) * New translations app_en.arb (Japanese) * New translations app_en.arb (Italian) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Greek) * New translations app_en.arb (German) * New translations app_en.arb (Czech) * New translations app_en.arb (Thai) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 +- lib/l10n/de_DE/app_de_DE.arb | 32 ++------------------------------ lib/l10n/el_GR/app_el_GR.arb | 2 +- lib/l10n/es_ES/app_es_ES.arb | 2 +- lib/l10n/fa_IR/app_fa_IR.arb | 2 +- lib/l10n/fr_FR/app_fr_FR.arb | 34 +--------------------------------- lib/l10n/he_IL/app_he_IL.arb | 2 +- lib/l10n/hu_HU/app_hu_HU.arb | 12 +----------- lib/l10n/id_ID/app_id_ID.arb | 2 +- lib/l10n/it_IT/app_it_IT.arb | 16 +--------------- lib/l10n/ja_JP/app_ja_JP.arb | 16 +--------------- lib/l10n/ko_KR/app_ko_KR.arb | 6 +----- lib/l10n/nl_NL/app_nl_NL.arb | 2 +- lib/l10n/no_NO/app_no_NO.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 18 +----------------- lib/l10n/pt_PT/app_pt_PT.arb | 10 +--------- lib/l10n/ru_RU/app_ru_RU.arb | 6 +----- lib/l10n/sv_SE/app_sv_SE.arb | 2 +- lib/l10n/th_TH/app_th_TH.arb | 2 +- lib/l10n/tr_TR/app_tr_TR.arb | 8 +------- lib/l10n/vi_VN/app_vi_VN.arb | 2 +- lib/l10n/zh_CN/app_zh_CN.arb | 6 +----- 22 files changed, 23 insertions(+), 163 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 1aeae1d..36d80aa 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -1,5 +1,5 @@ { - "@@locale": "cs", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index ec3b2b6..a4e0e6f 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1,13 +1,5 @@ { - "@@locale": "de", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Über", "@about": {}, "accountDetails": "Konto Details", @@ -150,10 +142,6 @@ "@description": {}, "destroyed": "Vernichtet", "@destroyed": {}, - "details": "Details", - "@details": { - "description": "details" - }, "documentation": "Dokumentation", "@documentation": {}, "downloading": "Datei wird heruntergeladen", @@ -198,8 +186,6 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", "@errorReportUploadDetails": {}, - "feedback": "Feedback", - "@feedback": {}, "feedbackError": "Fehler beim Senden des Feedbacks", "@feedbackError": {}, "feedbackSuccess": "Feedback gesendet", @@ -258,8 +244,6 @@ "@incompleteDetails": {}, "internalPartNumber": "Interne Teilenummer", "@internalPartNumber": {}, - "info": "Info", - "@info": {}, "inProduction": "In Produktion", "@inProduction": {}, "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", @@ -300,16 +284,12 @@ "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Verloren", "@lost": {}, "manufacturers": "Hersteller", "@manufacturers": {}, "missingData": "Fehlende Daten", "@missingData": {}, - "name": "Name", - "@name": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, "notes": "Notizen", @@ -538,8 +518,6 @@ "@send": {}, "serialNumber": "Seriennummer", "@serialNumber": {}, - "server": "Server", - "@server": {}, "serverAddress": "Serveradresse", "@serverAddress": {}, "serverApiRequired": "Erforderliche API-Version", @@ -584,8 +562,6 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Ton bei Serverfehler abspielen", "@soundOnServerError": {}, - "status": "Status", - "@status": {}, "statusCode": "Statuscode", "@statusCode": {}, "stock": "Bestand", @@ -736,10 +712,6 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Wert erforderlich", "@valueRequired": {}, - "version": "Version", - "@version": {}, "viewSupplierPart": "Zulieferer-Teil anzeigen", - "@viewSupplierPart": {}, - "website": "Website", - "@website": {} + "@viewSupplierPart": {} } \ No newline at end of file diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 2ae9e43..36d80aa 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -1,5 +1,5 @@ { - "@@locale": "el", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 17a7a62..91793f1 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -1,5 +1,5 @@ { - "@@locale": "es", + "@@locale": "en", "barcodeScanInItems": "Escanear artículos de stock en su ubicación", "@barcodeScanInItems": {}, "@homeShowSubscsribedDescription": {}, diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index f17cd61..36d80aa 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,5 @@ { - "@@locale": "fa", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index b4ded9e..81610da 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1,21 +1,9 @@ { - "@@locale": "fr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "À propos", "@about": {}, "accountDetails": "Détails du compte", "@accountDetails": {}, - "actions": "Actions", - "@actions": { - "description": "" - }, "actionsNone": "Aucune action disponible", "@actionsNone": {}, "add": "Ajouter", @@ -52,8 +40,6 @@ "@attachmentNonePartDetail": {}, "attachmentSelect": "Sélectionner une pièce jointe", "@attachmentSelect": {}, - "attention": "Attention", - "@attention": {}, "availableStock": "Stock disponible", "@availableStock": {}, "barcodeAssign": "Affecter un code-barres", @@ -94,8 +80,6 @@ "@batchCode": {}, "billOfMaterials": "Liste des matériaux", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Assemblage", "@build": {}, "building": "Assemblage en cours", @@ -146,16 +130,12 @@ "@deletePart": {}, "deletePartDetail": "Supprimer cette pièce de la base de données", "@deletePartDetail": {}, - "description": "Description", - "@description": {}, "destroyed": "Détruit", "@destroyed": {}, "details": "Détails", "@details": { "description": "details" }, - "documentation": "Documentation", - "@documentation": {}, "downloading": "Téléchargement du fichier", "@downloading": {}, "downloadError": "Erreur lors du téléchargement", @@ -312,10 +292,6 @@ "@name": {}, "notConnected": "Non connecté", "@notConnected": {}, - "notes": "Notes", - "@notes": { - "description": "Notes" - }, "noResponse": "Aucune réponse du serveur", "@noResponse": {}, "noResults": "Aucun résultat", @@ -334,8 +310,6 @@ "@packaging": {}, "packageName": "Nom du package", "@packageName": {}, - "parent": "Parent", - "@parent": {}, "parentCategory": "Catégorie parent", "@parentCategory": {}, "parentLocation": "Emplacement parent", @@ -588,10 +562,6 @@ "@status": {}, "statusCode": "Code d'état", "@statusCode": {}, - "stock": "Stock", - "@stock": { - "description": "stock" - }, "stockDetails": "Quantité actuelle de stock disponible", "@stockDetails": {}, "stockItem": "Article en stock", @@ -734,8 +704,6 @@ "@valueCannotBeEmpty": {}, "valueRequired": "La valeur est requise", "@valueRequired": {}, - "version": "Version", - "@version": {}, "viewSupplierPart": "Voir la pièce du fournisseur", "@viewSupplierPart": {}, "website": "Site web", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 2d1bbf1..36d80aa 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,5 @@ { - "@@locale": "he", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 98a69b4..b378a02 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -1,13 +1,5 @@ { - "@@locale": "hu", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Névjegy", "@about": {}, "accountDetails": "Felhasználó adatok", @@ -300,8 +292,6 @@ "@locationNotSet": {}, "locationUpdated": "Készlet hely adatai frissítve", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Elveszett", "@lost": {}, "manufacturers": "Gyártók", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index c917076..36d80aa 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,5 @@ { - "@@locale": "id", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 4df3b7d..b9a1b84 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -1,13 +1,5 @@ { - "@@locale": "it", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Info", "@about": {}, "accountDetails": "Dettagli account", @@ -176,8 +168,6 @@ "@includeSubcategories": {}, "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", "@incompleteDetails": {}, - "info": "Info", - "@info": {}, "invalidHost": "Nome host non valido", "@invalidHost": {}, "invalidHostDetails": "Il nome host fornito non è valido", @@ -232,8 +222,6 @@ }, "partSuppliers": "Fornitori articoli", "@partSuppliers": {}, - "password": "Password", - "@password": {}, "passwordEmpty": "La password non può essere vuota", "@passwordEmpty": {}, "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", @@ -366,8 +354,6 @@ "@send": {}, "serialNumber": "Numero seriale", "@serialNumber": {}, - "server": "Server", - "@server": {}, "serverAddress": "Indirizzo del server", "@serverAddress": {}, "serverApiRequired": "Versione API Richiesta", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index c55ad78..6c5a25e 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,13 +1,5 @@ { - "@@locale": "ja", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "概要", "@about": {}, "accountDetails": "アカウントの詳細", @@ -84,16 +76,10 @@ "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "在庫アイテムをスキャン", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", - "@barcodeTones": {}, "barcodeUnassign": "バーコードの割り当てを解除", "@barcodeUnassign": {}, "barcodeUnknown": "バーコードが認識されません", "@barcodeUnknown": {}, - "billOfMaterials": "Bill of Materials", - "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "ビルド", "@build": {}, "building": "ビルド", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 0bc359b..2f42897 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -1,9 +1,5 @@ { - "@@locale": "ko", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "add": "추가", "@add": { "description": "add" diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 40c32de..36d80aa 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -1,5 +1,5 @@ { - "@@locale": "nl", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 34df543..36d80aa 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -1,5 +1,5 @@ { - "@@locale": "no", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 4274486..7a403f3 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1,13 +1,5 @@ { - "@@locale": "pl", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "O nas", "@about": {}, "accountDetails": "Szczegóły konta", @@ -92,8 +84,6 @@ "@batchCode": {}, "billOfMaterials": "Zestawienie materiałów", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Budowa", "@build": {}, "building": "Budowanie", @@ -256,8 +246,6 @@ "@incompleteDetails": {}, "internalPartNumber": "Wewnętrzny numer części", "@internalPartNumber": {}, - "info": "Info", - "@info": {}, "inProduction": "W produkcji", "@inProduction": {}, "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", @@ -298,8 +286,6 @@ "@locationNotSet": {}, "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", "@locationUpdated": {}, - "link": "Link", - "@link": {}, "lost": "Zagubiono", "@lost": {}, "manufacturers": "Producenci", @@ -582,8 +568,6 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", "@soundOnServerError": {}, - "status": "Status", - "@status": {}, "statusCode": "Kod statusu", "@statusCode": {}, "stock": "Stan", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 65bbe17..1848474 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -1,13 +1,5 @@ { - "@@locale": "pt", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, - "ok": "OK", - "@ok": { - "description": "OK" - }, + "@@locale": "en", "about": "Sobre", "@about": {}, "accountDetails": "Detalhes da Conta", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index d89f472..c71ac25 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -1,9 +1,5 @@ { - "@@locale": "ru", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "ОК", "@ok": { "description": "OK" diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index e37c200..36d80aa 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -1,5 +1,5 @@ { - "@@locale": "sv", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 5fdf211..36d80aa 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,5 @@ { - "@@locale": "th", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 447ecee..d9aaa29 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -1,9 +1,5 @@ { - "@@locale": "tr", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "TAMAM", "@ok": { "description": "OK" @@ -92,8 +88,6 @@ "@batchCode": {}, "billOfMaterials": "Fatura materyalleri", "@billOfMaterials": {}, - "bom": "BOM", - "@bom": {}, "build": "Oluştur", "@build": {}, "building": "Oluşturma", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 08adba6..36d80aa 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -1,5 +1,5 @@ { - "@@locale": "vi", + "@@locale": "en", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index a94ee5b..b41d65d 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -1,9 +1,5 @@ { - "@@locale": "zh", - "appTitle": "InvenTree", - "@appTitle": { - "description": "InvenTree application title string" - }, + "@@locale": "en", "ok": "好", "@ok": { "description": "OK" From 5e4abcf68c38bc04ec9c1c8f24059bfb1ef1f01e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 12:49:59 +1000 Subject: [PATCH 065/746] Translation script creates fallback locale files --- l10n.yaml | 2 +- lib/l10n/collect_translations.py | 45 ++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/l10n.yaml b/l10n.yaml index a5b40b9..7b9da73 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,4 +1,4 @@ -arb-dir: lib/l10n +arb-dir: lib/l10n/collected 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/collect_translations.py b/lib/l10n/collect_translations.py index f1987e3..9b5c062 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -11,21 +11,20 @@ So, simply copy them here! """ import os +import glob +from posixpath import dirname import shutil import re import json +import sys -def process_locale_file(filename): +def process_locale_file(filename, locale_name): """ Process a locale file after copying - Ensure the 'locale' matches """ - # Extract the locale name from the filename - f = os.path.basename(filename) - locale = re.search(r"^app\_(\w+)\.arb$", f).groups()[0] - # TODO: Use JSON processing instead of manual # Need to work out unicode issues for this to work @@ -38,7 +37,7 @@ def process_locale_file(filename): # but it does not preserve unicode data! for line in lines: if '@@locale' in line: - new_line = f' "@@locale": "{locale}"' + new_line = f' "@@locale": "{locale_name}"' if ',' in line: new_line += ',' @@ -67,26 +66,50 @@ def copy_locale_file(path): shutil.copyfile(src, dst) print(f"Copied file '{f}'") - process_locale_file(dst) + locale = os.path.split(path)[-1] + + process_locale_file(dst, locale) + + # Create a "fallback" locale file, without a country code specifier, if it does not exist + r = re.search(r"app_(\w+)_(\w+).arb", f) + locale = r.groups()[0] + fallback = f"app_{locale}.arb" + + fallback_file = os.path.join(here, 'collected', fallback) + + if not os.path.exists(fallback_file): + print(f"Creating fallback file:", fallback_file) + shutil.copyfile(dst, fallback_file) + + process_locale_file(fallback_file, locale) if __name__ == '__main__': here = os.path.abspath(os.path.dirname(__file__)) + # Ensure the 'collected' output directory exists output_dir = os.path.join(here, 'collected') os.makedirs(output_dir, exist_ok=True) - for item in os.listdir(here): + # Remove existing .arb files from output directory + arbs = glob.glob(os.path.join(output_dir, "*.arb")) + + for arb in arbs: + os.remove(arb) + + locales = [] + + for locale in os.listdir(here): # Ignore the output directory - if item == 'collected': + if locale == 'collected': continue - f = os.path.join(here, item) + f = os.path.join(here, locale) - if os.path.exists(f) and os.path.isdir(item): + if os.path.exists(f) and os.path.isdir(locale): copy_locale_file(f) # Ensure the translation source file ('app_en.arb') is copied also From 71c16e055646553908062027c70995c922d403e8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 13:07:04 +1000 Subject: [PATCH 066/746] Auto generate a list of supported locales whenever translations are updated --- lib/l10n/.gitignore | 3 ++- lib/l10n/collect_translations.py | 38 ++++++++++++++++++++++++++++---- lib/main.dart | 34 +++++----------------------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/lib/l10n/.gitignore b/lib/l10n/.gitignore index 1a05426..d0e30b8 100644 --- a/lib/l10n/.gitignore +++ b/lib/l10n/.gitignore @@ -1,2 +1,3 @@ # Do not track the collected translation files -collected/ \ No newline at end of file +collected/ +supported_locales.dart diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index 9b5c062..e6ce6f1 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -15,8 +15,6 @@ import glob from posixpath import dirname import shutil import re -import json -import sys def process_locale_file(filename, locale_name): """ @@ -84,11 +82,38 @@ def copy_locale_file(path): process_locale_file(fallback_file, locale) +def generate_locale_list(locales): + """ + Generate a .dart file which contains all the supported locales, + for importing into the project + """ + + with open("supported_locales.dart", "w") as output: + + output.write("// This file is auto-generated by the 'collect_translations.py' script - do not edit it directly!\n\n") + + output.write('import "package:flutter/material.dart";\n\n') + + output.write("const List supported_locales = [\n"); + + for locale in locales: + splt = locale.split("_") + + if len(splt) == 2: + lc, cc = splt + else: + lc = locale + cc = '' + + output.write(f' const Locale("{lc}", "{cc}"), // Translations avilable in app_{locale}.arb\n') + + output.write("];\n") + output.write("") + if __name__ == '__main__': here = os.path.abspath(os.path.dirname(__file__)) - # Ensure the 'collected' output directory exists output_dir = os.path.join(here, 'collected') os.makedirs(output_dir, exist_ok=True) @@ -99,7 +124,7 @@ if __name__ == '__main__': for arb in arbs: os.remove(arb) - locales = [] + locales = ['en'] for locale in os.listdir(here): @@ -111,6 +136,7 @@ if __name__ == '__main__': if os.path.exists(f) and os.path.isdir(locale): copy_locale_file(f) + locales.append(locale) # Ensure the translation source file ('app_en.arb') is copied also # Note that this does not require any further processing @@ -118,3 +144,7 @@ if __name__ == '__main__': dst = os.path.join(here, 'collected', 'app_en.arb') shutil.copyfile(src, dst) + + generate_locale_list(locales) + + print(f"Updated translations for {len(locales)} locales.") diff --git a/lib/main.dart b/lib/main.dart index e52a8ff..f8062e3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,6 +12,9 @@ import "package:inventree/inventree/sentry.dart"; import "package:inventree/dsn.dart"; import "package:inventree/widget/home.dart"; +// Supported translations are automatically updated +import "package:inventree/l10n/supported_locales.dart"; + Future main() async { @@ -69,36 +72,9 @@ class InvenTreeApp extends StatelessWidget { I18N.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, ], - supportedLocales: [ - const Locale("cs", ""), // Czech - const Locale("de", ""), // German - const Locale("el", ""), // Greek - const Locale("en", ""), // English - const Locale("es-ES", ""), // Spanish - const Locale("es-MX", ""), // Spanish (mexican) - const Locale("fa", ""), // Farsi (Persian) - const Locale("fr", ""), // French - const Locale("he", ""), // Hebrew - const Locale("hu", ""), // Hungarian - const Locale("id", ""), // Indonesian - const Locale("it", ""), // Italian - const Locale("ja", ""), // Japanese - const Locale("ko", ""), // Korean - const Locale("nl", ""), // Dutch - const Locale("no", ""), // Norwegian - const Locale("pl", ""), // Polish - const Locale("pt", ""), // Portuguese - const Locale("pt-BR", ""), - const Locale("ru", ""), // Russian - const Locale("sv", ""), // Swedish - const Locale("th", ""), // Thai - const Locale("tr", ""), // Turkish - const Locale("vi", ""), // Vietnamese - const Locale("zh-CN", ""), // Chinese - ], - + locale: const Locale("hu"), + supportedLocales: supported_locales, ); } } \ No newline at end of file From 95c3bc5ae57f793c1137c478c773cbc239be9cb8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 13:14:17 +1000 Subject: [PATCH 067/746] Fix delegate issue --- lib/l10n/collect_translations.py | 2 +- lib/main.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index e6ce6f1..fa1cb88 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -105,7 +105,7 @@ def generate_locale_list(locales): lc = locale cc = '' - output.write(f' const Locale("{lc}", "{cc}"), // Translations avilable in app_{locale}.arb\n') + output.write(f' const Locale("{lc}", "{cc}"), // Translations available in app_{locale}.arb\n') output.write("];\n") output.write("") diff --git a/lib/main.dart b/lib/main.dart index f8062e3..9d97ccc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,9 +71,9 @@ class InvenTreeApp extends StatelessWidget { localizationsDelegates: [ I18N.delegate, GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], - locale: const Locale("hu"), supportedLocales: supported_locales, ); } From 69bbc3bec30a8fd16cf45dbb88d1844eec70180b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 13:20:37 +1000 Subject: [PATCH 068/746] remove const keyword --- lib/l10n/collect_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index fa1cb88..4f0182a 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -105,7 +105,7 @@ def generate_locale_list(locales): lc = locale cc = '' - output.write(f' const Locale("{lc}", "{cc}"), // Translations available in app_{locale}.arb\n') + output.write(f' Locale("{lc}", "{cc}"), // Translations available in app_{locale}.arb\n') output.write("];\n") output.write("") From 501971681e4d7de6b22cb222bb52d62d180c6eeb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 2 May 2022 13:28:47 +1000 Subject: [PATCH 069/746] Adds missing step from android CI build --- .github/workflows/android.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 32aed76..a9d4940 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -32,6 +32,10 @@ jobs: uses: gradle/gradle-build-action@v2 with: gradle-version: 6.1.1 + - name: Collect Translation Files + run: | + cd lib/l10n + python3 collect_translations.py - name: Build for Android run: | flutter pub get From 15dba61300d307ae132ac2d58dbc808f5c924e64 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 3 May 2022 00:18:02 +1000 Subject: [PATCH 070/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index b378a02..b4624dc 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -1,5 +1,13 @@ { "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, "about": "Névjegy", "@about": {}, "accountDetails": "Felhasználó adatok", @@ -292,6 +300,8 @@ "@locationNotSet": {}, "locationUpdated": "Készlet hely adatai frissítve", "@locationUpdated": {}, + "link": "Link", + "@link": {}, "lost": "Elveszett", "@lost": {}, "manufacturers": "Gyártók", From 1e1ed96d646a5bb0fd48c5e779cc70ca6b7f3abe Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 3 May 2022 09:38:45 +1000 Subject: [PATCH 071/746] 0.6.2 - Update release notes --- assets/release_notes.md | 5 +++++ pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 77b02c4..32b1149 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.6.2 - April 2022 +--- + +- Fixes issues related to locale support (for specific locales) + ### 0.6.1 - April 2022 --- diff --git a/pubspec.yaml b/pubspec.yaml index 74200e9..0c003ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.6.1+39 +version: 0.6.2+40 environment: sdk: ">=2.16.0 <3.0.0" From 102b4e021ba1c03ed3c7374daacb4e1fba0c69d7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 10:02:50 +1000 Subject: [PATCH 072/746] Change home screen from "grid" display to "list" display --- assets/release_notes.md | 5 +++ lib/widget/home.dart | 70 +++++++++++++++-------------------------- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 32b1149..9a31282 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.7.0 - +--- + +- Refactor home screen display + ### 0.6.2 - April 2022 --- diff --git a/lib/widget/home.dart b/lib/widget/home.dart index cea5773..20349f7 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -41,11 +41,11 @@ class _InvenTreeHomePageState extends State { } - bool homeShowPo = true; - bool homeShowSubscribed = true; - bool homeShowManufacturers = true; - bool homeShowCustomers = true; - bool homeShowSuppliers = true; + bool homeShowPo = false; + bool homeShowSubscribed = false; + bool homeShowManufacturers = false; + bool homeShowCustomers = false; + bool homeShowSuppliers = false; final GlobalKey<_InvenTreeHomePageState> _homeKey = GlobalKey<_InvenTreeHomePageState>(); @@ -169,7 +169,7 @@ class _InvenTreeHomePageState extends State { } - Widget _iconButton(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = ""}) { + Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = ""}) { bool connected = InvenTreeAPI().isConnected(); @@ -182,27 +182,13 @@ class _InvenTreeHomePageState extends State { return GestureDetector( child: Card( margin: EdgeInsets.symmetric( - vertical: 12, + vertical: 5, horizontal: 12 ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FaIcon( - icon, - color: connected && allowed ? COLOR_CLICK : Colors.grey, - ), - Divider( - height: 15, - thickness: 0, - color: Colors.transparent, - ), - Text( - label, - textAlign: TextAlign.center, - ), - ] - ) + child: ListTile( + leading: FaIcon(icon, color: connected && allowed ? COLOR_CLICK : Colors.grey), + title: Text(label), + ), ), onTap: () { @@ -224,12 +210,12 @@ class _InvenTreeHomePageState extends State { ); } - List getGridTiles(BuildContext context) { + List getListTiles(BuildContext context) { List tiles = []; // Barcode scanner - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().scanBarcode, Icons.qr_code_scanner, @@ -239,7 +225,7 @@ class _InvenTreeHomePageState extends State { )); // Search widget - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().search, FontAwesomeIcons.search, @@ -249,7 +235,7 @@ class _InvenTreeHomePageState extends State { )); // Parts - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().parts, FontAwesomeIcons.shapes, @@ -260,7 +246,7 @@ class _InvenTreeHomePageState extends State { // Starred parts if (homeShowSubscribed) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().partsStarred, FontAwesomeIcons.bell, @@ -271,7 +257,7 @@ class _InvenTreeHomePageState extends State { } // Stock button - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().stock, FontAwesomeIcons.boxes, @@ -282,7 +268,7 @@ class _InvenTreeHomePageState extends State { // Purchase orderes if (homeShowPo) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().purchaseOrders, FontAwesomeIcons.shoppingCart, @@ -294,7 +280,7 @@ class _InvenTreeHomePageState extends State { // Suppliers if (homeShowSuppliers) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().suppliers, FontAwesomeIcons.building, @@ -306,7 +292,7 @@ class _InvenTreeHomePageState extends State { // Manufacturers if (homeShowManufacturers) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().manufacturers, FontAwesomeIcons.industry, @@ -318,7 +304,7 @@ class _InvenTreeHomePageState extends State { // Customers if (homeShowCustomers) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().customers, FontAwesomeIcons.userTie, @@ -329,7 +315,7 @@ class _InvenTreeHomePageState extends State { } // Settings - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().settings, FontAwesomeIcons.cogs, @@ -360,15 +346,9 @@ class _InvenTreeHomePageState extends State { ), drawer: InvenTreeDrawer(context), body: ListView( - children: [ - GridView.extent( - maxCrossAxisExtent: 140, - shrinkWrap: true, - physics: ClampingScrollPhysics(), - children: getGridTiles(context), - ), - ], - ), + scrollDirection: Axis.vertical, + children: getListTiles(context), + ) ); } } From 3fa68ec6da9a57f52eda633d4d3be2cf2f3f4540 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 10:27:04 +1000 Subject: [PATCH 073/746] The "search" window is now a tab on the main screen --- lib/api.dart | 3 ++ lib/l10n/app_en.arb | 6 +++ lib/widget/category_display.dart | 1 - lib/widget/home.dart | 84 ++++++++++++++++++++++---------- lib/widget/search.dart | 4 +- 5 files changed, 70 insertions(+), 28 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 71af9cb..9c2674b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -230,6 +230,9 @@ class InvenTreeAPI { int get apiVersion => _apiVersion; + // Notification support requires API v25 or newer + bool get supportsNotifications => isConnected() && apiVersion >= 25; + // Are plugins enabled on the server? bool _pluginsEnabled = false; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index dc95339..cc6b279 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -308,6 +308,9 @@ "description": "history" }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", "@homeScreen": {}, @@ -461,6 +464,9 @@ "description": "Notes" }, + "notifications": "Notifications", + "@notifications": {}, + "noResponse": "No Response from Server", "@noResponse": {}, diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 8cd5081..2ce7e02 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -174,7 +174,6 @@ class _CategoryDisplayState extends RefreshableState { icon: FaIcon(FontAwesomeIcons.shapes), label: L10().parts, ), - // TODO - Add the "actions" item back in BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.wrench), label: L10().actions diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 20349f7..f8c4c6d 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -41,6 +41,9 @@ class _InvenTreeHomePageState extends State { } + // Index of bottom navigation bar + int _tabIndex = 0; + bool homeShowPo = false; bool homeShowSubscribed = false; bool homeShowManufacturers = false; @@ -52,17 +55,6 @@ class _InvenTreeHomePageState extends State { // Selected user profile UserProfile? _profile; - void _search(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SearchWidget() - ) - ); - - } void _scan(BuildContext context) { if (!InvenTreeAPI().checkConnection(context)) return; @@ -224,16 +216,6 @@ class _InvenTreeHomePageState extends State { } )); - // Search widget - tiles.add(_listTile( - context, - L10().search, - FontAwesomeIcons.search, - callback: () { - _search(context); - } - )); - // Parts tiles.add(_listTile( context, @@ -327,6 +309,52 @@ class _InvenTreeHomePageState extends State { return tiles; } + /* + * Return the main body widget for display. + * This depends on the current value of _tabIndex + */ + Widget getBody(BuildContext context) { + switch (_tabIndex) { + case 1: // Search widget + return SearchWidget(); + case 2: // Notification widget + case 0: // Home widget + default: + return ListView( + scrollDirection: Axis.vertical, + children: getListTiles(context), + ); + } + } + + /* + * Construct the bottom navigation bar + */ + List getNavBarItems(BuildContext context) { + + List items = [ + BottomNavigationBarItem( + icon: FaIcon(FontAwesomeIcons.home), + label: L10().home, + ), + BottomNavigationBarItem( + icon: FaIcon(FontAwesomeIcons.search), + label: L10().search, + ), + ]; + + if (InvenTreeAPI().supportsNotifications) { + items.add( + BottomNavigationBarItem( + icon: FaIcon(FontAwesomeIcons.bell), + label: L10().notifications, + ) + ); + } + + return items; + } + @override Widget build(BuildContext context) { @@ -345,10 +373,16 @@ class _InvenTreeHomePageState extends State { ], ), drawer: InvenTreeDrawer(context), - body: ListView( - scrollDirection: Axis.vertical, - children: getListTiles(context), - ) + body: getBody(context), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _tabIndex, + onTap: (int index) { + setState(() { + _tabIndex = index; + }); + }, + items: getNavBarItems(context), + ), ); } } diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 77258d4..d0fadae 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -26,7 +26,7 @@ class SearchWidget extends StatefulWidget { } -class _SearchDisplayState extends RefreshableState { +class _SearchDisplayState extends State { @override String getAppBarTitle(BuildContext context) => L10().search; @@ -333,7 +333,7 @@ class _SearchDisplayState extends RefreshableState { } @override - Widget getBody(BuildContext context) { + Widget build(BuildContext context) { return Center( child: ListView( children: ListTile.divideTiles( From b6a5af08d8ff0ec37669504b0c556d13cf779a7a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 10:29:44 +1000 Subject: [PATCH 074/746] Fix title for stock items list --- lib/widget/stock_list.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index b78cdf1..09d0dc3 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -28,7 +28,7 @@ class _StockListState extends RefreshableState { final Map filters; @override - String getAppBarTitle(BuildContext context) => L10().purchaseOrders; + String getAppBarTitle(BuildContext context) => L10().stockItems; @override Widget getBody(BuildContext context) { From a3597c5d617f45a1ebe206136536356cba8e38c3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 10:42:33 +1000 Subject: [PATCH 075/746] Allow search widget to be constructed with or without an app bar --- lib/widget/drawer.dart | 2 +- lib/widget/home.dart | 3 +-- lib/widget/refreshable_state.dart | 14 +++++++++----- lib/widget/search.dart | 23 ++++++++++++++++++++--- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 871b511..85a3025 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -41,7 +41,7 @@ class InvenTreeDrawer extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => SearchWidget() + builder: (context) => SearchWidget(true) ) ); } diff --git a/lib/widget/home.dart b/lib/widget/home.dart index f8c4c6d..04cc0df 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -55,7 +55,6 @@ class _InvenTreeHomePageState extends State { // Selected user profile UserProfile? _profile; - void _scan(BuildContext context) { if (!InvenTreeAPI().checkConnection(context)) return; @@ -316,7 +315,7 @@ class _InvenTreeHomePageState extends State { Widget getBody(BuildContext context) { switch (_tabIndex) { case 1: // Search widget - return SearchWidget(); + return SearchWidget(false); case 2: // Notification widget case 0: // Home widget default: diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index fe318ca..3518569 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -80,6 +80,14 @@ abstract class RefreshableState extends State { return null; } + AppBar? buildAppBar(BuildContext context) { + return AppBar( + title: Text(getAppBarTitle(context)), + actions: getAppBarActions(context), + leading: backButton(context, refreshableKey), + ); + } + @override Widget build(BuildContext context) { @@ -88,11 +96,7 @@ abstract class RefreshableState extends State { return Scaffold( key: refreshableKey, - appBar: AppBar( - title: Text(getAppBarTitle(context)), - actions: getAppBarActions(context), - leading: backButton(context, refreshableKey), - ), + appBar: buildAppBar(context), drawer: getDrawer(context), floatingActionButton: getFab(context), body: Builder( diff --git a/lib/widget/search.dart b/lib/widget/search.dart index d0fadae..0705ea5 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -21,16 +21,33 @@ import "package:inventree/widget/location_list.dart"; // Widget for performing database-wide search class SearchWidget extends StatefulWidget { + SearchWidget(this.hasAppbar); + + final bool hasAppbar; + @override - _SearchDisplayState createState() => _SearchDisplayState(); + _SearchDisplayState createState() => _SearchDisplayState(hasAppbar); } -class _SearchDisplayState extends State { +class _SearchDisplayState extends RefreshableState { + + _SearchDisplayState(this.hasAppBar) : super(); + + final bool hasAppBar; @override String getAppBarTitle(BuildContext context) => L10().search; + @override + AppBar? buildAppBar(BuildContext context) { + if (hasAppBar) { + return super.buildAppBar(context); + } else { + return null; + } + } + final TextEditingController searchController = TextEditingController(); Timer? debounceTimer; @@ -333,7 +350,7 @@ class _SearchDisplayState extends State { } @override - Widget build(BuildContext context) { + Widget getBody(BuildContext context) { return Center( child: ListView( children: ListTile.divideTiles( From b8857f2dbeea7c1a18e3170ca5eec6983d090964 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 10:50:51 +1000 Subject: [PATCH 076/746] Adds skeleton widget for displayign notifications --- lib/widget/home.dart | 16 +++++----- lib/widget/notifications.dart | 57 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 lib/widget/notifications.dart diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 04cc0df..d5e7ebf 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -2,23 +2,24 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/app_settings.dart"; +import "package:inventree/barcode.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/settings/login.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/user_profile.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/barcode.dart"; -import "package:inventree/api.dart"; -import "package:inventree/settings/login.dart"; + import "package:inventree/widget/category_display.dart"; import "package:inventree/widget/company_list.dart"; +import "package:inventree/widget/drawer.dart"; import "package:inventree/widget/location_display.dart"; +import "package:inventree/widget/notifications.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/purchase_order_list.dart"; import "package:inventree/widget/search.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/drawer.dart"; - -import "package:inventree/app_settings.dart"; class InvenTreeHomePage extends StatefulWidget { @@ -317,6 +318,7 @@ class _InvenTreeHomePageState extends State { case 1: // Search widget return SearchWidget(false); case 2: // Notification widget + return NotificationWidget(); case 0: // Home widget default: return ListView( diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart new file mode 100644 index 0000000..9db9147 --- /dev/null +++ b/lib/widget/notifications.dart @@ -0,0 +1,57 @@ + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:inventree/widget/refreshable_state.dart'; + +class NotificationWidget extends StatefulWidget { + + @override + _NotificationState createState() => _NotificationState(); + +} + + +class _NotificationState extends RefreshableState { + + _NotificationState() : super(); + + @override + AppBar? buildAppBar(BuildContext context) { + // No app bar for the notification widget + return null; + } + + @override + Future request (BuildContext context) async { + print("requesting notifications!"); + } + + List renderNotifications(BuildContext context) { + + List tiles = []; + + tiles.add( + ListTile( + title: Text("Not"), + subtitle: Text("subtitle yatyayaya"), + ) + ); + + return tiles; + + } + + @override + Widget getBody(BuildContext context) { + return Center( + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: renderNotifications(context), + ).toList() + ) + ); + } + +} \ No newline at end of file From 6bbae67482b98626b4cdd1d26d018e4646d0ffb7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 11:11:29 +1000 Subject: [PATCH 077/746] Add model for notifications - Display a list of active notifications --- lib/inventree/notification.dart | 31 ++++++++++++++++++++++ lib/l10n/app_en.arb | 3 +++ lib/widget/notifications.dart | 47 ++++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 lib/inventree/notification.dart diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart new file mode 100644 index 0000000..2a09965 --- /dev/null +++ b/lib/inventree/notification.dart @@ -0,0 +1,31 @@ +import "package:inventree/inventree/model.dart"; + +/* + * Class representing a "notification" + */ + +class InvenTreeNotification extends InvenTreeModel { + + InvenTreeNotification() : super(); + + InvenTreeNotification.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeNotification createFromJson(Map json) { + return InvenTreeNotification.fromJson(json); + } + + @override + String get URL => "notifications/"; + + String get message => (jsondata["message"] ?? "") as String; + + DateTime? get creationDate { + if (jsondata.containsKey("creation")) { + return DateTime.tryParse((jsondata["creation"] ?? "") as String); + } else { + return null; + } + } + +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cc6b279..a21ea56 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -467,6 +467,9 @@ "notifications": "Notifications", "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", "@noResponse": {}, diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 9db9147..f86ed08 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -1,8 +1,15 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -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:inventree/l10.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/notification.dart"; +import "package:inventree/widget/refreshable_state.dart"; + class NotificationWidget extends StatefulWidget { @@ -16,6 +23,8 @@ class _NotificationState extends RefreshableState { _NotificationState() : super(); + List notifications = []; + @override AppBar? buildAppBar(BuildContext context) { // No app bar for the notification widget @@ -24,7 +33,14 @@ class _NotificationState extends RefreshableState { @override Future request (BuildContext context) async { - print("requesting notifications!"); + + final results = await InvenTreeNotification().list(); + + for (InvenTreeModel n in results) { + if (n is InvenTreeNotification) { + notifications.add(n); + } + } } List renderNotifications(BuildContext context) { @@ -33,11 +49,30 @@ class _NotificationState extends RefreshableState { tiles.add( ListTile( - title: Text("Not"), - subtitle: Text("subtitle yatyayaya"), + title: Text( + L10().notifications, + ), + subtitle: notifications.isEmpty ? Text(L10().notificationsEmpty) : null, + leading: notifications.isEmpty ? FaIcon(FontAwesomeIcons.bellSlash) : FaIcon(FontAwesomeIcons.bell), + trailing: Text("${notifications.length}"), ) ); + for (var notification in notifications) { + tiles.add( + ListTile( + title: Text(notification.name), + subtitle: Text(notification.message), + trailing: IconButton( + icon: FaIcon(FontAwesomeIcons.bookmark), + onPressed: () async { + + }, + ), + ) + ); + } + return tiles; } From 020f006410651a1dc83200ac6cb280b30b25293c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 11:21:52 +1000 Subject: [PATCH 078/746] Adds ability to "dismiss" a notification --- lib/inventree/notification.dart | 20 ++++++++++++++++++++ lib/inventree/stock.dart | 4 ++-- lib/widget/notifications.dart | 12 +++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart index 2a09965..dae7e67 100644 --- a/lib/inventree/notification.dart +++ b/lib/inventree/notification.dart @@ -18,6 +18,15 @@ class InvenTreeNotification extends InvenTreeModel { @override String get URL => "notifications/"; + @override + Map defaultListFilters() { + + // By default, only return 'unread' notifications + return { + "read": "false", + }; + } + String get message => (jsondata["message"] ?? "") as String; DateTime? get creationDate { @@ -28,4 +37,15 @@ class InvenTreeNotification extends InvenTreeModel { } } + /* + * Dismiss this notification (mark as read) + */ + Future dismiss() async { + + final response = await api.post( + "${url}read/", + ); + + } + } \ No newline at end of file diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 45808d2..3dc4f2b 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -533,7 +533,7 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; // Note: Format of adjustment API was updated in API v14 - if (InvenTreeAPI().supportModernStockTransactions()) { + if (api.supportModernStockTransactions()) { // Modern (> 14) API data = { "items": [ @@ -560,7 +560,7 @@ class InvenTreeStockItem extends InvenTreeModel { } // Expected API return code depends on server API version - final int expected_response = InvenTreeAPI().supportModernStockTransactions() ? 201 : 200; + final int expected_response = api.supportModernStockTransactions() ? 201 : 200; var response = await api.post( endpoint, diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index f86ed08..a37d9d3 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -36,6 +36,8 @@ class _NotificationState extends RefreshableState { final results = await InvenTreeNotification().list(); + notifications.clear(); + for (InvenTreeModel n in results) { if (n is InvenTreeNotification) { notifications.add(n); @@ -43,6 +45,14 @@ class _NotificationState extends RefreshableState { } } + Future dismissNotification(BuildContext context, InvenTreeNotification notification) async { + + await notification.dismiss(); + + refresh(context); + + } + List renderNotifications(BuildContext context) { List tiles = []; @@ -66,7 +76,7 @@ class _NotificationState extends RefreshableState { trailing: IconButton( icon: FaIcon(FontAwesomeIcons.bookmark), onPressed: () async { - + dismissNotification(context, notification); }, ), ) From a36a251f239c282d35099128d8c995b81c88201f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 11:26:47 +1000 Subject: [PATCH 079/746] Remove debug message --- lib/widget/back.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/widget/back.dart b/lib/widget/back.dart index 04f0325..9797e4b 100644 --- a/lib/widget/back.dart +++ b/lib/widget/back.dart @@ -12,7 +12,6 @@ Widget backButton(BuildContext context, GlobalKey key) { onLongPress: () { // Display the menu key.currentState!.openDrawer(); - print("hello?"); }, child: IconButton( icon: BackButtonIcon(), From 6533cc4af60fc09241ea53fbe6f34e03f5db47e7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 11:41:53 +1000 Subject: [PATCH 080/746] Display badge showing current number of unread notifications --- lib/api.dart | 1 + lib/widget/home.dart | 60 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 9c2674b..ee8a613 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -431,6 +431,7 @@ class InvenTreeAPI { // Return the received token _token = (data["token"] ?? "") as String; + print("Received token - $_token"); // Request user role information (async) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index d5e7ebf..f9c3c25 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -11,6 +13,9 @@ import "package:inventree/settings/login.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/user_profile.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/notification.dart"; + import "package:inventree/widget/category_display.dart"; import "package:inventree/widget/company_list.dart"; import "package:inventree/widget/drawer.dart"; @@ -33,18 +38,29 @@ class InvenTreeHomePage extends StatefulWidget { class _InvenTreeHomePageState extends State { _InvenTreeHomePageState() : super() { - // Load display settings _loadSettings(); // Initially load the profile and attempt server connection _loadProfile(); + _refreshNotifications(); + + // Refresh notifications every ~30 seconds + Timer.periodic( + Duration( + milliseconds: 30000, + ), (timer) { + _refreshNotifications(); + }); } // Index of bottom navigation bar int _tabIndex = 0; + // Number of outstanding notifications + int _notificationCounter = 0; + bool homeShowPo = false; bool homeShowSubscribed = false; bool homeShowManufacturers = false; @@ -160,6 +176,18 @@ class _InvenTreeHomePageState extends State { setState(() {}); } + /* + * Refresh the number of active notifications for this user + */ + Future _refreshNotifications() async { + + final notifications = await InvenTreeNotification().list(); + + setState(() { + _notificationCounter = notifications.length; + }); + } + Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = ""}) { @@ -347,7 +375,33 @@ class _InvenTreeHomePageState extends State { if (InvenTreeAPI().supportsNotifications) { items.add( BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.bell), + icon: _notificationCounter == 0 ? FaIcon(FontAwesomeIcons.bell) : Stack( + children: [ + FaIcon(FontAwesomeIcons.bell), + new Positioned( + right: 0, + child: new Container( + padding: EdgeInsets.all(2), + decoration: new BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(20), + ), + constraints: BoxConstraints( + minWidth: 12, + minHeight: 12, + ), + child: new Text( + "${_notificationCounter}", + style: new TextStyle( + color: Colors.white, + fontSize: 9, + ), + textAlign: TextAlign.center, + ), + ), + ) + ], + ), label: L10().notifications, ) ); @@ -381,6 +435,8 @@ class _InvenTreeHomePageState extends State { setState(() { _tabIndex = index; }); + + _refreshNotifications(); }, items: getNavBarItems(context), ), From 7ef7096e2654958cc4a14479e8816790a44359f1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 11:53:11 +1000 Subject: [PATCH 081/746] Updates to search controller --- lib/l10n/app_en.arb | 3 +++ lib/widget/home.dart | 10 +++++----- lib/widget/notifications.dart | 2 -- lib/widget/search.dart | 9 ++++++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a21ea56..cf9a275 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -640,6 +640,9 @@ "quantityPositive": "Quantity must be positive", "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", "@queryNoResults": {}, diff --git a/lib/widget/home.dart b/lib/widget/home.dart index f9c3c25..d526339 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -378,11 +378,11 @@ class _InvenTreeHomePageState extends State { icon: _notificationCounter == 0 ? FaIcon(FontAwesomeIcons.bell) : Stack( children: [ FaIcon(FontAwesomeIcons.bell), - new Positioned( + Positioned( right: 0, - child: new Container( + child: Container( padding: EdgeInsets.all(2), - decoration: new BoxDecoration( + decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(20), ), @@ -390,9 +390,9 @@ class _InvenTreeHomePageState extends State { minWidth: 12, minHeight: 12, ), - child: new Text( + child: Text( "${_notificationCounter}", - style: new TextStyle( + style: TextStyle( color: Colors.white, fontSize: 9, ), diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index a37d9d3..8c03343 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -1,6 +1,4 @@ - -import "package:flutter/cupertino.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 0705ea5..2d21fc6 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -21,7 +21,7 @@ import "package:inventree/widget/location_list.dart"; // Widget for performing database-wide search class SearchWidget extends StatefulWidget { - SearchWidget(this.hasAppbar); + const SearchWidget(this.hasAppbar); final bool hasAppbar; @@ -172,12 +172,15 @@ class _SearchDisplayState extends RefreshableState { child: ListTile( title: TextField( readOnly: false, + decoration: InputDecoration( + helperText: L10().queryEmpty, + ), controller: searchController, onChanged: (String text) { onSearchTextChanged(text); }, ), - leading: IconButton( + trailing: IconButton( icon: FaIcon(FontAwesomeIcons.backspace, color: Colors.red), onPressed: () { searchController.clear(); @@ -332,7 +335,7 @@ class _SearchDisplayState extends RefreshableState { ); } - if (results.isEmpty) { + if (results.isEmpty && searchController.text.isNotEmpty) { tiles.add( ListTile( title: Text(L10().queryNoResults), From 407250c33640a10e141e8306db293deb1bad8432 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 12:17:55 +1000 Subject: [PATCH 082/746] Further linting fixes --- lib/inventree/notification.dart | 2 +- lib/widget/home.dart | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart index dae7e67..c6b7404 100644 --- a/lib/inventree/notification.dart +++ b/lib/inventree/notification.dart @@ -42,7 +42,7 @@ class InvenTreeNotification extends InvenTreeModel { */ Future dismiss() async { - final response = await api.post( + await api.post( "${url}read/", ); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index d526339..712b4e2 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -13,7 +13,6 @@ import "package:inventree/settings/login.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/user_profile.dart"; -import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/notification.dart"; import "package:inventree/widget/category_display.dart"; From 23706a19bc5c51e27dc539626f90cbaa80035fa9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 12:48:51 +1000 Subject: [PATCH 083/746] Update release notes --- assets/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 9a31282..b9fb849 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,7 @@ --- - Refactor home screen display +- Display unread notifications on home screen ### 0.6.2 - April 2022 --- From 7ff61add76f35f6f860adada167da9d22615da1e Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:04 +1000 Subject: [PATCH 084/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 81610da..82ccc61 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -194,8 +194,8 @@ "@history": { "description": "history" }, - "homeScreen": "Ecran d'accueil", "@homeScreen": {}, + "homeScreen": "Ecran d'accueil", "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", "@homeScreenSettings": {}, "homeShowPo": "Afficher les commandes d'achat", From 943669e67fd04dcfeedf479bb975b48cbbbfa9a8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:10 +1000 Subject: [PATCH 085/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index d9aaa29..8008b52 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -206,8 +206,8 @@ "@history": { "description": "history" }, - "homeScreen": "Ana Ekran", "@homeScreen": {}, + "homeScreen": "Ana Ekran", "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", "@homeScreenSettings": {}, "homeShowPo": "Satın Alma Siparişlerini Göster", From 4e7930f8df28c6216b2c4f27f0761ebf6fce08f5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:12 +1000 Subject: [PATCH 086/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 7a403f3..d499412 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -202,8 +202,8 @@ "@history": { "description": "history" }, - "homeScreen": "Ekran główny", "@homeScreen": {}, + "homeScreen": "Ekran główny", "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", "@homeScreenSettings": {}, "homeShowPo": "Pokaż zamówienia zakupu", From 27167f93b38a3f24566c2357ad29fc95afd33e5f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:14 +1000 Subject: [PATCH 087/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 306 ++++++++++++++++++++++++++++++++++- 1 file changed, 305 insertions(+), 1 deletion(-) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 36d80aa..b026218 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -1,5 +1,309 @@ { "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Over", + "@about": {}, + "accountDetails": "Accountgegevens", + "@accountDetails": {}, + "actions": "Acties", + "@actions": { + "description": "" + }, + "actionsNone": "Geen acties beschikbaar", + "@actionsNone": {}, + "add": "Toevoegen", + "@add": { + "description": "add" + }, + "addStock": "Voorraad toevoegen", + "@addStock": { + "description": "add stock" + }, + "address": "Adres", + "@address": {}, + "appAbout": "Over InvenTree", + "@appAbout": {}, + "appCredits": "Extra app credits", + "@appCredits": {}, + "appDetails": "App details", + "@appDetails": {}, + "appReleaseNotes": "App release notities weergeven", + "@appReleaseNotes": {}, + "appSettings": "App Instellingen", + "@appSettings": {}, + "appSettingsDetails": "Configureer InvenTree app instellingen", + "@appSettingsDetails": {}, + "attachments": "Bijlagen", + "@attachments": {}, + "attachImage": "Voeg afbeelding toe", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Geen bijlagen gevonden", + "@attachmentNone": {}, + "attachmentNonePartDetail": "Geen bijlagen voor dit onderdeel gevonden", + "@attachmentNonePartDetail": {}, + "attachmentSelect": "Bijlage selecteren", + "@attachmentSelect": {}, + "attention": "Let op", + "@attention": {}, + "availableStock": "Beschikbare Voorraad", + "@availableStock": {}, + "barcodeAssign": "Streepjescode toewijzen", + "@barcodeAssign": {}, + "barcodeAssigned": "Streepjescode toegewezen", + "@barcodeAssigned": {}, + "barcodeError": "Streepjescode scanfout", + "@barcodeError": {}, + "barcodeInUse": "Streepjescode al toegewezen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Streepjescode hash gegevens ontbreken in reactie", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Geen overeenkomst voor streepjescode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Streepjescode niet toegewezen", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scan om streepjescode toe te wijzen", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scan een InvenTree streepjescode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan voorraadartikelen naar locatie", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan voorraadlocatie", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Gescand naar locatie", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artikel niet gescand in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan voorraadartikel", + "@barcodeScanItem": {}, + "barcodeTones": "Streepjescodetonen", + "@barcodeTones": {}, + "barcodeUnassign": "Streepjescodetoewijzing ongedaan maken", + "@barcodeUnassign": {}, + "barcodeUnknown": "Streepjescode wordt niet herkend", + "@barcodeUnknown": {}, + "batchCode": "Batchcode", + "@batchCode": {}, + "billOfMaterials": "Stuklijst", + "@billOfMaterials": {}, + "bom": "Stuklijst", + "@bom": {}, + "build": "Productie", + "@build": {}, + "building": "Produceren", + "@building": {}, + "cancel": "Annuleer", + "@cancel": { + "description": "Cancel" + }, + "category": "Categorie", + "@category": {}, + "categoryCreate": "Nieuwe Categorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Creëer nieuw onderdeelcategorie", + "@categoryCreateDetail": {}, + "categoryUpdated": "Onderdeelcategorie bijgewerkt", + "@categoryUpdated": {}, + "company": "Bedrijf", + "@company": {}, + "companyEdit": "Bedrijf bewerken", + "@companyEdit": {}, + "companyNoResults": "Geen enkel bedrijf voldoet aan de zoekopdracht", + "@companyNoResults": {}, + "companyUpdated": "Bedrijfsinstellingen bijgewerkt", + "@companyUpdated": {}, + "companies": "Bedrijven", + "@companies": {}, + "configureServer": "Configureer server instellingen", + "@configureServer": {}, + "connectionRefused": "Verbinding geweigerd", + "@connectionRefused": {}, + "count": "Tellen", + "@count": { + "description": "Count" + }, + "countStock": "Voorraad tellen", + "@countStock": { + "description": "Count Stock" + }, + "customers": "Klanten", + "@customers": {}, + "damaged": "Beschadigd", + "@damaged": {}, + "delete": "Verwijderen", + "@delete": {}, + "deletePart": "Onderdeel Verwijderen", + "@deletePart": {}, + "deletePartDetail": "Verwijder dit onderdeel uit de database", + "@deletePartDetail": {}, + "description": "Omschrijving", + "@description": {}, + "destroyed": "Vernietigd", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentatie", + "@documentation": {}, + "downloading": "Bestand wordt gedownload", + "@downloading": {}, + "downloadError": "Fout bij downloaden", + "@downloadError": {}, + "edit": "Bewerken", + "@edit": { + "description": "edit" + }, + "editCategory": "Bewerk Categorie", + "@editCategory": {}, + "editLocation": "Bewerk Locatie", + "@editLocation": {}, + "editNotes": "Bewerk Notities", + "@editNotes": {}, + "editPart": "Bewerk onderdeel", + "@editPart": { + "description": "edit part" + }, + "editItem": "Bewerk Voorraadartikel", + "@editItem": {}, + "enterPassword": "Wachtwoord invoeren", + "@enterPassword": {}, + "enterUsername": "Gebruikersnaam invoeren", + "@enterUsername": {}, + "error": "Fout", + "@error": { + "description": "Error" + }, + "errorCreate": "Fout bij aanmaken database invoer", + "@errorCreate": {}, + "errorDelete": "Fout bij verwijderen database invoer", + "@errorDelete": {}, + "errorDetails": "Foutdetails", + "@errorDetails": {}, + "errorFetch": "Fout bij het ophalen van gegevens van server", + "@errorFetch": {}, + "errorReporting": "Fout bij Rapportage", + "@errorReporting": {}, + "errorReportUpload": "Foutrapporten Uploaden", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonieme foutrapporten en crashlogs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fout bij indienen feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback verzonden", + "@feedbackSuccess": {}, + "formatExceptionJson": "JSON gegevensformaat exceptie", + "@formatExceptionJson": {}, + "history": "Geschiedenis", + "@history": { + "description": "history" + }, + "@homeScreen": {}, + "homeScreen": "Startscherm", + "homeScreenSettings": "Configureer Startscherminstellingen", + "@homeScreenSettings": {}, + "homeShowPo": "Inkooporders tonen", + "@homeShowPo": {}, + "homeShowSubscribed": "Geabonneerde Onderdelen", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Geabonneerde Onderdelen weergeven op startscherm", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Leveranciers weergeven", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Leveranciersknop weergeven op startscherm", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Fabrikant weergeven", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Fabrikantenknop op startscherm weergeven", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Klanten weergeven", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Klantenknop weergeven op startscherm", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Uploaden van afbeelding is mislukt", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Afbeelding geüpload", + "@imageUploadSuccess": {}, + "inactive": "Inactief", + "@inactive": {}, + "inactiveDetail": "Dit onderdeel is gemarkeerd als inactief", + "@inactiveDetail": {}, + "includeSubcategories": "Inclusief subcategorieën", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Toon subcategorieonderdelen in lijstweergave", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclusief Sublocaties", + "@includeSublocations": {}, + "includeSublocationsDetail": "Toon sublocatieonderdelen in lijstweergave", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Onvolledige profieldetails", + "@incompleteDetails": {}, + "internalPartNumber": "Intern Onderdeelnummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Productie", + "@inProduction": {}, + "inProductionDetail": "Dit voorraadartikel is in productie", + "@inProductionDetail": {}, + "invalidHost": "Ongeldige hostnaam", + "@invalidHost": {}, + "invalidHostDetails": "Opgegeven hostnaam is ongeldig", + "@invalidHostDetails": {}, + "invalidPart": "Ongeldig Onderdeel", + "@invalidPart": {}, + "invalidPartCategory": "Ongeldig Onderdeelcategorie", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ongeldige Voorraadlocatie", + "@invalidStockLocation": {}, + "invalidStockItem": "Ongeldig Voorraadartikel", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", + "@invalidUsernamePassword": {}, + "issueDate": "Uitgiftedatum", + "@issueDate": {}, + "itemInLocation": "Artikel al op locatie", + "@itemInLocation": {}, + "keywords": "Trefwoorden", + "@keywords": {}, + "lastStocktake": "Laatste Voorraadcontrole", + "@lastStocktake": {}, + "lastUpdated": "Laatst Bijgewerkt", + "@lastUpdated": {}, + "lineItem": "Regelartikel", + "@lineItem": {}, + "lineItems": "Regelartikelen", + "@lineItems": {}, + "locationCreate": "Nieuwe Locatie", + "@locationCreate": {}, + "locationCreateDetail": "Creëer nieuwe voorraadlocatie", + "@locationCreateDetail": {}, + "locationNotSet": "Geen locatie opgegeven", + "@locationNotSet": {}, + "locationUpdated": "Voorraadlocatie bijgewerkt", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "profileNotSelected": "Geen Profiel Geselecteerd", + "@profileNotSelected": {}, + "profileSelect": "Selecteer InvenTree Server", + "@profileSelect": {}, + "scanBarcode": "Streepjescode Scannen", + "@scanBarcode": {}, + "soundOnBarcodeAction": "Speel hoorbare toon bij streepjescode actie", + "@soundOnBarcodeAction": {} } \ No newline at end of file From 40730af102daac6abcc1ef4003494ee8e714716f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:16 +1000 Subject: [PATCH 088/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 6c5a25e..2eb648e 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -198,8 +198,8 @@ "@history": { "description": "history" }, - "homeScreen": "ホーム画面", "@homeScreen": {}, + "homeScreen": "ホーム画面", "homeScreenSettings": "ホーム画面の設定", "@homeScreenSettings": {}, "homeShowPo": "注文書を表示", From 0c025289add543e29e193a8f3fe42f808107b8ca Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:18 +1000 Subject: [PATCH 089/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index b4624dc..c53da9c 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -214,8 +214,8 @@ "@history": { "description": "history" }, - "homeScreen": "Főképernyő", "@homeScreen": {}, + "homeScreen": "Főképernyő", "homeScreenSettings": "Főképernyő beállítások konfigurálása", "@homeScreenSettings": {}, "homeShowPo": "Beszerzési rendelések megjelenítése", From 04ca7cc783d524914f27a8db505365f1b1b2693b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 May 2022 15:28:20 +1000 Subject: [PATCH 090/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index a4e0e6f..30cfeff 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -200,8 +200,8 @@ "@history": { "description": "history" }, - "homeScreen": "Startseite", "@homeScreen": {}, + "homeScreen": "Startseite", "homeScreenSettings": "Einstellungen für Startseite konfigurieren", "@homeScreenSettings": {}, "homeShowPo": "Bestellungen anzeigen", From 52b3873cd75752d6fcdcbda21e7ec4b2d048954e Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 May 2022 03:26:48 +1000 Subject: [PATCH 091/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index c53da9c..bc91891 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -214,6 +214,7 @@ "@history": { "description": "history" }, + "home": "Főoldal", "@homeScreen": {}, "homeScreen": "Főképernyő", "homeScreenSettings": "Főképernyő beállítások konfigurálása", @@ -316,6 +317,10 @@ "@notes": { "description": "Notes" }, + "notifications": "Értesítések", + "@notifications": {}, + "notificationsEmpty": "Nincsenek olvasatlan értesítések", + "@notificationsEmpty": {}, "noResponse": "Nincs válasz a kiszolgálótól", "@noResponse": {}, "noResults": "Nincs találat", @@ -432,6 +437,8 @@ "@quantityInvalid": {}, "quantityPositive": "Mennyiség pozitív kell legyen", "@quantityPositive": {}, + "queryEmpty": "Add meg a keresési lekérdezést", + "@queryEmpty": {}, "queryNoResults": "Nincs találat", "@queryNoResults": {}, "received": "Beérkezett", From 0140ffd96ff3b02af2bee81a3a7cbd83d47fb5f0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 7 May 2022 15:25:26 +1000 Subject: [PATCH 092/746] Fix duplicate display of units --- assets/release_notes.md | 1 + lib/inventree/part.dart | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index b9fb849..508da4b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Refactor home screen display - Display unread notifications on home screen +- Fixes duplicated display of units when showing stock quantity ### 0.6.2 - April 2022 --- diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 723a7e8..7467012 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -261,10 +261,6 @@ class InvenTreePart extends InvenTreeModel { String q = simpleNumberString(inStock); - if (units.isNotEmpty) { - q += " ${units}"; - } - return q; } @@ -282,10 +278,6 @@ class InvenTreePart extends InvenTreeModel { String get unallocatedStockString { String q = simpleNumberString(unallocatedStock); - if (units.isNotEmpty) { - q += " ${units}"; - } - return q; } From 347d2175be26e6d1ab1f5cd7ca1b68a6312d7477 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 20:37:57 +1000 Subject: [PATCH 093/746] Display a "launch" screen if server is not connected --- lib/api.dart | 4 ++++ lib/l10n/app_en.arb | 3 +++ lib/widget/home.dart | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index ee8a613..aa9b73b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -193,6 +193,7 @@ class InvenTreeAPI { UserProfile? profile; + // Available user roles (permissions) are loaded when connecting to the server Map roles = {}; // Authentication token (initially empty, must be requested) @@ -454,6 +455,9 @@ class InvenTreeAPI { profile = null; } + /* + * Public facing connection function + */ Future connectToServer() async { // Ensure server is first disconnected diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cf9a275..56371b4 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -608,6 +608,9 @@ "profileSelect": "Select InvenTree Server", "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", "@profileTapToCreate": {}, diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 712b4e2..eefd9c6 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -229,6 +229,9 @@ class _InvenTreeHomePageState extends State { ); } + /* + * Constructs a list of tiles for the main screen + */ List getListTiles(BuildContext context) { List tiles = []; @@ -336,11 +339,43 @@ class _InvenTreeHomePageState extends State { return tiles; } + /* + * If the app is not connected to an InvenTree server, + * display a connection status widget + */ + Widget _connectionStatusWidget(BuildContext context) { + return Center( + child: Column( + children: [ + Image.asset( + "assets/image/icon.png", + color: Colors.white.withOpacity(0.2), + colorBlendMode: BlendMode.modulate, + scale: 0.5, + ), + Spacer(), + ListTile( + title: Text(L10().serverNotConnected), + subtitle: Text(L10().profileSelectOrCreate), + trailing: FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_DANGER), + onTap: _selectProfile, + ) + ] + ), + ); + } + /* * Return the main body widget for display. * This depends on the current value of _tabIndex */ Widget getBody(BuildContext context) { + + if (!InvenTreeAPI().isConnected()) { + return _connectionStatusWidget(context); + } + switch (_tabIndex) { case 1: // Search widget return SearchWidget(false); @@ -412,6 +447,8 @@ class _InvenTreeHomePageState extends State { @override Widget build(BuildContext context) { + var connected = InvenTreeAPI().isConnected(); + return Scaffold( key: _homeKey, appBar: AppBar( @@ -420,7 +457,7 @@ class _InvenTreeHomePageState extends State { IconButton( icon: FaIcon( FontAwesomeIcons.server, - color: InvenTreeAPI().isConnected() ? COLOR_SUCCESS : COLOR_DANGER, + color: connected ? COLOR_SUCCESS : COLOR_DANGER, ), onPressed: _selectProfile, ) @@ -428,7 +465,7 @@ class _InvenTreeHomePageState extends State { ), drawer: InvenTreeDrawer(context), body: getBody(context), - bottomNavigationBar: BottomNavigationBar( + bottomNavigationBar: connected ? BottomNavigationBar( currentIndex: _tabIndex, onTap: (int index) { setState(() { @@ -438,7 +475,7 @@ class _InvenTreeHomePageState extends State { _refreshNotifications(); }, items: getNavBarItems(context), - ), + ) : null, ); } } From 349eca4533044d8b6aad214155df2623164175bd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 20:51:27 +1000 Subject: [PATCH 094/746] Save datetime since last reload --- lib/inventree/model.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index c39da8f..c18882e 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -44,6 +44,9 @@ class InvenTreeModel { // Construct an InvenTreeModel from a JSON data object InvenTreeModel.fromJson(this.jsondata); + // Update whenever the model is loaded from the server + DateTime? lastReload; + // Override the endpoint URL for each subclass String get URL => ""; @@ -287,6 +290,8 @@ class InvenTreeModel { } + lastReload = DateTime.now(); + jsondata = response.asMap(); return true; @@ -357,6 +362,8 @@ class InvenTreeModel { } + lastReload = DateTime.now(); + return createFromJson(response.asMap()); } From da3b668e8c74b5a0a6ebe1672964dbbada0e05cd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 20:53:12 +1000 Subject: [PATCH 095/746] Adds class representing global and user settings --- lib/inventree/model.dart | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index c18882e..b196691 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -572,6 +572,50 @@ class InvenTreePlugin extends InvenTreeModel { } +/* + * Class representing a 'setting' object on the InvenTree server. + * There are two sorts of settings available from the server, via the API: + * - GlobalSetting (applicable to all users) + * - UserSetting (applicable only to the current user) + */ +class InvenTreeGlobalSetting extends InvenTreeModel { + + InvenTreeGlobalSetting() : super(); + + InvenTreeGlobalSetting.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeGlobalSetting.fromJson(json); + } + + @override + String get URL => "settings/global/"; + + String get key => (jsondata["key"] ?? "") as String; + + String get value => (jsondata["value"] ?? "") as String; + + String get type => (jsondata["type"] ?? "") as String; + +} + +class InvenTreeUserSetting extends InvenTreeGlobalSetting { + + InvenTreeUserSetting() : super(); + + InvenTreeUserSetting.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeGlobalSetting.fromJson(json); + } + + @override + String get URL => "settings/user/"; +} + + class InvenTreeAttachment extends InvenTreeModel { // Class representing an "attachment" file InvenTreeAttachment() : super(); From 059b69ce99a41cd89a0dd743ac41620648e8b888 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 21:41:34 +1000 Subject: [PATCH 096/746] Adds code to requeest global setting from server - Settings are individually cached for 5 minutes - For now, use it for the purchase order reference prefix --- lib/api.dart | 36 ++++++++++++++++++++++++++- lib/inventree/model.dart | 14 ++++++++++- lib/widget/paginator.dart | 1 - lib/widget/purchase_order_detail.dart | 8 ++++-- lib/widget/purchase_order_list.dart | 9 +++++-- 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index ee8a613..20cd3b1 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -452,6 +452,10 @@ class InvenTreeAPI { _connecting = false; _token = ""; profile = null; + + // Clear received settings + _globalSettings.clear(); + _userSettings.clear(); } Future connectToServer() async { @@ -488,7 +492,9 @@ class InvenTreeAPI { return _connected; } - + /* + * Request the user roles (permissions) from the InvenTree server + */ Future getUserRoles() async { roles.clear(); @@ -1143,4 +1149,32 @@ class InvenTreeAPI { cacheManager: manager, ); } + + bool get supportsSettings => isConnected() && apiVersion >= 45; + + // Keep a record of which settings we have received from the server + Map _globalSettings = {}; + Map _userSettings = {}; + + Future getGlobalSetting(String key) async { + + if (!supportsSettings) return ""; + + InvenTreeGlobalSetting? setting = _globalSettings[key]; + + if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { + return setting.value; + } + + final response = await InvenTreeGlobalSetting().getModel(key); + + if (response is InvenTreeGlobalSetting) { + response.lastReload = DateTime.now(); + _globalSettings[key] = response; + return response.value; + } else { + return ""; + } + } + } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index b196691..1d13d17 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -47,6 +47,14 @@ class InvenTreeModel { // Update whenever the model is loaded from the server DateTime? lastReload; + bool reloadedWithin(Duration d) { + if (lastReload == null) { + return false; + } else { + return lastReload!.add(d).isAfter(DateTime.now()); + } + } + // Override the endpoint URL for each subclass String get URL => ""; @@ -320,7 +328,7 @@ class InvenTreeModel { } // Return the detail view for the associated pk - Future get(int pk, {Map filters = const {}}) async { + Future getModel(String pk, {Map filters = const {}}) async { var url = path.join(URL, pk.toString()); @@ -367,6 +375,10 @@ class InvenTreeModel { return createFromJson(response.asMap()); } + Future get(int pk, {Map filters = const {}}) async { + return getModel(pk.toString(), filters: filters); + } + Future create(Map data) async { if (data.containsKey("pk")) { diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index c3343a7..f1bfbc8 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -44,7 +44,6 @@ class PaginatedSearchState extends State { Future requestPage(int limit, int offset, Map params) async { - print("Blank request page"); // Default implementation returns null - must be overridden return null; } diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 2a657ec..2748696 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -37,6 +37,8 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; @@ -61,6 +63,9 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { + + _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); + await order.reload(); lines = await order.getLineItems(); @@ -72,7 +77,6 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { @@ -93,7 +97,7 @@ class _PurchaseOrderDetailState extends RefreshableState filters) : super(filters); + // Purchase order prefix + String _poPrefix = ""; + @override Future requestPage(int limit, int offset, Map params) async { + _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); + params["outstanding"] = "true"; final page = await InvenTreePurchaseOrder().listPaginated(limit, offset, filters: params); @@ -72,9 +77,9 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState Date: Mon, 9 May 2022 21:42:46 +1000 Subject: [PATCH 097/746] Adds code for requesting user settings --- lib/api.dart | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/api.dart b/lib/api.dart index 20cd3b1..861ed82 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1157,7 +1157,6 @@ class InvenTreeAPI { Map _userSettings = {}; Future getGlobalSetting(String key) async { - if (!supportsSettings) return ""; InvenTreeGlobalSetting? setting = _globalSettings[key]; @@ -1177,4 +1176,24 @@ class InvenTreeAPI { } } + Future getUserSetting(String key) async { + if (!supportsSettings) return ""; + + InvenTreeUserSetting? setting = _userSettings[key]; + + if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { + return setting.value; + } + + final response = await InvenTreeGlobalSetting().getModel(key); + + if (response is InvenTreeUserSetting) { + response.lastReload = DateTime.now(); + _userSettings[key] = response; + return response.value; + } else { + return ""; + } + } + } From 97ee07741905442a773221ead784d2d05cf4dc04 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 21:46:29 +1000 Subject: [PATCH 098/746] Require API version 46 --- lib/api.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api.dart b/lib/api.dart index 861ed82..04377b9 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1150,7 +1150,7 @@ class InvenTreeAPI { ); } - bool get supportsSettings => isConnected() && apiVersion >= 45; + bool get supportsSettings => isConnected() && apiVersion >= 46; // Keep a record of which settings we have received from the server Map _globalSettings = {}; From 30b4ed96004af5a51b3dcc5281b8c1d2fb711d1d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 May 2022 22:21:26 +1000 Subject: [PATCH 099/746] Update release notes --- assets/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 508da4b..c7dfde3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -7,6 +7,8 @@ - Refactor home screen display - Display unread notifications on home screen - Fixes duplicated display of units when showing stock quantity +- Improve rendering of home screen when server is not connected +- Adds ability to load global and user settings from the server ### 0.6.2 - April 2022 --- From 03c6de8255aed5eb5d01aa7d01b244b1565176c6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 00:15:20 +1000 Subject: [PATCH 100/746] Stock location can now be identified via the app --- assets/release_notes.md | 1 + lib/l10n/app_en.arb | 15 +++++ lib/widget/location_display.dart | 97 +++++++++++++++++++++++++++++--- lib/widget/stock_detail.dart | 4 +- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index c7dfde3..38487ba 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -7,6 +7,7 @@ - Refactor home screen display - Display unread notifications on home screen - Fixes duplicated display of units when showing stock quantity +- Adds ability to locate / identify stock items or locations (requires server plugin) - Improve rendering of home screen when server is not connected - Adds ability to load global and user settings from the server diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 56371b4..7640b15 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -416,6 +416,9 @@ "keywords": "Keywords", "@keywords": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "lastStocktake": "Last Stocktake", "@lastStocktake": {}, @@ -428,6 +431,12 @@ "lineItems": "Line Items", "@lineItems": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", "@locationCreate": {}, @@ -575,6 +584,12 @@ "printLabel": "Print Label", "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "printLabelFailure": "Label printing failed", "@printLabelFailure": {}, diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index cdf1856..17ca010 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -3,6 +3,7 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; +import 'package:inventree/api_form.dart'; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/inventree/stock.dart"; @@ -61,19 +62,99 @@ class _LocationDisplayState extends RefreshableState { ); */ - if ((location != null) && (InvenTreeAPI().checkPermission("stock_location", "change"))) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { _editLocationDialog(context); }, - ) - ); + if (location != null) { + + // Add "locate" button + if (InvenTreeAPI().supportsMixin("locate")) { + actions.add( + IconButton( + icon: FaIcon(FontAwesomeIcons.searchLocation), + tooltip: L10().locateLocation, + onPressed: () async { + _locateStockLocation(context); + }, + ) + ); + } + + // Add "edit" button + if (InvenTreeAPI().checkPermission("stock_location", "change")) { + actions.add( + IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + tooltip: L10().edit, + onPressed: () { _editLocationDialog(context); }, + ) + ); + } } return actions; } + Future _locateStockLocation(BuildContext context) async { + + final _loc = location; + + if (_loc != null) { + + final plugins = InvenTreeAPI().getPlugins(mixin: "locate"); + + if (plugins.isEmpty) { + // TODO: Error message here + return; + } + + String plugin_name = ""; + + if (plugins.length == 1) { + plugin_name = plugins.first.key; + } else { + // User selects which plugin to use + List> plugin_options = []; + + for (var plugin in plugins) { + plugin_options.add({ + "display_name": plugin.humanName, + "value": plugin.key, + }); + } + + Map fields = { + "plugin": { + "label": L10().plugin, + "type": "choice", + "value": plugins.first.key, + "choices": plugin_options, + "required": true, + } + }; + + await launchApiForm( + context, + L10().locateLocation, + "", + fields, + icon: FontAwesomeIcons.searchLocation, + onSuccess: (Map data) async { + plugin_name = (data["plugin"] ?? "") as String; + } + ); + } + + print("plugin: ${plugin_name}"); + + InvenTreeAPI().post( + "/api/locate/", + body: { + "plugin": plugin_name, + "location": "${_loc.pk}", + }, + expectedStatusCode: 200, + ); + } + } + void _editLocationDialog(BuildContext context) { final _loc = location; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 3b400b2..3e2f470 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -217,14 +217,14 @@ class _StockItemDisplayState extends RefreshableState { Map fields = { "label": { - "label": "Label Template", + "label": L10().labelTemplate, "type": "choice", "value": initial_label, "choices": label_options, "required": true, }, "plugin": { - "label": "Printer", + "label": L10().pluginPrinter, "type": "choice", "value": initial_plugin, "choices": plugin_options, From 5ba887d59b430ab13463dc17f2f4954faa4fed69 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 00:28:49 +1000 Subject: [PATCH 101/746] Refactor locate function --- lib/api.dart | 78 ++++++++++++++++++++++++++++++++ lib/l10n/app_en.arb | 3 ++ lib/widget/location_display.dart | 62 +++---------------------- 3 files changed, 88 insertions(+), 55 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index fc900c1..a799235 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -22,6 +22,8 @@ import "package:inventree/user_profile.dart"; import "package:inventree/widget/snacks.dart"; import "package:path_provider/path_provider.dart"; +import 'api_form.dart'; + /* * Class representing an API response from the server @@ -1200,4 +1202,80 @@ class InvenTreeAPI { } } + /** + * Send a request to the server to locate / identify either a StockItem or StockLocation + */ + Future locateItemOrLocation(BuildContext context, {int? item, int? location}) async { + + var plugins = getPlugins(mixin: "locate"); + + print("locateItemOrLocation"); + + if (plugins.isEmpty) { + // TODO: Error message + return; + } + + String plugin_name = ""; + + if (plugins.length == 1) { + plugin_name = plugins.first.key; + } else { + // User selects which plugin to use + List> plugin_options = []; + + for (var plugin in plugins) { + plugin_options.add({ + "display_name": plugin.humanName, + "value": plugin.key, + }); + } + + Map fields = { + "plugin": { + "label": L10().plugin, + "type": "choice", + "value": plugins.first.key, + "choices": plugin_options, + "required": true, + } + }; + + await launchApiForm( + context, + L10().locateLocation, + "", + fields, + icon: FontAwesomeIcons.searchLocation, + onSuccess: (Map data) async { + plugin_name = (data["plugin"] ?? "") as String; + } + ); + } + + Map body = { + "plugin": plugin_name, + }; + + if (item != null) { + body["item"] = item.toString(); + } + + if (location != null) { + body["location"] = location.toString(); + } + + post( + "/api/locate/", + body: body, + expectedStatusCode: 200, + ).then((APIResponse response) { + if (response.successful()) { + showSnackIcon( + L10().requestSuccessful, + success: true, + ); + } + }); + } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7640b15..02cb93b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -707,6 +707,9 @@ "request": "Request", "@request": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", "@requestingData": {}, diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 17ca010..4b38bf4 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -92,69 +92,21 @@ class _LocationDisplayState extends RefreshableState { return actions; } + /* + * Request identification of this location + */ Future _locateStockLocation(BuildContext context) async { final _loc = location; if (_loc != null) { - - final plugins = InvenTreeAPI().getPlugins(mixin: "locate"); - - if (plugins.isEmpty) { - // TODO: Error message here - return; - } - - String plugin_name = ""; - - if (plugins.length == 1) { - plugin_name = plugins.first.key; - } else { - // User selects which plugin to use - List> plugin_options = []; - - for (var plugin in plugins) { - plugin_options.add({ - "display_name": plugin.humanName, - "value": plugin.key, - }); - } - - Map fields = { - "plugin": { - "label": L10().plugin, - "type": "choice", - "value": plugins.first.key, - "choices": plugin_options, - "required": true, - } - }; - - await launchApiForm( - context, - L10().locateLocation, - "", - fields, - icon: FontAwesomeIcons.searchLocation, - onSuccess: (Map data) async { - plugin_name = (data["plugin"] ?? "") as String; - } - ); - } - - print("plugin: ${plugin_name}"); - - InvenTreeAPI().post( - "/api/locate/", - body: { - "plugin": plugin_name, - "location": "${_loc.pk}", - }, - expectedStatusCode: 200, - ); + InvenTreeAPI().locateItemOrLocation(context, location: _loc.pk); } } + /* + * Launch a dialog form to edit this stock location + */ void _editLocationDialog(BuildContext context) { final _loc = location; From 366c732668344b5a039b57b2e75a3cf2d5285d68 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 00:30:28 +1000 Subject: [PATCH 102/746] Add support for locating a stock item --- lib/widget/stock_detail.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 3e2f470..b0b3cda 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -67,6 +67,18 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (InvenTreeAPI().supportsMixin("locate")) { + actions.add( + IconButton( + icon: FaIcon(FontAwesomeIcons.searchLocation), + tooltip: L10().locateItem, + onPressed: () async { + InvenTreeAPI().locateItemOrLocation(context, item: item.pk); + }, + ) + ); + } + if (InvenTreeAPI().checkPermission("stock", "change")) { actions.add( IconButton( From 9f6269375feabe8376f27d02e41a1b569278c1af Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 01:19:38 +1000 Subject: [PATCH 103/746] linting --- lib/api.dart | 4 ++-- lib/widget/location_display.dart | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index a799235..51a414c 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -22,7 +22,7 @@ import "package:inventree/user_profile.dart"; import "package:inventree/widget/snacks.dart"; import "package:path_provider/path_provider.dart"; -import 'api_form.dart'; +import "package:inventree/api_form.dart"; /* @@ -1202,7 +1202,7 @@ class InvenTreeAPI { } } - /** + /* * Send a request to the server to locate / identify either a StockItem or StockLocation */ Future locateItemOrLocation(BuildContext context, {int? item, int? location}) async { diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 4b38bf4..c1647ee 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -3,7 +3,6 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; -import 'package:inventree/api_form.dart'; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/inventree/stock.dart"; From bc53dafaba4653f609b8091bb4bc9b026159d027 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 08:12:53 +1000 Subject: [PATCH 104/746] Add plugin support status to server information screen --- lib/l10n/app_en.arb | 6 ++++++ lib/settings/about.dart | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 02cb93b..3b13d9c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -590,6 +590,12 @@ "pluginPrinter": "Printer", "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", "@printLabelFailure": {}, diff --git a/lib/settings/about.dart b/lib/settings/about.dart index f62179c..7ba8c5d 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -102,6 +102,18 @@ class InvenTreeAboutWidget extends StatelessWidget { leading: FaIcon(FontAwesomeIcons.server), ) ); + + // Display extra tile if the server supports plugins + if (InvenTreeAPI().pluginsEnabled()) { + tiles.add( + ListTile( + title: Text(L10().pluginSupport), + subtitle: Text(L10().pluginSupportDetail), + leading: FaIcon(FontAwesomeIcons.plug), + ) + ); + } + } else { tiles.add( ListTile( From 969875ad49c1e716176b2745c3d4c50a9af6a5ae Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 08:42:08 +1000 Subject: [PATCH 105/746] Hide manufacturer / supplier / customer screens - For now, as they don't do anything useful - Will add back in once features are expanded --- lib/settings/home_settings.dart | 4 ++++ lib/widget/home.dart | 3 +++ 2 files changed, 7 insertions(+) diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 7b93f40..c5776c6 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -85,6 +85,9 @@ class _HomeScreenSettingsState extends State { }, ), ), + // TODO: When these features are improved, add them back in! + // Currently, the company display does not provide any value + /* ListTile( title: Text(L10().homeShowSuppliers), subtitle: Text(L10().homeShowSuppliersDescription), @@ -127,6 +130,7 @@ class _HomeScreenSettingsState extends State { }, ), ), + */ ] ) ) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index eefd9c6..7cfb845 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -290,6 +290,8 @@ class _InvenTreeHomePageState extends State { )); } + // TODO: Add these tiles back in once the features are fleshed out + /* // Suppliers if (homeShowSuppliers) { tiles.add(_listTile( @@ -325,6 +327,7 @@ class _InvenTreeHomePageState extends State { } )); } + */ // Settings tiles.add(_listTile( From 4bd800d27310940bea835b4c0bca93c91fc63d1c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 17:07:53 +1000 Subject: [PATCH 106/746] linting fix --- lib/widget/home.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 7cfb845..23153a8 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -16,7 +16,6 @@ import "package:inventree/user_profile.dart"; import "package:inventree/inventree/notification.dart"; import "package:inventree/widget/category_display.dart"; -import "package:inventree/widget/company_list.dart"; import "package:inventree/widget/drawer.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/notifications.dart"; @@ -117,7 +116,7 @@ class _InvenTreeHomePageState extends State { ); } - + /* void _showSuppliers(BuildContext context) { if (!InvenTreeAPI().checkConnection(context)) return; @@ -135,6 +134,7 @@ class _InvenTreeHomePageState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"}))); } + */ void _selectProfile() { Navigator.push( From 7c36659fe940601c4f12ff2a5c3a545e76b9216f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 18:15:53 +1000 Subject: [PATCH 107/746] Remove "submit feedback" widget - Now open source on github! --- lib/widget/submit_feedback.dart | 90 --------------------------------- 1 file changed, 90 deletions(-) delete mode 100644 lib/widget/submit_feedback.dart diff --git a/lib/widget/submit_feedback.dart b/lib/widget/submit_feedback.dart deleted file mode 100644 index 3439292..0000000 --- a/lib/widget/submit_feedback.dart +++ /dev/null @@ -1,90 +0,0 @@ -import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/widget/snacks.dart"; - -import "package:inventree/l10.dart"; - -class SubmitFeedbackWidget extends StatefulWidget { - - @override - _SubmitFeedbackState createState() => _SubmitFeedbackState(); - -} - - -class _SubmitFeedbackState extends State { - - final _formkey = GlobalKey(); - - String message = ""; - - @override - Widget build(BuildContext context) { - - return Scaffold( - appBar: AppBar( - title: Text(L10().submitFeedback), - actions: [ - IconButton( - icon: FaIcon(FontAwesomeIcons.paperPlane), - onPressed: () async { - if (_formkey.currentState!.validate()) { - _formkey.currentState!.save(); - - // Upload - bool result = await sentryReportMessage(message); - - if (result) { - showSnackIcon( - L10().feedbackSuccess, - success: true, - ); - } else { - showSnackIcon( - L10().feedbackError, - success: false - ); - } - - // Exit - Navigator.of(context).pop(); - } - }, - ) - ], - ), - body: Form( - key: _formkey, - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextFormField( - decoration: InputDecoration( - labelText: L10().feedback, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - ), - maxLines: null, - keyboardType: TextInputType.multiline, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return L10().valueCannotBeEmpty; - } - - return null; - }, - onSaved: (value) { - if (value != null) { - message = value; - } - }, - ), - ], - ) - ) - ) - ); - } - -} \ No newline at end of file From 610f6533d0488a1823f315483fdfb8c879b6f53c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 18:16:15 +1000 Subject: [PATCH 108/746] Refactor sentry error reporting for model class --- lib/inventree/model.dart | 106 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 1d13d17..609dafb 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -233,6 +233,32 @@ class InvenTreeModel { return {}; } + Future reportModelError(String title, APIResponse response, {Map context = {}}) async { + + String dataString = response.data?.toString() ?? "null"; + + if (dataString.length > 500) { + dataString = dataString.substring(0, 500); + } + + // Add some default context data + + context["url"] = response.url.toString(); + context["statusCode"] = response.statusCode.toString(); + context["responseData"] = dataString; + context["valid"] = response.isValid().toString(); + context["error"] = response.error; + context["errorDetail"] = response.errorDetail; + context["isNull"] = response.data == null ? "true" : "false"; + context["dataType"] = response.data?.runtimeType.toString() ?? "null"; + context["model"] = URL; + + await sentryReportMessage( + title, + context: context, + ); + } + /// Delete the instance on the remote server /// Returns true if the operation was successful, else false Future delete() async { @@ -240,18 +266,10 @@ class InvenTreeModel { if (!response.isValid() || response.data == null || (response.data is! Map)) { - if (response.statusCode > 0) { - await sentryReportMessage( - "InvenTreeModel.delete() returned invalid response", - context: { - "url": url, - "statusCode": response.statusCode.toString(), - "data": response.data?.toString() ?? "null", - "error": response.error, - "errorDetail": response.errorDetail, - } - ); - } + reportModelError( + "InvenTreeModel.delete() returned invalid response", + response, + ); showServerError( L10().serverError, @@ -274,20 +292,13 @@ class InvenTreeModel { if (!response.isValid() || response.data == null || (response.data is! Map)) { - // Report error - if (response.statusCode > 0) { - await sentryReportMessage( - "InvenTreeModel.reload() returned invalid response", - context: { - "url": url, - "statusCode": response.statusCode.toString(), - "data": response.data?.toString() ?? "null", - "valid": response.isValid().toString(), - "error": response.error, - "errorDetail": response.errorDetail, - }, - ); - } + reportModelError( + "InvenTreeModel.reload() returned invalid response", + response, + context: { + "pk": pk.toString(), + } + ); showServerError( L10().serverError, @@ -347,19 +358,15 @@ class InvenTreeModel { if (!response.isValid() || response.data == null || response.data is! Map) { - if (response.statusCode > 0) { - await sentryReportMessage( - "InvenTreeModel.get() returned invalid response", - context: { - "url": url, - "statusCode": response.statusCode.toString(), - "data": response.data?.toString() ?? "null", - "valid": response.isValid().toString(), - "error": response.error, - "errorDetail": response.errorDetail, - } - ); - } + // Report error + reportModelError( + "InvenTreeModel.getModel() returned invalid response", + response, + context: { + "filters": filters.toString(), + "pk": pk, + } + ); showServerError( L10().serverError, @@ -394,26 +401,19 @@ class InvenTreeModel { // Invalid response returned from server if (!response.isValid() || response.data == null || response.data is! Map) { - if (response.statusCode > 0) { - await sentryReportMessage( - "InvenTreeModel.create() returned invalid response", - context: { - "url": url, - "statusCode": response.statusCode.toString(), - "data": response.data?.toString() ?? "null", - "valid": response.isValid().toString(), - "error": response.error, - "errorDetail": response.errorDetail, - } - ); - } + reportModelError( + "InvenTreeModel.create() returned invalid response", + response, + context: { + "pk": pk.toString(), + } + ); showServerError( L10().serverError, L10().errorCreate, ); - return null; } From e2ed80f2d0c7c5b800131f562825b6ad23777908 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 18:26:55 +1000 Subject: [PATCH 109/746] Add barcode scan context --- lib/barcode.dart | 1 + lib/inventree/model.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/barcode.dart b/lib/barcode.dart index 4fd23f3..af16658 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -99,6 +99,7 @@ class BarcodeHandler { "valid": response.isValid().toString(), "error": response.error, "errorDetail": response.errorDetail, + "overlayText": getOverlayText(context), } ); } else if (data.containsKey("error")) { diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 609dafb..decb7aa 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -233,7 +233,7 @@ class InvenTreeModel { return {}; } - Future reportModelError(String title, APIResponse response, {Map context = {}}) async { + Future reportModelError(String title, APIResponse response, {Map context = const {}}) async { String dataString = response.data?.toString() ?? "null"; From 6d764e32a0ae8c294ab3061380c7e7c17c8c05d8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 23:37:21 +1000 Subject: [PATCH 110/746] Improve barcode error handling --- lib/api.dart | 4 ---- lib/barcode.dart | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 51a414c..e69f756 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -332,10 +332,6 @@ class InvenTreeAPI { if (!address.endsWith("/")) { address = address + "/"; } - /* TODO: Better URL validation - * - If not a valid URL, return error - * - If no port supplied, append a default port - */ _BASE_URL = address; diff --git a/lib/barcode.dart b/lib/barcode.dart index af16658..8781f2d 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -77,7 +77,7 @@ class BarcodeHandler { body: { "barcode": barcode, }, - expectedStatusCode: 200 + expectedStatusCode: null, // Do not show an error on "unexpected code" ); _controller?.resumeCamera(); @@ -90,7 +90,7 @@ class BarcodeHandler { // We want to know about this one! await sentryReportMessage( - "BarcodeHandler.processBarcode returned strange value", + "BarcodeHandler.processBarcode returned unexpected value", context: { "data": response.data?.toString() ?? "null", "barcode": barcode, @@ -102,7 +102,7 @@ class BarcodeHandler { "overlayText": getOverlayText(context), } ); - } else if (data.containsKey("error")) { + } else if ((response.statusCode >= 400) || data.containsKey("error")) { onBarcodeUnknown(context, data); } else if (data.containsKey("success")) { onBarcodeMatched(context, data); From 23a27fde6751831cfbc6d24f5d8ac0fa029f8754 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 23:42:27 +1000 Subject: [PATCH 111/746] Adds ability to show / hide password in profile widget --- lib/settings/login.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 5c29e16..a998af4 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -240,6 +240,8 @@ class _ProfileEditState extends State { String username = ""; String password = ""; + bool _obscured = true; + @override Widget build(BuildContext context) { return Scaffold( @@ -379,10 +381,18 @@ class _ProfileEditState extends State { labelText: L10().password, labelStyle: TextStyle(fontWeight: FontWeight.bold), hintText: L10().enterPassword, + suffixIcon: IconButton( + icon: _obscured ? FaIcon(FontAwesomeIcons.eye) : FaIcon(FontAwesomeIcons.solidEyeSlash), + onPressed: () { + setState(() { + _obscured = !_obscured; + }); + }, + ), ), initialValue: profile?.password ?? "", keyboardType: TextInputType.visiblePassword, - obscureText: true, + obscureText: _obscured, onSaved: (value) { password = value ?? ""; }, From b4e8d47d9aee3a71818b8a0457d46c37cd6af828 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 10 May 2022 23:49:03 +1000 Subject: [PATCH 112/746] Prevent notification requests if server is not connected --- lib/widget/home.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 23153a8..64c566d 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -180,6 +180,10 @@ class _InvenTreeHomePageState extends State { */ Future _refreshNotifications() async { + if (!InvenTreeAPI().isConnected()) { + return; + } + final notifications = await InvenTreeNotification().list(); setState(() { From c90a849a5ae2cfe4331fa14b35e58f38a1d7fd53 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 12 May 2022 22:46:12 +1000 Subject: [PATCH 113/746] Add extra context information to sentry error reports - Should help to track down bugs where stacktrace is missing information - Adds some more error catching, too --- lib/api.dart | 42 ++++++++++++++++++++++++++++++++------- lib/api_form.dart | 17 ++++++++++++++-- lib/inventree/sentry.dart | 6 +++++- lib/main.dart | 12 +++++++++-- lib/widget/paginator.dart | 5 ++++- 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index e69f756..9994b65 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -574,7 +574,15 @@ class InvenTreeAPI { // Ignore TypeError } else { // Unknown error - report it! - sentryReportError(error, stackTrace); + sentryReportError( + "api.checkPermission", + error, stackTrace, + context: { + "role": role, + "permission": permission, + "error": error.toString(), + } + ); } // Unable to determine permission - assume true? @@ -668,7 +676,10 @@ class InvenTreeAPI { } catch (error, stackTrace) { print("Server error at ${url}: ${error.toString()}"); showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + sentryReportError( + "api.downloadFile : client.openUrl", + error, stackTrace, + ); return; } @@ -692,10 +703,14 @@ class InvenTreeAPI { showServerError(L10().connectionRefused, error.toString()); } on TimeoutException { showTimeoutError(); - } catch (error) { + } catch (error, stackTrace) { print("Error downloading image:"); print(error.toString()); showServerError(L10().downloadError, error.toString()); + sentryReportError( + "api.downloadFile : client.closeRequest", + error, stackTrace, + ); } } @@ -779,7 +794,10 @@ class InvenTreeAPI { response.error = "TimeoutException"; } catch (error, stackTrace) { showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + sentryReportError( + "api.uploadFile", + error, stackTrace + ); response.error = "UnknownError"; response.errorDetail = error.toString(); } @@ -930,7 +948,14 @@ class InvenTreeAPI { } catch (error, stackTrace) { print("Server error at ${url}: ${error.toString()}"); showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + sentryReportError( + "api.apiRequest : openUrl", + error, stackTrace, + context: { + "url": url, + "method": method, + } + ); return null; } } @@ -996,13 +1021,16 @@ class InvenTreeAPI { showServerError(L10().connectionRefused, error.toString()); response.error = "SocketException"; response.errorDetail = error.toString(); - + } on CertificateException catch (error) { + print("CertificateException at ${request.uri.toString()}:"); + print(error.toString()); + showServerError(L10().serverCertificateError, error.toString()); } on TimeoutException { showTimeoutError(); response.error = "TimeoutException"; } catch (error, stackTrace) { showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + sentryReportError("api.completeRequest", error, stackTrace); response.error = "UnknownError"; response.errorDetail = error.toString(); } diff --git a/lib/api_form.dart b/lib/api_form.dart index ff82759..07221a1 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -788,7 +788,14 @@ Map extractFieldDefinition(Map data, String lo print(error.toString()); // Report the error - sentryReportError(error, stackTrace); + sentryReportError( + "apiForm.extractFieldDefinition : path traversal", + error, stackTrace, + context: { + "path": path.toString(), + "el": el, + } + ); return {}; } } @@ -808,7 +815,13 @@ Map extractFieldDefinition(Map data, String lo print(error.toString()); // Report the error - sentryReportError(error, stacktrace); + sentryReportError( + "apiForm.extractFieldDefinition : as map", + error, stacktrace, + context: { + "el": el.toString(), + } + ); return {}; } diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 79a8ea5..429a50a 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -142,7 +142,7 @@ Future sentryReportMessage(String message, {Map? context}) } -Future sentryReportError(dynamic error, dynamic stackTrace) async { +Future sentryReportError(String source, dynamic error, dynamic stackTrace, {Map context = const {}}) async { print("----- Sentry Intercepted error: $error -----"); print(stackTrace); @@ -167,10 +167,14 @@ Future sentryReportError(dynamic error, dynamic stackTrace) async { final app_info = await getAppInfo(); final device_info = await getDeviceInfo(); + // Ensure we pass the 'source' of the error + context["source"] = source; + Sentry.configureScope((scope) { scope.setExtra("server", server_info); scope.setExtra("app", app_info); scope.setExtra("device", device_info); + scope.setExtra("context", context); }); Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { diff --git a/lib/main.dart b/lib/main.dart index 9d97ccc..ea0703f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -39,7 +39,15 @@ Future main() async { FlutterError.onError = (FlutterErrorDetails details) async { // Ensure that the error gets reported to sentry! - await sentryReportError(details.exception, details.stack); + await sentryReportError( + "FlutterError.onError", + details.exception, details.stack, + context: { + "context": details.context.toString(), + "summary": details.summary.toString(), + "library": details.library ?? "null", + } + ); }; runApp( @@ -47,7 +55,7 @@ Future main() async { ); }, (Object error, StackTrace stackTrace) async { - sentryReportError(error, stackTrace); + sentryReportError("main.runZonedGuarded", error, stackTrace); }); } diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index f1bfbc8..aa62647 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -86,7 +86,10 @@ class PaginatedSearchState extends State { } catch (error, stackTrace) { _pagingController.error = error; - sentryReportError(error, stackTrace); + sentryReportError( + "paginator.fetchPage", + error, stackTrace, + ); } } From 4d81cd04150609aa956b6b5d142a3ae06e4086f1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 12 May 2022 22:48:46 +1000 Subject: [PATCH 114/746] Update release notes --- assets/release_notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 38487ba..c407b2d 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,11 +5,12 @@ --- - Refactor home screen display -- Display unread notifications on home screen +- Display notification messages from InvenTree server - Fixes duplicated display of units when showing stock quantity - Adds ability to locate / identify stock items or locations (requires server plugin) - Improve rendering of home screen when server is not connected - Adds ability to load global and user settings from the server +- Translation updates ### 0.6.2 - April 2022 --- From 73a8e8da403633fa3acf2a32210b7c167c7681fd Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 May 2022 23:58:05 +1000 Subject: [PATCH 115/746] New translations app_en.arb (German) (#130) --- lib/l10n/de_DE/app_de_DE.arb | 49 +++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 30cfeff..9fcf776 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1,5 +1,13 @@ { "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, "about": "Über", "@about": {}, "accountDetails": "Konto Details", @@ -142,6 +150,10 @@ "@description": {}, "destroyed": "Vernichtet", "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, "documentation": "Dokumentation", "@documentation": {}, "downloading": "Datei wird heruntergeladen", @@ -186,6 +198,8 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, "feedbackError": "Fehler beim Senden des Feedbacks", "@feedbackError": {}, "feedbackSuccess": "Feedback gesendet", @@ -200,6 +214,7 @@ "@history": { "description": "history" }, + "home": "Startseite", "@homeScreen": {}, "homeScreen": "Startseite", "homeScreenSettings": "Einstellungen für Startseite konfigurieren", @@ -244,6 +259,8 @@ "@incompleteDetails": {}, "internalPartNumber": "Interne Teilenummer", "@internalPartNumber": {}, + "info": "Info", + "@info": {}, "inProduction": "In Produktion", "@inProduction": {}, "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", @@ -284,18 +301,26 @@ "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", "@locationUpdated": {}, + "link": "Link", + "@link": {}, "lost": "Verloren", "@lost": {}, "manufacturers": "Hersteller", "@manufacturers": {}, "missingData": "Fehlende Daten", "@missingData": {}, + "name": "Name", + "@name": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, "notes": "Notizen", "@notes": { "description": "Notes" }, + "notifications": "Benachrichtigungen", + "@notifications": {}, + "notificationsEmpty": "Keine ungelesenen Benachrichtigungen", + "@notificationsEmpty": {}, "noResponse": "Keine Antwort vom Server", "@noResponse": {}, "noResults": "Keine Ergebnisse", @@ -368,6 +393,14 @@ "@permissionRequired": {}, "printLabel": "Label drucken", "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Drucker", + "@pluginPrinter": {}, + "pluginSupport": "Plugin-Unterstützung aktiviert", + "@pluginSupport": {}, + "pluginSupportDetail": "Der Server unterstützt individuelle Plugins", + "@pluginSupportDetail": {}, "printLabelFailure": "Labeldruck fehlgeschlagen", "@printLabelFailure": {}, "printLabelSuccess": "Label an den Drucker gesendet", @@ -390,6 +423,8 @@ "@profileNotSelected": {}, "profileSelect": "InvenTree-Server auswählen", "@profileSelect": {}, + "profileSelectOrCreate": "Server auswählen oder ein neues Profil erstellen", + "@profileSelectOrCreate": {}, "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", "@profileTapToCreate": {}, "purchaseOrder": "Bestellung", @@ -412,6 +447,8 @@ "@quantityInvalid": {}, "quantityPositive": "Menge muss positiv sein", "@quantityPositive": {}, + "queryEmpty": "Suchanfrage eingeben", + "@queryEmpty": {}, "queryNoResults": "Keine Ergebnisse für die Anfrage", "@queryNoResults": {}, "received": "Empfangen", @@ -444,6 +481,8 @@ "@results": {}, "request": "Anfrage", "@request": {}, + "requestSuccessful": "Anfrage erfolgreich", + "@requestSuccessful": {}, "requestingData": "Daten werden angefordert", "@requestingData": {}, "required": "Erforderlich", @@ -518,6 +557,8 @@ "@send": {}, "serialNumber": "Seriennummer", "@serialNumber": {}, + "server": "Server", + "@server": {}, "serverAddress": "Serveradresse", "@serverAddress": {}, "serverApiRequired": "Erforderliche API-Version", @@ -562,6 +603,8 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Ton bei Serverfehler abspielen", "@soundOnServerError": {}, + "status": "Status", + "@status": {}, "statusCode": "Statuscode", "@statusCode": {}, "stock": "Bestand", @@ -712,6 +755,10 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Wert erforderlich", "@valueRequired": {}, + "version": "Version", + "@version": {}, "viewSupplierPart": "Zulieferer-Teil anzeigen", - "@viewSupplierPart": {} + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file From 1b4c53b4b3ad794301be158b3b0093a887a5a885 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 17 May 2022 12:59:32 +1000 Subject: [PATCH 116/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index bc91891..4075b80 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -285,6 +285,8 @@ "@itemInLocation": {}, "keywords": "Kulcsszavak", "@keywords": {}, + "labelTemplate": "Címke sablon", + "@labelTemplate": {}, "lastStocktake": "Utolsó leltár", "@lastStocktake": {}, "lastUpdated": "Utoljára módosítva", @@ -293,6 +295,10 @@ "@lineItem": {}, "lineItems": "Sortételek", "@lineItems": {}, + "locateItem": "Készlet tétel keresése", + "@locateItem": {}, + "locateLocation": "Készlet hely keresése", + "@locateLocation": {}, "locationCreate": "Új hely", "@locationCreate": {}, "locationCreateDetail": "Új készlet hely létrehozása", @@ -393,6 +399,14 @@ "@permissionRequired": {}, "printLabel": "Címke nyomtatása", "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Nyomtató", + "@pluginPrinter": {}, + "pluginSupport": "Plugin támogatás engedélyezve", + "@pluginSupport": {}, + "pluginSupportDetail": "A kiszolgáló támogatja az egyedi pluginokat", + "@pluginSupportDetail": {}, "printLabelFailure": "Címkenyomtatás sikertelen", "@printLabelFailure": {}, "printLabelSuccess": "Címke nyomtatónak elküldve", @@ -415,6 +429,8 @@ "@profileNotSelected": {}, "profileSelect": "Válassz InvenTree kiszolgálót", "@profileSelect": {}, + "profileSelectOrCreate": "Válassz kiszolgálót vagy hozz létre új profilt", + "@profileSelectOrCreate": {}, "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", "@profileTapToCreate": {}, "purchaseOrder": "Beszerzési rendelés", @@ -471,6 +487,8 @@ "@results": {}, "request": "Kérés", "@request": {}, + "requestSuccessful": "Kérés sikeres", + "@requestSuccessful": {}, "requestingData": "Adatok lekérése", "@requestingData": {}, "required": "Kötelező", From d7d8cefdddf585c9916312065fd664a31c4a2601 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 17 May 2022 20:28:26 +1000 Subject: [PATCH 117/746] v0.7.0 - Update version number --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index c407b2d..ca14a6c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,7 +1,7 @@ ## InvenTree App Release Notes --- -### 0.7.0 - +### 0.7.0 - May 2022 --- - Refactor home screen display diff --git a/pubspec.yaml b/pubspec.yaml index 0c003ee..9031ea5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.6.2+40 +version: 0.7.0+41 environment: sdk: ">=2.16.0 <3.0.0" From acf89426cec238ef3837ad7dc409a317a22e6197 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 19 May 2022 20:38:28 +1000 Subject: [PATCH 118/746] Fix for search screen - Change input and controller - Add focus node - Add "searching" indicator --- assets/release_notes.md | 5 +++ lib/l10n/app_en.arb | 3 ++ lib/widget/search.dart | 88 +++++++++++++++++++++++++++++++++-------- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ca14a6c..e240c26 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.7.1 - May 2022 +--- + +- Fixes issue which prevented text input in search window + ### 0.7.0 - May 2022 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3b13d9c..f6e6064 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -797,6 +797,9 @@ "description": "search" }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", "@searchLocation": {}, diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 2d21fc6..96cf42f 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -36,6 +36,19 @@ class _SearchDisplayState extends RefreshableState { final bool hasAppBar; + @override + void initState() { + super.initState(); + + _focusNode = FocusNode(); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + @override String getAppBarTitle(BuildContext context) => L10().search; @@ -52,6 +65,17 @@ class _SearchDisplayState extends RefreshableState { Timer? debounceTimer; + bool isSearching() { + + if (searchController.text.isEmpty) { + return false; + } + + return nSearchResults < 6; + } + + int nSearchResults = 0; + int nPartResults = 0; int nCategoryResults = 0; @@ -64,6 +88,8 @@ class _SearchDisplayState extends RefreshableState { int nPurchaseOrderResults = 0; + late FocusNode _focusNode; + // Callback when the text is being edited // Incorporates a debounce timer to restrict search frequency void onSearchTextChanged(String text, {bool immediate = false}) { @@ -84,6 +110,10 @@ class _SearchDisplayState extends RefreshableState { Future search(String term) async { + setState(() { + nSearchResults = 0; + }); + if (term.isEmpty) { setState(() { // Do not search on an empty string @@ -93,6 +123,8 @@ class _SearchDisplayState extends RefreshableState { nLocationResults = 0; nSupplierResults = 0; nPurchaseOrderResults = 0; + + nSearchResults = 0; }); return; @@ -104,6 +136,8 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nPartResults = n; + + nSearchResults++; }); }); @@ -113,6 +147,8 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nCategoryResults = n; + + nSearchResults++; }); }); @@ -122,6 +158,8 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nStockResults = n; + + nSearchResults++; }); }); @@ -131,6 +169,8 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nLocationResults = n; + + nSearchResults++; }); }); @@ -143,6 +183,7 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nSupplierResults = n; + nSearchResults++; }); }); @@ -155,6 +196,7 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { setState(() { nPurchaseOrderResults = n; + nSearchResults++; }); }); @@ -166,29 +208,31 @@ class _SearchDisplayState extends RefreshableState { // Search input tiles.add( - InputDecorator( + TextFormField( decoration: InputDecoration( - ), - child: ListTile( - title: TextField( - readOnly: false, - decoration: InputDecoration( - helperText: L10().queryEmpty, - ), - controller: searchController, - onChanged: (String text) { - onSearchTextChanged(text); - }, + hintText: L10().queryEmpty, + prefixIcon: IconButton( + icon: FaIcon(FontAwesomeIcons.search), + onPressed: null, ), - trailing: IconButton( + suffixIcon: IconButton( icon: FaIcon(FontAwesomeIcons.backspace, color: Colors.red), onPressed: () { searchController.clear(); onSearchTextChanged("", immediate: true); - }, + _focusNode.requestFocus(); + } ), - ) - ) + ), + readOnly: false, + autofocus: true, + autocorrect: false, + focusNode: _focusNode, + controller: searchController, + onChanged: (String text) { + onSearchTextChanged(text); + }, + ), ); String query = searchController.text; @@ -335,7 +379,17 @@ class _SearchDisplayState extends RefreshableState { ); } - if (results.isEmpty && searchController.text.isNotEmpty) { + if (isSearching()) { + tiles.add( + ListTile( + title: Text(L10().searching), + leading: FaIcon(FontAwesomeIcons.search), + trailing: CircularProgressIndicator(), + ) + ); + } + + if (!isSearching() && results.isEmpty && searchController.text.isNotEmpty) { tiles.add( ListTile( title: Text(L10().queryNoResults), From 941ee5e1725975b6fbba9f4a44c2fb0c70e14286 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 19 May 2022 21:06:20 +1000 Subject: [PATCH 119/746] Prevent "old" search results from mucking up the displayed data - Only accept results if the search term has not changed --- lib/inventree/model.dart | 2 - lib/widget/search.dart | 103 ++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index decb7aa..550bc2f 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -216,8 +216,6 @@ class InvenTreeModel { if (response.isValid()) { int n = int.tryParse(response.data["count"].toString()) ?? 0; - - print("${URL} -> ${n} results"); return n; } else { return 0; diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 96cf42f..1a59237 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -105,78 +105,78 @@ class _SearchDisplayState extends RefreshableState { search(text); }); } - } + /* + * Initiate multiple search requests to the server. + * Each request returns at *some point* in the future, + * by which time the search input may have changed, giving unexpected results. + * + * So, each request only causes an update *if* the search term is still the same when it completes + */ Future search(String term) async { setState(() { + // Do not search on an empty string + nPartResults = 0; + nCategoryResults = 0; + nStockResults = 0; + nLocationResults = 0; + nSupplierResults = 0; + nPurchaseOrderResults = 0; + nSearchResults = 0; }); if (term.isEmpty) { - setState(() { - // Do not search on an empty string - nPartResults = 0; - nCategoryResults = 0; - nStockResults = 0; - nLocationResults = 0; - nSupplierResults = 0; - nPurchaseOrderResults = 0; - - nSearchResults = 0; - }); - return; } // Search parts - InvenTreePart().count( - searchQuery: term - ).then((int n) { - setState(() { - nPartResults = n; - - nSearchResults++; - }); + InvenTreePart().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nPartResults = n; + nSearchResults++; + }); + } }); // Search part categories - InvenTreePartCategory().count( - searchQuery: term, - ).then((int n) { - setState(() { - nCategoryResults = n; - - nSearchResults++; - }); + InvenTreePartCategory().count(searchQuery: term,).then((int n) { + if (term == searchController.text) { + setState(() { + nCategoryResults = n; + nSearchResults++; + }); + } }); // Search stock items - InvenTreeStockItem().count( - searchQuery: term - ).then((int n) { - setState(() { - nStockResults = n; - - nSearchResults++; - }); + InvenTreeStockItem().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nStockResults = n; + nSearchResults++; + }); + } }); // Search stock locations - InvenTreeStockLocation().count( - searchQuery: term - ).then((int n) { - setState(() { - nLocationResults = n; + InvenTreeStockLocation().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nLocationResults = n; - nSearchResults++; - }); + nSearchResults++; + }); + } }); + // TDOO: Re-implement this once display for companies has been fixed + /* // Search suppliers - InvenTreeCompany().count( - searchQuery: term, + InvenTreeCompany().count(searchQuery: term, filters: { "is_supplier": "true", }, @@ -186,6 +186,7 @@ class _SearchDisplayState extends RefreshableState { nSearchResults++; }); }); + */ // Search purchase orders InvenTreePurchaseOrder().count( @@ -194,10 +195,12 @@ class _SearchDisplayState extends RefreshableState { "outstanding": "true" } ).then((int n) { - setState(() { - nPurchaseOrderResults = n; - nSearchResults++; - }); + if (term == searchController.text) { + setState(() { + nPurchaseOrderResults = n; + nSearchResults++; + }); + } }); } From 11157b7c77da15ab6578ec48957b8540694579e9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 19 May 2022 21:11:46 +1000 Subject: [PATCH 120/746] Fix search counter --- lib/widget/search.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 1a59237..c2bc63f 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -4,7 +4,6 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/purchase_order_list.dart"; @@ -71,7 +70,7 @@ class _SearchDisplayState extends RefreshableState { return false; } - return nSearchResults < 6; + return nSearchResults < 5; } int nSearchResults = 0; @@ -405,8 +404,11 @@ class _SearchDisplayState extends RefreshableState { } } - return tiles; + if (!_focusNode.hasFocus) { + _focusNode.requestFocus(); + } + return tiles; } @override From a9f794af1fc5ef5339814f28055492379e888a51 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 May 2022 23:04:53 +1000 Subject: [PATCH 121/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 82ccc61..e6de669 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1,9 +1,21 @@ { "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, "about": "À propos", "@about": {}, "accountDetails": "Détails du compte", "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, "actionsNone": "Aucune action disponible", "@actionsNone": {}, "add": "Ajouter", @@ -40,6 +52,8 @@ "@attachmentNonePartDetail": {}, "attachmentSelect": "Sélectionner une pièce jointe", "@attachmentSelect": {}, + "attention": "Avertissement", + "@attention": {}, "availableStock": "Stock disponible", "@availableStock": {}, "barcodeAssign": "Affecter un code-barres", @@ -80,6 +94,8 @@ "@batchCode": {}, "billOfMaterials": "Liste des matériaux", "@billOfMaterials": {}, + "bom": "Liste de matériel", + "@bom": {}, "build": "Assemblage", "@build": {}, "building": "Assemblage en cours", @@ -130,12 +146,16 @@ "@deletePart": {}, "deletePartDetail": "Supprimer cette pièce de la base de données", "@deletePartDetail": {}, + "description": "Description", + "@description": {}, "destroyed": "Détruit", "@destroyed": {}, "details": "Détails", "@details": { "description": "details" }, + "documentation": "Documentation", + "@documentation": {}, "downloading": "Téléchargement du fichier", "@downloading": {}, "downloadError": "Erreur lors du téléchargement", @@ -194,6 +214,7 @@ "@history": { "description": "history" }, + "home": "Page d’accueil", "@homeScreen": {}, "homeScreen": "Ecran d'accueil", "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", @@ -264,6 +285,8 @@ "@itemInLocation": {}, "keywords": "Mots clés", "@keywords": {}, + "labelTemplate": "Modèle d'étiquette", + "@labelTemplate": {}, "lastStocktake": "Dernier inventaire", "@lastStocktake": {}, "lastUpdated": "Dernière mise à jour", @@ -272,6 +295,10 @@ "@lineItem": {}, "lineItems": "Position", "@lineItems": {}, + "locateItem": "Localiser l'article en stock", + "@locateItem": {}, + "locateLocation": "Localiser l'emplacement du stock", + "@locateLocation": {}, "locationCreate": "Nouvel emplacement", "@locationCreate": {}, "locationCreateDetail": "Créer un nouvel emplacement de stock", @@ -292,6 +319,14 @@ "@name": {}, "notConnected": "Non connecté", "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "Aucune notification non-lue", + "@notificationsEmpty": {}, "noResponse": "Aucune réponse du serveur", "@noResponse": {}, "noResults": "Aucun résultat", @@ -310,6 +345,8 @@ "@packaging": {}, "packageName": "Nom du package", "@packageName": {}, + "parent": "Niveau superieur", + "@parent": {}, "parentCategory": "Catégorie parent", "@parentCategory": {}, "parentLocation": "Emplacement parent", @@ -362,6 +399,14 @@ "@permissionRequired": {}, "printLabel": "Imprimer l'étiquette", "@printLabel": {}, + "plugin": "Extension", + "@plugin": {}, + "pluginPrinter": "Imprimante", + "@pluginPrinter": {}, + "pluginSupport": "Prise en charge du plugin activée", + "@pluginSupport": {}, + "pluginSupportDetail": "Le serveur supporte des plugins personnalisés", + "@pluginSupportDetail": {}, "printLabelFailure": "Echec de l'impression", "@printLabelFailure": {}, "printLabelSuccess": "Etiquette envoyée à l'imprimante", @@ -384,6 +429,8 @@ "@profileNotSelected": {}, "profileSelect": "Sélectionner le serveur InvenTree", "@profileSelect": {}, + "profileSelectOrCreate": "Sélectionnez un serveur ou créez un nouveau profil", + "@profileSelectOrCreate": {}, "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", "@profileTapToCreate": {}, "purchaseOrder": "Commande d’achat", @@ -406,6 +453,8 @@ "@quantityInvalid": {}, "quantityPositive": "La quantité doit être positive", "@quantityPositive": {}, + "queryEmpty": "Entrer un critère de recherche", + "@queryEmpty": {}, "queryNoResults": "Pas de résultat pour votre requête", "@queryNoResults": {}, "received": "Reçu", @@ -438,6 +487,8 @@ "@results": {}, "request": "Requête", "@request": {}, + "requestSuccessful": "Recherche reussie", + "@requestSuccessful": {}, "requestingData": "Demande de données", "@requestingData": {}, "required": "Requis", @@ -562,6 +613,10 @@ "@status": {}, "statusCode": "Code d'état", "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, "stockDetails": "Quantité actuelle de stock disponible", "@stockDetails": {}, "stockItem": "Article en stock", @@ -636,6 +691,8 @@ "@takePicture": {}, "targetDate": "Date Cible", "@targetDate": {}, + "templatePart": "Modele de composant", + "@templatePart": {}, "testName": "Nom de test", "@testName": {}, "testPassedOrFailed": "Test réussi ou échoué", @@ -704,6 +761,8 @@ "@valueCannotBeEmpty": {}, "valueRequired": "La valeur est requise", "@valueRequired": {}, + "version": "Version", + "@version": {}, "viewSupplierPart": "Voir la pièce du fournisseur", "@viewSupplierPart": {}, "website": "Site web", From cb866fb45c7c7a6647439604f8267a7fc9ca4f8d Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 20 May 2022 11:00:58 +1000 Subject: [PATCH 122/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index e6de669..780036a 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -219,13 +219,13 @@ "homeScreen": "Ecran d'accueil", "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", "@homeScreenSettings": {}, - "homeShowPo": "Afficher les commandes d'achat", + "homeShowPo": "Voir bon de commande", "@homeShowPo": {}, "homeShowSubscribed": "Pièces suivies", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Afficher le bouton de bon de commande sur l'écran d'accueil", + "homeShowPoDescription": "Afficher le bouton de l'ordre d'achat sur l'écran d'accueil", "@homeShowPoDescription": {}, "homeShowSuppliers": "Afficher les fournisseurs", "@homeShowSuppliers": {}, From 8300cde3eca926650c1216c2b9e269210caaf967 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 20 May 2022 11:01:00 +1000 Subject: [PATCH 123/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 9fcf776..099b892 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -285,6 +285,8 @@ "@itemInLocation": {}, "keywords": "Schlüsselwörter", "@keywords": {}, + "labelTemplate": "Label Vorlage", + "@labelTemplate": {}, "lastStocktake": "Letzte Inventur", "@lastStocktake": {}, "lastUpdated": "Letzte Änderung", @@ -539,6 +541,8 @@ "@search": { "description": "search" }, + "searching": "Suche", + "@searching": {}, "searchLocation": "Lagerort suchen", "@searchLocation": {}, "searchParts": "Teile suchen", From 10b435f4faa329af4894f26a5740aa775ee9ccb1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 May 2022 21:32:21 +1000 Subject: [PATCH 124/746] Merge pull request #132 from inventree/search-fix Search fix (cherry picked from commit a4814816ad4772ab0c2c08e33aef7d66f8800edf) --- assets/release_notes.md | 5 ++ lib/inventree/model.dart | 2 - lib/l10n/app_en.arb | 3 + lib/widget/search.dart | 177 ++++++++++++++++++++++++++------------- 4 files changed, 126 insertions(+), 61 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ca14a6c..e240c26 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.7.1 - May 2022 +--- + +- Fixes issue which prevented text input in search window + ### 0.7.0 - May 2022 --- diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index decb7aa..550bc2f 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -216,8 +216,6 @@ class InvenTreeModel { if (response.isValid()) { int n = int.tryParse(response.data["count"].toString()) ?? 0; - - print("${URL} -> ${n} results"); return n; } else { return 0; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3b13d9c..f6e6064 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -797,6 +797,9 @@ "description": "search" }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", "@searchLocation": {}, diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 2d21fc6..c2bc63f 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -4,7 +4,6 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/purchase_order_list.dart"; @@ -36,6 +35,19 @@ class _SearchDisplayState extends RefreshableState { final bool hasAppBar; + @override + void initState() { + super.initState(); + + _focusNode = FocusNode(); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + @override String getAppBarTitle(BuildContext context) => L10().search; @@ -52,6 +64,17 @@ class _SearchDisplayState extends RefreshableState { Timer? debounceTimer; + bool isSearching() { + + if (searchController.text.isEmpty) { + return false; + } + + return nSearchResults < 5; + } + + int nSearchResults = 0; + int nPartResults = 0; int nCategoryResults = 0; @@ -64,6 +87,8 @@ class _SearchDisplayState extends RefreshableState { int nPurchaseOrderResults = 0; + late FocusNode _focusNode; + // Callback when the text is being edited // Incorporates a debounce timer to restrict search frequency void onSearchTextChanged(String text, {bool immediate = false}) { @@ -79,72 +104,88 @@ class _SearchDisplayState extends RefreshableState { search(text); }); } - } + /* + * Initiate multiple search requests to the server. + * Each request returns at *some point* in the future, + * by which time the search input may have changed, giving unexpected results. + * + * So, each request only causes an update *if* the search term is still the same when it completes + */ Future search(String term) async { - if (term.isEmpty) { - setState(() { - // Do not search on an empty string - nPartResults = 0; - nCategoryResults = 0; - nStockResults = 0; - nLocationResults = 0; - nSupplierResults = 0; - nPurchaseOrderResults = 0; - }); + setState(() { + // Do not search on an empty string + nPartResults = 0; + nCategoryResults = 0; + nStockResults = 0; + nLocationResults = 0; + nSupplierResults = 0; + nPurchaseOrderResults = 0; + nSearchResults = 0; + }); + + if (term.isEmpty) { return; } // Search parts - InvenTreePart().count( - searchQuery: term - ).then((int n) { - setState(() { - nPartResults = n; - }); + InvenTreePart().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nPartResults = n; + nSearchResults++; + }); + } }); // Search part categories - InvenTreePartCategory().count( - searchQuery: term, - ).then((int n) { - setState(() { - nCategoryResults = n; - }); + InvenTreePartCategory().count(searchQuery: term,).then((int n) { + if (term == searchController.text) { + setState(() { + nCategoryResults = n; + nSearchResults++; + }); + } }); // Search stock items - InvenTreeStockItem().count( - searchQuery: term - ).then((int n) { - setState(() { - nStockResults = n; - }); + InvenTreeStockItem().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nStockResults = n; + nSearchResults++; + }); + } }); // Search stock locations - InvenTreeStockLocation().count( - searchQuery: term - ).then((int n) { - setState(() { - nLocationResults = n; - }); + InvenTreeStockLocation().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nLocationResults = n; + + nSearchResults++; + }); + } }); + // TDOO: Re-implement this once display for companies has been fixed + /* // Search suppliers - InvenTreeCompany().count( - searchQuery: term, + InvenTreeCompany().count(searchQuery: term, filters: { "is_supplier": "true", }, ).then((int n) { setState(() { nSupplierResults = n; + nSearchResults++; }); }); + */ // Search purchase orders InvenTreePurchaseOrder().count( @@ -153,9 +194,12 @@ class _SearchDisplayState extends RefreshableState { "outstanding": "true" } ).then((int n) { - setState(() { - nPurchaseOrderResults = n; - }); + if (term == searchController.text) { + setState(() { + nPurchaseOrderResults = n; + nSearchResults++; + }); + } }); } @@ -166,29 +210,31 @@ class _SearchDisplayState extends RefreshableState { // Search input tiles.add( - InputDecorator( + TextFormField( decoration: InputDecoration( - ), - child: ListTile( - title: TextField( - readOnly: false, - decoration: InputDecoration( - helperText: L10().queryEmpty, - ), - controller: searchController, - onChanged: (String text) { - onSearchTextChanged(text); - }, + hintText: L10().queryEmpty, + prefixIcon: IconButton( + icon: FaIcon(FontAwesomeIcons.search), + onPressed: null, ), - trailing: IconButton( + suffixIcon: IconButton( icon: FaIcon(FontAwesomeIcons.backspace, color: Colors.red), onPressed: () { searchController.clear(); onSearchTextChanged("", immediate: true); - }, + _focusNode.requestFocus(); + } ), - ) - ) + ), + readOnly: false, + autofocus: true, + autocorrect: false, + focusNode: _focusNode, + controller: searchController, + onChanged: (String text) { + onSearchTextChanged(text); + }, + ), ); String query = searchController.text; @@ -335,7 +381,17 @@ class _SearchDisplayState extends RefreshableState { ); } - if (results.isEmpty && searchController.text.isNotEmpty) { + if (isSearching()) { + tiles.add( + ListTile( + title: Text(L10().searching), + leading: FaIcon(FontAwesomeIcons.search), + trailing: CircularProgressIndicator(), + ) + ); + } + + if (!isSearching() && results.isEmpty && searchController.text.isNotEmpty) { tiles.add( ListTile( title: Text(L10().queryNoResults), @@ -348,8 +404,11 @@ class _SearchDisplayState extends RefreshableState { } } - return tiles; + if (!_focusNode.hasFocus) { + _focusNode.requestFocus(); + } + return tiles; } @override From cd9af13e2719e8e19b7c48e8cd4766fc58149a15 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 20 May 2022 23:34:02 +1000 Subject: [PATCH 125/746] Adds an initial unit test --- pubspec.lock | 196 +++++++++++++++++++++++++++++++++++++++--- pubspec.yaml | 7 +- test/api_test.dart | 45 ++++++++++ test/widget_test.dart | 6 +- 4 files changed, 234 insertions(+), 20 deletions(-) create mode 100644 test/api_test.dart diff --git a/pubspec.lock b/pubspec.lock index 4fb3ba9..a418a5b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "40.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" archive: dependency: transitive description: @@ -113,6 +127,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" cross_file: dependency: transitive description: @@ -190,13 +218,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" ffi: dependency: transitive description: @@ -263,11 +284,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.5" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter @@ -280,6 +296,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "9.2.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" http: dependency: "direct main" description: @@ -287,6 +317,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" http_parser: dependency: transitive description: @@ -336,6 +373,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -350,6 +394,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" markdown: dependency: transitive description: @@ -378,6 +429,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" octo_image: dependency: transitive description: @@ -399,6 +464,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.2.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" package_info_plus: dependency: "direct main" description: @@ -525,6 +597,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" process: dependency: transitive description: @@ -532,6 +611,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" qr_code_scanner: dependency: "direct main" description: @@ -630,6 +716,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -642,6 +756,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.5" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" source_span: dependency: transitive description: @@ -705,13 +833,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + test: + dependency: "direct dev" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.21.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.13" typed_data: dependency: transitive description: @@ -789,6 +931,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "8.3.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9031ea5..7489e15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,10 +38,9 @@ dependencies: url_launcher: ^6.0.9 # Open link in system browser dev_dependencies: - flutter_launcher_icons: - flutter_test: - sdk: flutter - lint: ^1.0.0 + flutter_launcher_icons: ^0.9.0 + lint: ^1.8.0 + test: ^1.21.0 flutter_icons: android: true diff --git a/test/api_test.dart b/test/api_test.dart new file mode 100644 index 0000000..36baa7f --- /dev/null +++ b/test/api_test.dart @@ -0,0 +1,45 @@ +/* + * Unit tests for the API class + */ + +import 'package:test/test.dart'; + +import 'package:inventree/api.dart'; +import 'package:inventree/user_profile.dart'; + +void main() { + + setUp(() async { + // Ensure we have a user profile available + // This profile will match the dockerized InvenTree setup, running locally + + print("Creating user profile"); + await UserProfileDBManager().addProfile(UserProfile( + username: "testuser", + password: "testpassword""", + server: "http://localhost:12345", + selected: true, + )); + + final profiles = await UserProfileDBManager().getAllProfiles(); + + // Ensure we have one profile available + expect(profiles.length, equals(1)); + + // Select the profile + await UserProfileDBManager().selectProfile(profiles.first.key ?? 1); + + }); + + test("Select Profile", () async { + // Ensure that we can select a user profile + final prf = await UserProfileDBManager().getSelectedProfile(); + + expect(prf, isNot(null)); + + expect(prf?.username, equals("testuser")); + expect(prf?.password, equals("testpassword")); + expect(prf?.server, equals("http://localhost:12345")); + }); + +} \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart index 3c73102..4e838ac 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,9 +5,9 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import "package:flutter_test/flutter_test.dart"; +// import "package:flutter_test/flutter_test.dart"; void main() { - testWidgets("Counter increments smoke test", (WidgetTester tester) async { - }); + // testWidgets("Counter increments smoke test", (WidgetTester tester) async { + // }); } From d898efdf6dc7631395cd1a68be8c79c4c3370237 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 20 May 2022 23:35:20 +1000 Subject: [PATCH 126/746] Rename github workflow --- .github/workflows/{lint.yaml => ci.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{lint.yaml => ci.yaml} (98%) diff --git a/.github/workflows/lint.yaml b/.github/workflows/ci.yaml similarity index 98% rename from .github/workflows/lint.yaml rename to .github/workflows/ci.yaml index 44b1ed3..dbbce59 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/ci.yaml @@ -1,6 +1,6 @@ # Run flutter linting checks -name: lint +name: CI on: push: From fe3c298f860b1f93572ad7b0ab7de1fbd6054eca Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 20 May 2022 23:37:55 +1000 Subject: [PATCH 127/746] Workflow updates --- .github/workflows/ci.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dbbce59..12dca6b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,12 +12,9 @@ on: jobs: - lint: + test: runs-on: ubuntu-latest - env: - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - steps: - name: Checkout code uses: actions/checkout@v2 From 96ae1be3ec2eadbe8d8f7bc04c8889820d318c16 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 20 May 2022 23:42:30 +1000 Subject: [PATCH 128/746] Add coveralls step --- .github/workflows/ci.yaml | 5 ++++- test/api_test.dart | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 12dca6b..456c715 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,4 +35,7 @@ jobs: - run: flutter pub get - run: cp lib/dummy_dsn.dart lib/dsn.dart - run: flutter analyze - - run: flutter test --coverage + - name: Run Unit Tests + run: | + flutter test --coverage + coveralls \ No newline at end of file diff --git a/test/api_test.dart b/test/api_test.dart index 36baa7f..5f24f89 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -2,18 +2,14 @@ * Unit tests for the API class */ -import 'package:test/test.dart'; - -import 'package:inventree/api.dart'; -import 'package:inventree/user_profile.dart'; +import "package:test/test.dart"; +import "package:inventree/user_profile.dart"; void main() { setUp(() async { // Ensure we have a user profile available // This profile will match the dockerized InvenTree setup, running locally - - print("Creating user profile"); await UserProfileDBManager().addProfile(UserProfile( username: "testuser", password: "testpassword""", From caa10b5f8fe255429180fc3af8afaa16c45c6711 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 20 May 2022 23:48:58 +1000 Subject: [PATCH 129/746] Add python requirements file --- .github/workflows/ci.yaml | 1 + requirements.txt | 4 ++++ test/api_test.dart | 26 ++++++++++++++++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 requirements.txt diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 456c715..90b2df3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,5 +37,6 @@ jobs: - run: flutter analyze - name: Run Unit Tests run: | + pip install -Ur requirements.txt flutter test --coverage coveralls \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..94f990c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# Python requirements for devops + +coverage==5.3 # Unit test coverage +coveralls==2.1.2 # Coveralls linking (for code coverage reporting) \ No newline at end of file diff --git a/test/api_test.dart b/test/api_test.dart index 5f24f89..1b5470b 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -27,15 +27,29 @@ void main() { }); - test("Select Profile", () async { + // Run a set of tests for user profile functionality + group("Profile Tests", () async { + + test("Profile Name Check", () async { + bool result = false; + + result = await UserProfileDBManager().profileNameExists("doesnotexist"); + expect(result, equals(false)); + + result = await UserProfileDBManager().profileNameExists("testuser"); + expect(result, equals(true)); + }); + // Ensure that we can select a user profile - final prf = await UserProfileDBManager().getSelectedProfile(); + test("Select Profile", () async { + final prf = await UserProfileDBManager().getSelectedProfile(); - expect(prf, isNot(null)); + expect(prf, isNot(null)); - expect(prf?.username, equals("testuser")); - expect(prf?.password, equals("testpassword")); - expect(prf?.server, equals("http://localhost:12345")); + expect(prf?.username, equals("testuser")); + expect(prf?.password, equals("testpassword")); + expect(prf?.server, equals("http://localhost:12345")); + }); }); } \ No newline at end of file From 00baff7a976e332bcedfad8a039f9747b615a99a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 00:26:09 +1000 Subject: [PATCH 130/746] All tests pass now --- lib/user_profile.dart | 91 +++++++++++++++++++++++++++---------------- test/api_test.dart | 71 ++++++++++++++++++++++++++++----- 2 files changed, 119 insertions(+), 43 deletions(-) diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 251aa30..507d9f0 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -62,68 +62,90 @@ class UserProfileDBManager { Future get _db async => InvenTreePreferencesDB.instance.database; + /* + * Check if a profile with the specified name exists in the database + */ Future profileNameExists(String name) async { - final finder = Finder(filter: Filter.equals("name", name)); + final profiles = await getAllProfiles(); - final profiles = await store.find(await _db, finder: finder); + for (var prf in profiles) { + if (name == prf.name) { + return true; + } + } - return profiles.isNotEmpty; + // No match found! + return false; } - Future addProfile(UserProfile profile) async { + /* + * Add a new UserProfile to the profiles database. + */ + Future addProfile(UserProfile profile) async { + + if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + print("Profile missing required values - not adding to database"); + return false; + } // Check if a profile already exists with the name final bool exists = await profileNameExists(profile.name); if (exists) { print("UserProfile '${profile.name}' already exists"); - return; + return false; } int key = await store.add(await _db, profile.toJson()) as int; - print("Added user profile <${key}> - '${profile.name}'"); - // Record the key profile.key = key; + + return true; } + /* + * Mark the particular profile as selected + */ Future selectProfile(int key) async { - /* - * Mark the particular profile as selected - */ - - final result = await store.record("selected").put(await _db, key); - - return result; + await store.record("selected").put(await _db, key); } - - Future updateProfile(UserProfile profile) async { - - if (profile.key == null) { - await addProfile(profile); - return; + + /* + * Update the selected profile in the database. + * The unique integer is used to determine if the profile already exists. + */ + Future updateProfile(UserProfile profile) async { + + // Prevent invalid profile data from being updated + if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + print("Profile missing required values - not updating"); + return false; } - final result = await store.record(profile.key).update(await _db, profile.toJson()); + if (profile.key == null) { + bool result = await addProfile(profile); + return result; + } - print("Updated user profile <${profile.key}> - '${profile.name}'"); + await store.record(profile.key).update(await _db, profile.toJson()); - return result; + return true; } + /* + * Remove a user profile from the database + */ Future deleteProfile(UserProfile profile) async { await store.record(profile.key).delete(await _db); - print("Deleted user profile <${profile.key}> - '${profile.name}'"); } + /* + * Return the currently selected profile. + * The key of the UserProfile should match the "selected" property + */ Future getSelectedProfile() async { - /* - * Return the currently selected profile. - * - * key should match the "selected" property - */ final selected = await store.record("selected").get(await _db); @@ -158,11 +180,12 @@ class UserProfileDBManager { if (profiles[idx].key is int) { profileList.add( - UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, - profiles[idx].key == selected, - )); + UserProfile.fromJson( + profiles[idx].key as int, + profiles[idx].value as Map, + profiles[idx].key == selected, + ) + ); } } diff --git a/test/api_test.dart b/test/api_test.dart index 1b5470b..928c402 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -10,33 +10,85 @@ void main() { setUp(() async { // Ensure we have a user profile available // This profile will match the dockerized InvenTree setup, running locally - await UserProfileDBManager().addProfile(UserProfile( + + // To start with, there should not be *any* profiles available + var profiles = await UserProfileDBManager().getAllProfiles(); + + for (var prf in profiles) { + UserProfileDBManager().deleteProfile(prf); + } + + // Check that there are *no* profiles in the database + profiles = await UserProfileDBManager().getAllProfiles(); + expect(profiles.length, equals(0)); + + // Now, create one! + bool result = await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", username: "testuser", password: "testpassword""", server: "http://localhost:12345", selected: true, )); - final profiles = await UserProfileDBManager().getAllProfiles(); + expect(result, equals(true)); // Ensure we have one profile available + // expect(profiles.length, equals(1)); + profiles = await UserProfileDBManager().getAllProfiles(); + expect(profiles.length, equals(1)); - // Select the profile - await UserProfileDBManager().selectProfile(profiles.first.key ?? 1); + int key = -1; + // Find the first available profile + for (var p in profiles) { + if (p.key != null) { + key = p.key ?? key; + break; + } + } + + // Select the profile + await UserProfileDBManager().selectProfile(key); }); // Run a set of tests for user profile functionality - group("Profile Tests", () async { + group("Profile Tests:", () { - test("Profile Name Check", () async { - bool result = false; + test("Add Invalid Profiles", () async { + // Add a profile with missing data + bool result = await UserProfileDBManager().addProfile( + UserProfile( + username: "what", + password: "why", + ) + ); - result = await UserProfileDBManager().profileNameExists("doesnotexist"); expect(result, equals(false)); - result = await UserProfileDBManager().profileNameExists("testuser"); + // Add a profile with a name that already exists + result = await UserProfileDBManager().addProfile( + UserProfile( + name: "Test Profile", + username: "xyz", + password: "hunter42", + ) + ); + + expect(result, equals(false)); + + // Check that the number of protocols available is still the same + var profiles = await UserProfileDBManager().getAllProfiles(); + + expect(profiles.length, equals(1)); + }); + + test("Profile Name Check", () async { + bool result = await UserProfileDBManager().profileNameExists("doesnotexist"); + expect(result, equals(false)); + + result = await UserProfileDBManager().profileNameExists("Test Profile"); expect(result, equals(true)); }); @@ -46,6 +98,7 @@ void main() { expect(prf, isNot(null)); + expect(prf?.name, equals("Test Profile")); expect(prf?.username, equals("testuser")); expect(prf?.password, equals("testpassword")); expect(prf?.server, equals("http://localhost:12345")); From b8d413027032a1e15d6293393a4bd2818c62f093 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 00:30:56 +1000 Subject: [PATCH 131/746] Adds tests for the "updateProfile" function --- test/api_test.dart | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/api_test.dart b/test/api_test.dart index 928c402..9c28f71 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -92,16 +92,31 @@ void main() { expect(result, equals(true)); }); - // Ensure that we can select a user profile test("Select Profile", () async { + // Ensure that we can select a user profile final prf = await UserProfileDBManager().getSelectedProfile(); expect(prf, isNot(null)); - expect(prf?.name, equals("Test Profile")); - expect(prf?.username, equals("testuser")); - expect(prf?.password, equals("testpassword")); - expect(prf?.server, equals("http://localhost:12345")); + if (prf != null) { + UserProfile p = prf; + + expect(p.name, equals("Test Profile")); + expect(p.username, equals("testuser")); + expect(p.password, equals("testpassword")); + expect(p.server, equals("http://localhost:12345")); + + // Test that we can update the profile + p.name = "different name"; + + bool result = await UserProfileDBManager().updateProfile(p); + expect(result, equals(true)); + + // Trying to update with an invalid value will fail! + p.password = ""; + result = await UserProfileDBManager().updateProfile(p); + expect(result, equals(false)); + } }); }); From 80d898e212f80474d70b0d694a90aa8e78325483 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 00:39:05 +1000 Subject: [PATCH 132/746] Add github token secret --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 90b2df3..184740c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,6 +10,9 @@ on: branches: - master +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + jobs: test: From 237a7da54a293cd4d283ad9253e1c219b7e971ee Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 00:44:07 +1000 Subject: [PATCH 133/746] Add .coveragerc file --- .coveragerc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..8c4a4b7 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +source = ./lib \ No newline at end of file From 6ef95499b78e919546707696680c13a6651aa3b8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 19:27:44 +1000 Subject: [PATCH 134/746] Add genhtml step --- .github/workflows/ci.yaml | 2 + lib/app_settings.dart | 68 ---------------------------------- lib/preferences.dart | 76 ++++++++++++++++++++++++++++---------- test/preferences_test.dart | 21 +++++++++++ 4 files changed, 80 insertions(+), 87 deletions(-) delete mode 100644 lib/app_settings.dart create mode 100644 test/preferences_test.dart diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 184740c..dbf1d5b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,6 +40,8 @@ jobs: - run: flutter analyze - name: Run Unit Tests run: | + apt-get install lcov pip install -Ur requirements.txt flutter test --coverage + genhtml coverage/lcov.info -o coverage/html coveralls \ No newline at end of file diff --git a/lib/app_settings.dart b/lib/app_settings.dart deleted file mode 100644 index e009b78..0000000 --- a/lib/app_settings.dart +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Class for managing app-level configuration options - */ - -import "package:sembast/sembast.dart"; -import "package:inventree/preferences.dart"; - -// Settings key values -const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; -const String INV_HOME_SHOW_PO = "homeShowPo"; -const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; -const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; -const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; - -const String INV_SOUNDS_BARCODE = "barcodeSounds"; -const String INV_SOUNDS_SERVER = "serverSounds"; - -const String INV_PART_SUBCATEGORY = "partSubcategory"; - -const String INV_STOCK_SUBLOCATION = "stockSublocation"; -const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; - -const String INV_REPORT_ERRORS = "reportErrors"; - -const String INV_STRICT_HTTPS = "strictHttps"; - -class InvenTreeSettingsManager { - - factory InvenTreeSettingsManager() { - return _manager; - } - - InvenTreeSettingsManager._internal(); - - final store = StoreRef("settings"); - - Future get _db async => InvenTreePreferencesDB.instance.database; - - Future getValue(String key, dynamic backup) async { - - final value = await store.record(key).get(await _db); - - if (value == null) { - return backup; - } - - return value; - } - - // Load a boolean setting - Future getBool(String key, bool backup) async { - final dynamic value = await getValue(key, backup); - - if (value is bool) { - return value; - } else { - return backup; - } - } - - Future setValue(String key, dynamic value) async { - - await store.record(key).put(await _db, value); - } - - // Ensure we only ever create a single instance of this class - static final InvenTreeSettingsManager _manager = InvenTreeSettingsManager._internal(); -} diff --git a/lib/preferences.dart b/lib/preferences.dart index 2c52a88..961a16b 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -6,6 +6,26 @@ import "package:sembast/sembast_io.dart"; import "package:path/path.dart"; +// Settings key values +const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; +const String INV_HOME_SHOW_PO = "homeShowPo"; +const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; +const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; +const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; + +const String INV_SOUNDS_BARCODE = "barcodeSounds"; +const String INV_SOUNDS_SERVER = "serverSounds"; + +const String INV_PART_SUBCATEGORY = "partSubcategory"; + +const String INV_STOCK_SUBLOCATION = "stockSublocation"; +const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; + +const String INV_REPORT_ERRORS = "reportErrors"; + +const String INV_STRICT_HTTPS = "strictHttps"; + + /* * Class for storing InvenTree preferences in a NoSql DB */ @@ -54,32 +74,50 @@ class InvenTreePreferencesDB { } } -class InvenTreePreferences { - factory InvenTreePreferences() { - return _api; +/* + * InvenTree setings manager class. + * Provides functions for loading and saving settings, with provision for default values + */ +class InvenTreeSettingsManager { + + factory InvenTreeSettingsManager() { + return _manager; } - InvenTreePreferences._internal(); + InvenTreeSettingsManager._internal(); - /* The following settings are not stored to persistent storage, - * instead they are only used as "session preferences". - * They are kept here as a convenience only. - */ + final store = StoreRef("settings"); - // Expand subcategory list in PartCategory view - bool expandCategoryList = false; + Future get _db async => InvenTreePreferencesDB.instance.database; - // Expand part list in PartCategory view - bool expandPartList = true; + Future getValue(String key, dynamic backup) async { - // Expand sublocation list in StockLocation view - bool expandLocationList = false; + final value = await store.record(key).get(await _db); - // Expand item list in StockLocation view - bool expandStockList = true; + if (value == null) { + return backup; + } - // Ensure we only ever create a single instance of the preferences class - static final InvenTreePreferences _api = InvenTreePreferences._internal(); + return value; + } -} \ No newline at end of file + // Load a boolean setting + Future getBool(String key, bool backup) async { + final dynamic value = await getValue(key, backup); + + if (value is bool) { + return value; + } else { + return backup; + } + } + + Future setValue(String key, dynamic value) async { + + await store.record(key).put(await _db, value); + } + + // Ensure we only ever create a single instance of this class + static final InvenTreeSettingsManager _manager = InvenTreeSettingsManager._internal(); +} diff --git a/test/preferences_test.dart b/test/preferences_test.dart new file mode 100644 index 0000000..cca8018 --- /dev/null +++ b/test/preferences_test.dart @@ -0,0 +1,21 @@ +/* + * Unit tests for the preferences manager + */ + +import "package:test/test.dart"; +import "package:inventree/preferences.dart"; + +void main() { + + setUp(() async { + + }); + + group("Settings Tests:", () { + test("Default Values", () async { + // Boolean values + expect(await InvenTreeSettingsManager().getBool("test", false), equals(false)); + expect(await InvenTreeSettingsManager().getBool("test", true), equals(true)); + }); + }); +} \ No newline at end of file From a42c1dc8863932844fbb8445f76e88ca519a2359 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 19:30:23 +1000 Subject: [PATCH 135/746] Reduce CI actions --- .github/workflows/android.yaml | 3 --- .github/workflows/ci.yaml | 2 +- .github/workflows/ios.yaml | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index a9d4940..4199cf2 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -6,9 +6,6 @@ on: push: branches: - master - pull_request: - branches: - - master jobs: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dbf1d5b..d8b9709 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -44,4 +44,4 @@ jobs: pip install -Ur requirements.txt flutter test --coverage genhtml coverage/lcov.info -o coverage/html - coveralls \ No newline at end of file + coveralls diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 039a6e9..3dc6338 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -6,9 +6,6 @@ on: push: branches: - master - pull_request: - branches: - - master jobs: From df4845044065e984b39d29c079a50fd259eb26dd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 19:33:01 +1000 Subject: [PATCH 136/746] Use coveralls github action --- .github/workflows/ci.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d8b9709..962e9ae 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,13 +35,14 @@ jobs: run: | cd lib/l10n python3 collect_translations.py - - run: flutter pub get - - run: cp lib/dummy_dsn.dart lib/dsn.dart - - run: flutter analyze - name: Run Unit Tests run: | - apt-get install lcov - pip install -Ur requirements.txt + cp lib/dummy_dsn.dart lib/dsn.dart + flutter pub get + flutter analyze flutter test --coverage - genhtml coverage/lcov.info -o coverage/html - coveralls + + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From b18dd9207979f4353e5132a9c3365ad880cd6b3a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 19:44:47 +1000 Subject: [PATCH 137/746] Fixes after preferences file refactor --- lib/api.dart | 2 +- lib/helpers.dart | 3 ++- lib/inventree/sentry.dart | 2 +- lib/settings/app_settings.dart | 2 +- lib/settings/home_settings.dart | 2 +- lib/widget/dialogs.dart | 8 ++++---- lib/widget/home.dart | 2 +- lib/widget/part_list.dart | 2 +- lib/widget/stock_detail.dart | 2 +- lib/widget/stock_list.dart | 2 +- 10 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 9994b65..99d005d 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -6,7 +6,7 @@ import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; import "package:intl/intl.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:open_file/open_file.dart"; import "package:cached_network_image/cached_network_image.dart"; diff --git a/lib/helpers.dart b/lib/helpers.dart index 524cd92..85d550a 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -8,7 +8,8 @@ */ import "package:audioplayers/audioplayers.dart"; -import "package:inventree/app_settings.dart"; + +import "package:inventree/preferences.dart"; String simpleNumberString(double number) { // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 429a50a..cd05a14 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,7 +1,7 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 124246d..f322bf7 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -3,7 +3,7 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/l10.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class InvenTreeAppSettingsWidget extends StatefulWidget { diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index c5776c6..13e19cd 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -5,7 +5,7 @@ import "package:inventree/l10.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class HomeScreenSettingsWidget extends StatefulWidget { @override diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 357983b..e6b3bfb 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -1,12 +1,12 @@ - -import "package:inventree/app_settings.dart"; -import "package:inventree/widget/snacks.dart"; import "package:audioplayers/audioplayers.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/l10.dart"; import "package:one_context/one_context.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; +import "package:inventree/widget/snacks.dart"; + Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 64c566d..290c866 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -6,7 +6,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/login.dart"; diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index ca4d158..528273f 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -6,7 +6,7 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/api.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/l10.dart"; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index b0b3cda..b742cfb 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -22,7 +22,7 @@ import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class StockDetailWidget extends StatefulWidget { diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index 09d0dc3..90481c7 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -5,7 +5,7 @@ import "package:inventree/inventree/stock.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/stock_detail.dart"; import "package:inventree/api.dart"; From 6b0fd2a7083f63e78f4cdca16219a2fdb1918e14 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:03:48 +1000 Subject: [PATCH 138/746] Add script to find and test all un-touched .dart files --- .github/workflows/ci.yaml | 1 + .gitignore | 3 +++ find_dart_files.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 find_dart_files.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 962e9ae..14f6345 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,6 +38,7 @@ jobs: - name: Run Unit Tests run: | cp lib/dummy_dsn.dart lib/dsn.dart + python3 find_dart_files.py flutter pub get flutter analyze flutter test --coverage diff --git a/.gitignore b/.gitignore index 2f25898..a9ecf32 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ coverage/* +# This file is auto-generated as part of the CI process +test/test_touch_files.dart + # Sentry API key lib/dsn.dart diff --git a/find_dart_files.py b/find_dart_files.py new file mode 100644 index 0000000..338ed89 --- /dev/null +++ b/find_dart_files.py @@ -0,0 +1,35 @@ +""" +This script recursively finds any '.dart' files in the ./lib directory, +and generates a 'test' file which includes all these files. + +This is to ensure that *all* .dart files are included in test coverage. +By default, source files which are not touched by the unit tests are not included! + +Ref: https://github.com/flutter/flutter/issues/27997#issue-410722816 +""" + +from pathlib import Path + +if __name__ == '__main__': + + dart_files = Path('lib').rglob('*.dart') + + with open("test/test_touch_files.dart", "w") as f: + + f.write("// ignore_for_file: unused_import\n\n") + + for path in dart_files: + path = str(path) + # Remove leading 'lib\' text + path = path[4:] + path = path.replace('\\', '/') + f.write(f'import "package:inventree/{path}";\n') + + f.write("\n\n") + + f.write("// DO NOT EDIT THIS FILE - it has been auto-generated by 'find_dart_files.py'\n") + f.write("// It has been created to ensure that *all* source file are included in coverage data\n") + f.write("// Reference: https://github.com/flutter/flutter/issues/27997#issue-410722816\n\n") + + f.write("// Do not actually test anything!") + f.write("void main() {}\n") From 12828e47f92048cbf2baef5485e00c9b9b1a7668 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:12:01 +1000 Subject: [PATCH 139/746] Had commented out the line that actually did anything... --- find_dart_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/find_dart_files.py b/find_dart_files.py index 338ed89..614c3d6 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -31,5 +31,5 @@ if __name__ == '__main__': f.write("// It has been created to ensure that *all* source file are included in coverage data\n") f.write("// Reference: https://github.com/flutter/flutter/issues/27997#issue-410722816\n\n") - f.write("// Do not actually test anything!") + f.write("// Do not actually test anything!\n") f.write("void main() {}\n") From 31325f4893465414d469679e565c09caa9b3c63f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:24:31 +1000 Subject: [PATCH 140/746] File name is apparently important... --- .coveragerc | 2 -- .gitignore | 2 +- find_dart_files.py | 7 ++++--- 3 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 8c4a4b7..0000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[run] -source = ./lib \ No newline at end of file diff --git a/.gitignore b/.gitignore index a9ecf32..07101c9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ coverage/* # This file is auto-generated as part of the CI process -test/test_touch_files.dart +test/coverage_helper_test.dart # Sentry API key lib/dsn.dart diff --git a/find_dart_files.py b/find_dart_files.py index 614c3d6..ca20e01 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -5,7 +5,7 @@ and generates a 'test' file which includes all these files. This is to ensure that *all* .dart files are included in test coverage. By default, source files which are not touched by the unit tests are not included! -Ref: https://github.com/flutter/flutter/issues/27997#issue-410722816 +Ref: https://github.com/flutter/flutter/issues/27997 """ from pathlib import Path @@ -14,7 +14,7 @@ if __name__ == '__main__': dart_files = Path('lib').rglob('*.dart') - with open("test/test_touch_files.dart", "w") as f: + with open("test/coverage_helper_test.dart", "w") as f: f.write("// ignore_for_file: unused_import\n\n") @@ -29,7 +29,8 @@ if __name__ == '__main__': f.write("// DO NOT EDIT THIS FILE - it has been auto-generated by 'find_dart_files.py'\n") f.write("// It has been created to ensure that *all* source file are included in coverage data\n") - f.write("// Reference: https://github.com/flutter/flutter/issues/27997#issue-410722816\n\n") + + f.write('import "package:test/test.dart";\n\n'); f.write("// Do not actually test anything!\n") f.write("void main() {}\n") From ee3b7502dc821f57d45fd5c0674d59edd6b6ba06 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:30:00 +1000 Subject: [PATCH 141/746] Skip some files --- find_dart_files.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/find_dart_files.py b/find_dart_files.py index ca20e01..c7397c6 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -18,8 +18,18 @@ if __name__ == '__main__': f.write("// ignore_for_file: unused_import\n\n") + skips = [ + 'generated', + 'l10n', + 'dummy_dsn.dart', + ] + for path in dart_files: path = str(path) + + if any([s in path for s in skips]): + continue + # Remove leading 'lib\' text path = path[4:] path = path.replace('\\', '/') From 253a75129aa8351f63e9a4d580bfcea67b6c6c2e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:41:03 +1000 Subject: [PATCH 142/746] Extra tests --- test/preferences_test.dart | 9 +++++++++ test/{api_test.dart => user_profile_test.dart} | 2 ++ 2 files changed, 11 insertions(+) rename test/{api_test.dart => user_profile_test.dart} (96%) diff --git a/test/preferences_test.dart b/test/preferences_test.dart index cca8018..b402b7a 100644 --- a/test/preferences_test.dart +++ b/test/preferences_test.dart @@ -16,6 +16,15 @@ void main() { // Boolean values expect(await InvenTreeSettingsManager().getBool("test", false), equals(false)); expect(await InvenTreeSettingsManager().getBool("test", true), equals(true)); + + // String values + expect(await InvenTreeSettingsManager().getValue("test", "x"), equals("x")); + }); + + test("Set value", () async { + await InvenTreeSettingsManager().setValue("abc", "xyz"); + + expect(await InvenTreeSettingsManager().getValue("abc", "123"), equals("xyz")); }); }); } \ No newline at end of file diff --git a/test/api_test.dart b/test/user_profile_test.dart similarity index 96% rename from test/api_test.dart rename to test/user_profile_test.dart index 9c28f71..5de1043 100644 --- a/test/api_test.dart +++ b/test/user_profile_test.dart @@ -106,6 +106,8 @@ void main() { expect(p.password, equals("testpassword")); expect(p.server, equals("http://localhost:12345")); + expect(p.toString(), equals("<${p.key}> Test Profile : http://localhost:12345 - testuser:testpassword")); + // Test that we can update the profile p.name = "different name"; From 63dd081a1c760dbaf0add841e58853cc53609749 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 20:49:32 +1000 Subject: [PATCH 143/746] Test fix? --- test/user_profile_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 5de1043..9b672ad 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -15,7 +15,7 @@ void main() { var profiles = await UserProfileDBManager().getAllProfiles(); for (var prf in profiles) { - UserProfileDBManager().deleteProfile(prf); + await UserProfileDBManager().deleteProfile(prf); } // Check that there are *no* profiles in the database From 62b0fcbec5b7a04b65e82ca40d1c05839db338bc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 21 May 2022 21:03:43 +1000 Subject: [PATCH 144/746] Start InvenTree server --- .github/workflows/ci.yaml | 29 +++++++++++++++++++++++++---- find_dart_files.py | 2 +- lib/app_colors.dart | 2 -- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 14f6345..f3ae7c7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,5 +1,3 @@ -# Run flutter linting checks - name: CI on: @@ -12,7 +10,16 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + INVENTREE_DB_ENGINE: django.db.backends.sqlite3 + INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3 + INVENTREE_MEDIA_ROOT: ../test_inventree_media + INVENTREE_STATIC_ROOT: ../test_inventree_static + INVENTREE_ADMIN_USER: testuser + INVENTREE_ADMIN_PASSWORD: testpassword + INVENTREE_ADMIN_EMAIL: test@test.com + INVENTREE_PYTHON_TEST_SERVER: http://localhost:12345 + INVENTREE_PYTHON_TEST_USERNAME: testuser + INVENTREE_PYTHON_TEST_PASSWORD: testpassword jobs: test: @@ -35,12 +42,26 @@ jobs: run: | cd lib/l10n python3 collect_translations.py - - name: Run Unit Tests + - name: Static Analysis Tests run: | cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get flutter analyze + + - name: Start InvenTree Server + run: | + sudo apt-get install python3-dev python3-pip python3-venv python3-wheel g++ + pip3 install invoke + git clone --depth 1 https://github.com/inventree/inventree ./inventree_server + cd inventree_server + invoke install + invoke migrate + invoke import-fixtures + invoke server -a 127.0.0.1:12345 & + invoke wait + - name: Unit Tests + run: | flutter test --coverage - name: Coveralls diff --git a/find_dart_files.py b/find_dart_files.py index c7397c6..a182daa 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -21,7 +21,7 @@ if __name__ == '__main__': skips = [ 'generated', 'l10n', - 'dummy_dsn.dart', + 'dsn.dart', ] for path in dart_files: diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 99d8138..2f0395f 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -1,5 +1,3 @@ - - import "dart:ui"; const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1); From e424a3cf7bc736d732f04f21514b96ffb30cf1dc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 00:02:27 +1000 Subject: [PATCH 145/746] Start of unit tests for the actual API code --- lib/api.dart | 4 ++- lib/l10.dart | 14 ++++++----- lib/widget/snacks.dart | 18 ++++++-------- pubspec.lock | 33 +++++++++++++++++++------ pubspec.yaml | 30 +++-------------------- test/api_test.dart | 55 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 51 deletions(-) create mode 100644 test/api_test.dart diff --git a/lib/api.dart b/lib/api.dart index 99d005d..4d42be0 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -201,6 +201,8 @@ class InvenTreeAPI { // Authentication token (initially empty, must be requested) String _token = ""; + bool get hasToken => _token.isNotEmpty; + /* * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. @@ -278,7 +280,7 @@ class InvenTreeAPI { bool _connecting = false; bool isConnected() { - return profile != null && _connected && baseUrl.isNotEmpty && _token.isNotEmpty; + return profile != null && _connected && baseUrl.isNotEmpty && hasToken; } bool isConnecting() { diff --git a/lib/l10.dart b/lib/l10.dart index ce9f319..2b44f96 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -7,16 +7,18 @@ import "package:flutter/material.dart"; // Shortcut function to reduce boilerplate! I18N L10() { - BuildContext? _ctx = OneContext().context; + if (OneContext.hasContext) { + BuildContext? _ctx = OneContext().context; - if (_ctx != null) { - I18N? i18n = I18N.of(_ctx); + if (_ctx != null) { + I18N? i18n = I18N.of(_ctx); - if (i18n != null) { - return i18n; + if (i18n != null) { + return i18n; + } } } // Fallback for "null" context - return I18NEn(); + return I18NEn(); } \ No newline at end of file diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index e6ee864..f578deb 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -1,21 +1,19 @@ - -/* - * Display a snackbar with: - * - * a) Text on the left - * b) Icon on the right - * - * | Text | - */ - import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; +/* + * Display a configurable 'snackbar' at the bottom of the screen + */ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? success, String? actionText}) { + // Escape quickly if we do not have context + if (!OneContext.hasContext) { + return; + } + BuildContext? context = OneContext().context; if (context != null) { diff --git a/pubspec.lock b/pubspec.lock index a418a5b..0f7c12f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "40.0.0" + version: "31.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "2.8.0" archive: dependency: transitive description: @@ -113,6 +113,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -140,7 +147,7 @@ packages: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.0.3" cross_file: dependency: transitive description: @@ -218,6 +225,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" ffi: dependency: transitive description: @@ -284,6 +298,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.5" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter @@ -839,21 +858,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.21.1" + version: "1.19.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.8" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.13" + version: "0.4.9" typed_data: dependency: transitive description: @@ -937,7 +956,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "8.3.0" + version: "7.5.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7489e15..59c3e66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,9 @@ dependencies: dev_dependencies: flutter_launcher_icons: ^0.9.0 lint: ^1.8.0 - test: ^1.21.0 + test: ^1.19.0 + flutter_test: + sdk: flutter flutter_icons: android: true @@ -63,29 +65,3 @@ flutter: - assets/sounds/barcode_scan.mp3 - assets/sounds/barcode_error.mp3 - assets/sounds/server_error.mp3 - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, 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 from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test/api_test.dart b/test/api_test.dart new file mode 100644 index 0000000..0841e7e --- /dev/null +++ b/test/api_test.dart @@ -0,0 +1,55 @@ +/* + * Unit tests for the InvenTree API code + */ + +import "package:test/test.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/user_profile.dart"; + + + +void main() { + + setUp(() async { + + // Create and select a profile to user + await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", + server: "http://localhost:12345", + username: "testuser", + password: "testpassword", + selected: true, + )); + + }); + + group("Login Tests:", () { + + test("Disconnected", () async { + // Test that calling disconnect() does the right thing + var api = InvenTreeAPI(); + + api.disconnectFromServer(); + + // Check expected values + expect(api.isConnected(), equals(false)); + expect(api.isConnecting(), equals(false)); + expect(api.hasToken, equals(false)); + + }); + + test("Login Success", () async { + // Test that we can login to the server successfully + var api = InvenTreeAPI(); + + // Attempt to connect + final bool result = await api.connectToServer(); + + expect(result, equals(true)); + expect(api.hasToken, equals(true)); + + expect(api.baseUrl, equals("http://localhost:12345/")); + }); + }); +} \ No newline at end of file From c453aaaf8ac090fb2c6e8587fa1edb53826d19a3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 22 May 2022 06:39:34 +1000 Subject: [PATCH 146/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 4075b80..da16480 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -545,6 +545,8 @@ "@search": { "description": "search" }, + "searching": "Keresés", + "@searching": {}, "searchLocation": "Hely keresése", "@searchLocation": {}, "searchParts": "Alkatrészek keresése", From f13b04d02985bf668e17fd59672ffef3a203db30 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 08:23:20 +1000 Subject: [PATCH 147/746] Refactor audio file player - Do not play if there is no context available (e.g. unit testing) --- lib/api_form.dart | 2 +- lib/barcode.dart | 69 ++++++++++++++++++++++++------------ lib/helpers.dart | 32 ++++++++--------- lib/widget/dialogs.dart | 5 ++- lib/widget/stock_detail.dart | 3 +- pubspec.yaml | 4 +-- test/api_test.dart | 29 ++++++++++++++- 7 files changed, 94 insertions(+), 50 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 07221a1..588658b 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -335,7 +335,7 @@ class APIFormField { controller.text = hash; data["value"] = hash; - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeAssigned, diff --git a/lib/barcode.dart b/lib/barcode.dart index 8781f2d..85702e0 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -11,15 +11,38 @@ import "package:qr_code_scanner/qr_code_scanner.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/stock_detail.dart"; +/* + * Play an audible 'success' alert to the user. + */ +Future barcodeSuccessTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_scan.mp3"); + } +} + +Future barcodeFailureTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_error.mp3"); + } +} + + class BarcodeHandler { /* * Class which "handles" a barcode, by communicating with the InvenTree server, @@ -44,7 +67,7 @@ class BarcodeHandler { // Called when the server does not know about a barcode // Override this function - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeNoMatch, @@ -55,7 +78,7 @@ class BarcodeHandler { Future onBarcodeUnhandled(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); // Called when the server returns an unhandled response showServerError(L10().responseUnknown, data.toString()); @@ -125,7 +148,7 @@ class BarcodeScanHandler extends BarcodeHandler { @override Future onBarcodeUnknown(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeNoMatch, @@ -146,7 +169,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreeStockLocation().get(pk).then((var loc) { if (loc is InvenTreeStockLocation) { @@ -156,7 +179,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockLocation, @@ -170,7 +193,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreeStockItem().get(pk).then((var item) { @@ -183,7 +206,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockItem, @@ -196,7 +219,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreePart().get(pk).then((var part) { @@ -209,7 +232,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidPart, @@ -218,7 +241,7 @@ class BarcodeScanHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeUnknown, @@ -275,7 +298,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { if (result) { - successTone(); + barcodeSuccessTone(); Navigator.of(context).pop(); @@ -285,7 +308,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { ); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeScanIntoLocationFailure, @@ -294,7 +317,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockLocation, @@ -329,14 +352,14 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { if (item == null) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockItem, success: false, ); } else if (item.locationId == location.pk) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().itemInLocation, @@ -347,7 +370,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { if (result) { - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeScanIntoLocationSuccess, @@ -355,7 +378,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { ); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeScanIntoLocationFailure, @@ -365,7 +388,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); // Does not match a valid stock item! showSnackIcon( @@ -401,7 +424,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); // If the barcode is known, we can"t assign it to the stock item! showSnackIcon( @@ -424,7 +447,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { String hash = (data["hash"] ?? "") as String; if (hash.isEmpty) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeError, @@ -432,7 +455,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { ); } else { - successTone(); + barcodeSuccessTone(); // Close the barcode scanner Navigator.of(context).pop(); diff --git a/lib/helpers.dart b/lib/helpers.dart index 85d550a..2bdbed5 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -8,8 +8,7 @@ */ import "package:audioplayers/audioplayers.dart"; - -import "package:inventree/preferences.dart"; +import "package:one_context/one_context.dart"; String simpleNumberString(double number) { // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart @@ -17,22 +16,19 @@ String simpleNumberString(double number) { return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1); } -Future successTone() async { +/* + * Play an audio file from the requested path. + * + * Note: If OneContext module fails the 'hasConext' check, + * we will not attempt to play the sound + */ +Future playAudioFile(String path) async { - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - final player = AudioCache(); - player.play("sounds/barcode_scan.mp3"); + if (!OneContext.hasContext) { + return; } + + final player = AudioCache(); + player.play(path); + } - -Future failureTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - final player = AudioCache(); - player.play("sounds/barcode_error.mp3"); - } -} \ No newline at end of file diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index e6b3bfb..5fbe20b 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -1,6 +1,6 @@ -import "package:audioplayers/audioplayers.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/helpers.dart"; import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; @@ -108,8 +108,7 @@ Future showServerError(String title, String description) async { final bool tones = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; if (tones) { - final player = AudioCache(); - player.play("sounds/server_error.mp3"); + playAudioFile("sounds/server_error.mp3"); } showSnackIcon( diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index b742cfb..5010779 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -19,7 +19,6 @@ import "package:inventree/widget/stock_item_history.dart"; import "package:inventree/widget/stock_item_test_results.dart"; import "package:inventree/widget/stock_notes.dart"; import "package:inventree/l10.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; import "package:inventree/preferences.dart"; @@ -1008,7 +1007,7 @@ class _StockItemDisplayState extends RefreshableState { } ).then((result) { if (result) { - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeAssigned, diff --git a/pubspec.yaml b/pubspec.yaml index 59c3e66..33932d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,10 +39,10 @@ dependencies: dev_dependencies: flutter_launcher_icons: ^0.9.0 - lint: ^1.8.0 - test: ^1.19.0 flutter_test: sdk: flutter + lint: ^1.8.0 + test: ^1.19.0 flutter_icons: android: true diff --git a/test/api_test.dart b/test/api_test.dart index 0841e7e..4631c5c 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -39,6 +39,30 @@ void main() { }); + test("Login Failure", () async { + // Tests for various types of login failures + var api = InvenTreeAPI(); + + // Incorrect server address + var profile = await UserProfileDBManager().getSelectedProfile(); + + assert(profile != null); + + if (profile != null) { + profile.server = "http://localhost:5555"; + await UserProfileDBManager().updateProfile(profile); + } + + bool result = await api.connectToServer(); + + assert(!result); + + // TODO: Test the the right 'error message' is returned + + // TODO: Test incorrect login details + + }); + test("Login Success", () async { // Test that we can login to the server successfully var api = InvenTreeAPI(); @@ -46,10 +70,13 @@ void main() { // Attempt to connect final bool result = await api.connectToServer(); + // Check expected values expect(result, equals(true)); expect(api.hasToken, equals(true)); - expect(api.baseUrl, equals("http://localhost:12345/")); + + expect(api.isConnected(), equals(true)); + expect(api.isConnecting(), equals(false)); }); }); } \ No newline at end of file From fc911ea5b5932ab8b89b6d90e964d964765b79ec Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 08:27:01 +1000 Subject: [PATCH 148/746] Server connection check passes now --- test/api_test.dart | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/test/api_test.dart b/test/api_test.dart index 4631c5c..8a4195a 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -10,17 +10,32 @@ import "package:inventree/user_profile.dart"; void main() { - + setUp(() async { - - // Create and select a profile to user - await UserProfileDBManager().addProfile(UserProfile( - name: "Test Profile", - server: "http://localhost:12345", - username: "testuser", - password: "testpassword", - selected: true, - )); + + if (! await UserProfileDBManager().profileNameExists("Test Profile")) { + // Create and select a profile to user + await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", + server: "http://localhost:12345", + username: "testuser", + password: "testpassword", + selected: true, + )); + } + + var prf = await UserProfileDBManager().getSelectedProfile(); + + // Ensure that the server settings are correct by default, + // as they can get overwritten by subsequent tests + + if (prf != null) { + prf.server = "http://localhost:12345"; + prf.username = "testuser"; + prf.password = "testpassword"; + + await UserProfileDBManager().updateProfile(prf); + } }); From cdeac137bf8bebf3130607bf4fa317041ced1af7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 08:38:34 +1000 Subject: [PATCH 149/746] Improved API connection testing --- test/api_test.dart | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/test/api_test.dart b/test/api_test.dart index 8a4195a..3ede350 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -66,15 +66,28 @@ void main() { if (profile != null) { profile.server = "http://localhost:5555"; await UserProfileDBManager().updateProfile(profile); + + bool result = await api.connectToServer(); + assert(!result); + + // TODO: Test the the right 'error message' is returned + // TODO: The request above should throw a 'SockeException' + + // Test incorrect login details + profile.server = "http://localhost:12345"; + profile.username = "invalidusername"; + + await UserProfileDBManager().updateProfile(profile); + + await api.connectToServer(); + assert(!result); + + // TODO: Test that the connection attempt above throws an authentication error + } else { + assert(false); } - bool result = await api.connectToServer(); - assert(!result); - - // TODO: Test the the right 'error message' is returned - - // TODO: Test incorrect login details }); From 8e1804b39dbf0e5a4cd9f8c572143bf4ccc684e1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 08:48:46 +1000 Subject: [PATCH 150/746] Debug --- test/api_test.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/api_test.dart b/test/api_test.dart index 3ede350..83ff2e3 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -15,6 +15,9 @@ void main() { if (! await UserProfileDBManager().profileNameExists("Test Profile")) { // Create and select a profile to user + + print("TEST: Creating profile for user 'testuser'"); + await UserProfileDBManager().addProfile(UserProfile( name: "Test Profile", server: "http://localhost:12345", @@ -30,6 +33,7 @@ void main() { // as they can get overwritten by subsequent tests if (prf != null) { + prf.name = "Test Profile"; prf.server = "http://localhost:12345"; prf.username = "testuser"; prf.password = "testpassword"; @@ -72,7 +76,7 @@ void main() { // TODO: Test the the right 'error message' is returned // TODO: The request above should throw a 'SockeException' - + // Test incorrect login details profile.server = "http://localhost:12345"; profile.username = "invalidusername"; From 2e86a02343091c32079566a52299a0dfb94d76fb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 09:00:09 +1000 Subject: [PATCH 151/746] more debug --- lib/user_profile.dart | 4 ++++ test/api_test.dart | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 507d9f0..05c98a8 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -151,8 +151,12 @@ class UserProfileDBManager { final profiles = await store.find(await _db); + print("getSelectedProfile() - ${profiles.length} profiles available - selected = ${selected}"); + for (int idx = 0; idx < profiles.length; idx++) { + print("- Checking ${idx} - key = ${profiles[idx].key} - ${profiles[idx].value.toString()}"); + if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( profiles[idx].key as int, diff --git a/test/api_test.dart b/test/api_test.dart index 83ff2e3..4553d33 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -76,7 +76,7 @@ void main() { // TODO: Test the the right 'error message' is returned // TODO: The request above should throw a 'SockeException' - + // Test incorrect login details profile.server = "http://localhost:12345"; profile.username = "invalidusername"; From 625d29fcf1ecef8b352a5cdcb2fe63d5b0243035 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 09:13:49 +1000 Subject: [PATCH 152/746] Adds debug message helper --- lib/api.dart | 1 + lib/helpers.dart | 16 +++++++++++++++- lib/user_profile.dart | 11 ++++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 4d42be0..34dfb43 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -16,6 +16,7 @@ import "package:flutter_cache_manager/flutter_cache_manager.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/user_profile.dart"; diff --git a/lib/helpers.dart b/lib/helpers.dart index 2bdbed5..24dc6e8 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -7,9 +7,23 @@ * supressing trailing zeroes */ +import "dart:io"; + import "package:audioplayers/audioplayers.dart"; import "package:one_context/one_context.dart"; + +/* + * Display a debug message if we are in testing mode, or running in debug mode + */ +void debug(dynamic msg) { + + if (Platform.environment.containsKey("FLUTTER_TEST")) { + print("DEBUG: ${msg.toString()}"); + } +} + + String simpleNumberString(double number) { // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart @@ -19,7 +33,7 @@ String simpleNumberString(double number) { /* * Play an audio file from the requested path. * - * Note: If OneContext module fails the 'hasConext' check, + * Note: If OneContext module fails the 'hasContext' check, * we will not attempt to play the sound */ Future playAudioFile(String path) async { diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 05c98a8..2d4a474 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -1,6 +1,7 @@ import "package:sembast/sembast.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/preferences.dart"; class UserProfile { @@ -85,7 +86,7 @@ class UserProfileDBManager { Future addProfile(UserProfile profile) async { if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { - print("Profile missing required values - not adding to database"); + debug("addProfile() : Profile missing required values - not adding to database"); return false; } @@ -93,7 +94,7 @@ class UserProfileDBManager { final bool exists = await profileNameExists(profile.name); if (exists) { - print("UserProfile '${profile.name}' already exists"); + debug("addProfile() : UserProfile '${profile.name}' already exists"); return false; } @@ -120,7 +121,7 @@ class UserProfileDBManager { // Prevent invalid profile data from being updated if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { - print("Profile missing required values - not updating"); + debug("updateProfile() : Profile missing required values - not updating"); return false; } @@ -151,11 +152,11 @@ class UserProfileDBManager { final profiles = await store.find(await _db); - print("getSelectedProfile() - ${profiles.length} profiles available - selected = ${selected}"); + debug("getSelectedProfile() : ${profiles.length} profiles available - selected = ${selected}"); for (int idx = 0; idx < profiles.length; idx++) { - print("- Checking ${idx} - key = ${profiles[idx].key} - ${profiles[idx].value.toString()}"); + debug("- Checking ${idx} - key = ${profiles[idx].key} - ${profiles[idx].value.toString()}"); if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( From 4e14bd077c3dbdf5ac07e56c9bcc62d2b001e95f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 09:17:32 +1000 Subject: [PATCH 153/746] Improved debug messages --- lib/api.dart | 16 +++++++--------- lib/preferences.dart | 5 ----- lib/settings/login.dart | 1 - 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 34dfb43..e098a52 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -341,7 +341,7 @@ class InvenTreeAPI { // Clear the list of available plugins _plugins.clear(); - print("Connecting to ${apiUrl} -> username=${username}"); + debug("Connecting to ${apiUrl} -> username=${username}"); APIResponse response; @@ -434,7 +434,7 @@ class InvenTreeAPI { // Return the received token _token = (data["token"] ?? "") as String; - print("Received token - $_token"); + debug("Received token from server"); // Request user role information (async) getUserRoles(); @@ -448,7 +448,7 @@ class InvenTreeAPI { } void disconnectFromServer() { - print("InvenTreeAPI().disconnectFromServer()"); + debug("API : disconnectFromServer()"); _connected = false; _connecting = false; @@ -504,7 +504,7 @@ class InvenTreeAPI { roles.clear(); - print("Requesting user role data"); + debug("API: Requesting user role data"); // Next we request the permissions assigned to the current user // Note: 2021-02-27 this "roles" feature for the API was just introduced. @@ -534,7 +534,7 @@ class InvenTreeAPI { return; } - print("Requesting plugin information"); + debug("API: getPluginInformation()"); // Request a list of plugins from the server final List results = await InvenTreePlugin().list(); @@ -664,7 +664,7 @@ class InvenTreeAPI { _request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale()); } on SocketException catch (error) { - print("SocketException at ${url}: ${error.toString()}"); + debug("SocketException at ${url}: ${error.toString()}"); showServerError(L10().connectionRefused, error.toString()); return; } on TimeoutException { @@ -673,7 +673,7 @@ class InvenTreeAPI { return; } on HandshakeException catch (error) { print("HandshakeException at ${url}:"); - print(error.toString()); + debug(error.toString()); showServerError(L10().serverCertificateError, error.toString()); return; } catch (error, stackTrace) { @@ -1236,8 +1236,6 @@ class InvenTreeAPI { var plugins = getPlugins(mixin: "locate"); - print("locateItemOrLocation"); - if (plugins.isEmpty) { // TODO: Error message return; diff --git a/lib/preferences.dart b/lib/preferences.dart index 961a16b..b804cbd 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -60,16 +60,11 @@ class InvenTreePreferencesDB { // Get a platform-specific directory where persistent app data can be stored final appDocumentDir = await getApplicationDocumentsDirectory(); - print("Documents Dir: ${appDocumentDir.toString()}"); - - print("Path: ${appDocumentDir.path}"); - // Path with the form: /platform-specific-directory/demo.db final dbPath = join(appDocumentDir.path, "InvenTreeSettings.db"); final database = await databaseFactoryIo.openDatabase(dbPath); - // Any code awaiting the Completer's future will now start executing _dbOpenCompleter.complete(database); } } diff --git a/lib/settings/login.dart b/lib/settings/login.dart index a998af4..e61c08b 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -344,7 +344,6 @@ class _ProfileEditState extends State { Uri uri = Uri.parse(value); if (uri.hasScheme) { - print("Scheme: ${uri.scheme}"); if (!["http", "https"].contains(uri.scheme.toLowerCase())) { return L10().serverStart; } From 53b69d9623e5754200a273b7d85bee247dfb1979 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 09:29:04 +1000 Subject: [PATCH 154/746] Improvements for profile management --- lib/user_profile.dart | 35 ++++++++++++++++++++++++++++------- test/api_test.dart | 4 ++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 2d4a474..9eff1ed 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -106,13 +106,6 @@ class UserProfileDBManager { return true; } - /* - * Mark the particular profile as selected - */ - Future selectProfile(int key) async { - await store.record("selected").put(await _db, key); - } - /* * Update the selected profile in the database. * The unique integer is used to determine if the profile already exists. @@ -196,4 +189,32 @@ class UserProfileDBManager { return profileList; } + + /* + * Mark the particular profile as selected + */ + Future selectProfile(int key) async { + await store.record("selected").put(await _db, key); + } + + /* + * Look-up and select a profile by name. + * Return true if the profile was selected + */ + Future selectProfileByName(String name) async { + var profiles = await getAllProfiles(); + + for (var prf in profiles) { + if (prf.name == name) { + int key = prf.key ?? -1; + + if (key >= 0) { + await selectProfile(key); + return true; + } + } + } + + return false; + } } diff --git a/test/api_test.dart b/test/api_test.dart index 4553d33..2ed4161 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -41,6 +41,10 @@ void main() { await UserProfileDBManager().updateProfile(prf); } + // Ensure the profile is selected + assert(! await UserProfileDBManager().selectProfileByName("Missing Profile")); + assert(await UserProfileDBManager().selectProfileByName("Test Profile")); + }); group("Login Tests:", () { From b98f044204b6c6c8546098c21de714a8033c5645 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 09:56:22 +1000 Subject: [PATCH 155/746] More checks --- lib/api.dart | 10 +++----- lib/inventree/stock.dart | 4 +-- lib/widget/drawer.dart | 4 +-- lib/widget/home.dart | 16 ++++++------ lib/widget/purchase_order_detail.dart | 2 +- lib/widget/stock_detail.dart | 8 +++--- test/api_test.dart | 36 ++++++++++++++++++++++----- 7 files changed, 50 insertions(+), 30 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index e098a52..52bd29a 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -208,7 +208,7 @@ class InvenTreeAPI { * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. */ - bool checkConnection(BuildContext context) { + bool checkConnection() { // Firstly, is the server connected? if (!isConnected()) { @@ -292,14 +292,10 @@ class InvenTreeAPI { static final InvenTreeAPI _api = InvenTreeAPI._internal(); // API endpoint for receiving purchase order line items was introduced in v12 - bool supportPoReceive() { - return apiVersion >= 12; - } + bool get supportsPoReceive => apiVersion >= 12; // "Modern" API transactions were implemented in API v14 - bool supportModernStockTransactions() { - return apiVersion >= 14; - } + bool get supportsModernStockTransactions => apiVersion >= 14; /* * Connect to the remote InvenTree server: diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 3dc4f2b..2bb741f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -533,7 +533,7 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; // Note: Format of adjustment API was updated in API v14 - if (api.supportModernStockTransactions()) { + if (api.supportsModernStockTransactions) { // Modern (> 14) API data = { "items": [ @@ -560,7 +560,7 @@ class InvenTreeStockItem extends InvenTreeModel { } // Expected API return code depends on server API version - final int expected_response = api.supportModernStockTransactions() ? 201 : 200; + final int expected_response = api.supportsModernStockTransactions ? 201 : 200; var response = await api.post( endpoint, diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 85a3025..cff24de 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -34,7 +34,7 @@ class InvenTreeDrawer extends StatelessWidget { void _search() { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; _closeDrawer(); @@ -51,7 +51,7 @@ class InvenTreeDrawer extends StatelessWidget { * Upon successful scan, data are passed off to be decoded. */ Future _scan() async { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; _closeDrawer(); scanQrCode(context); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 290c866..19f1c95 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -71,13 +71,13 @@ class _InvenTreeHomePageState extends State { UserProfile? _profile; void _scan(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; scanQrCode(context); } void _showParts(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } @@ -87,7 +87,7 @@ class _InvenTreeHomePageState extends State { } void _showStarredParts(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, @@ -100,13 +100,13 @@ class _InvenTreeHomePageState extends State { } void _showStock(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); } void _showPurchaseOrders(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, @@ -118,19 +118,19 @@ class _InvenTreeHomePageState extends State { /* void _showSuppliers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"}))); } void _showManufacturers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().manufacturers, {"is_manufacturer": "true"}))); } void _showCustomers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"}))); } diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 2748696..2abe56c 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -247,7 +247,7 @@ class _PurchaseOrderDetailState extends RefreshableState { Future _addStockDialog() async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { @@ -391,7 +391,7 @@ class _StockItemDisplayState extends RefreshableState { void _removeStockDialog() { // TODO: In future, deprecate support for the older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { "parent": "items", @@ -463,7 +463,7 @@ class _StockItemDisplayState extends RefreshableState { Future _countStockDialog() async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { @@ -566,7 +566,7 @@ class _StockItemDisplayState extends RefreshableState { Future _transferStockDialog(BuildContext context) async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { diff --git a/test/api_test.dart b/test/api_test.dart index 2ed4161..113ab4d 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -5,6 +5,7 @@ import "package:test/test.dart"; import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/user_profile.dart"; @@ -91,12 +92,13 @@ void main() { assert(!result); // TODO: Test that the connection attempt above throws an authentication error + + assert(!api.checkConnection()); + } else { assert(false); } - - }); test("Login Success", () async { @@ -107,12 +109,34 @@ void main() { final bool result = await api.connectToServer(); // Check expected values - expect(result, equals(true)); - expect(api.hasToken, equals(true)); + assert(result); + assert(api.hasToken); expect(api.baseUrl, equals("http://localhost:12345/")); - expect(api.isConnected(), equals(true)); - expect(api.isConnecting(), equals(false)); + assert(api.isConnected()); + assert(!api.isConnecting()); + assert(api.checkConnection()); }); + + test("Version Checks", () async { + // Test server version information + var api = InvenTreeAPI(); + + assert(await api.connectToServer()); + + // Check supported functions + assert(api.apiVersion >= 50); + assert(api.supportsSettings); + assert(api.supportsNotifications); + assert(api.supportsModernStockTransactions); + assert(api.supportsPoReceive); + + // Check available permissions + assert(api.checkPermission("part", "change")); + assert(api.checkPermission("stocklocation", "delete")); + assert(api.checkPermission("part", "weirdpermission")); + assert(api.checkPermission("blah", "bloo")); + }); + }); } \ No newline at end of file From 2cd73a98e8b7aa319a5c70ed5b57ecccdab8f536 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 10:03:56 +1000 Subject: [PATCH 156/746] Remove unused import --- test/api_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/test/api_test.dart b/test/api_test.dart index 113ab4d..b46cab6 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -5,7 +5,6 @@ import "package:test/test.dart"; import "package:inventree/api.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/user_profile.dart"; From cfc9f09b809525d2ef61cc1f16e3fbf8a4b51335 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 22 May 2022 10:11:36 +1000 Subject: [PATCH 157/746] Merge pull request #135 from inventree/unit-testing Unit testing (cherry picked from commit d55f594342e07fe142fdceda76a36ee0138d270f) --- .github/workflows/android.yaml | 3 - .github/workflows/ci.yaml | 70 ++++++++++ .github/workflows/ios.yaml | 3 - .github/workflows/lint.yaml | 41 ------ .gitignore | 3 + find_dart_files.py | 46 +++++++ lib/api.dart | 33 ++--- lib/api_form.dart | 2 +- lib/app_colors.dart | 2 - lib/app_settings.dart | 68 --------- lib/barcode.dart | 69 ++++++---- lib/helpers.dart | 45 +++--- lib/inventree/sentry.dart | 2 +- lib/inventree/stock.dart | 4 +- lib/l10.dart | 14 +- lib/preferences.dart | 81 +++++++---- lib/settings/app_settings.dart | 2 +- lib/settings/home_settings.dart | 2 +- lib/settings/login.dart | 1 - lib/user_profile.dart | 121 ++++++++++++----- lib/widget/dialogs.dart | 13 +- lib/widget/drawer.dart | 4 +- lib/widget/home.dart | 18 +-- lib/widget/part_list.dart | 2 +- lib/widget/purchase_order_detail.dart | 2 +- lib/widget/snacks.dart | 18 ++- lib/widget/stock_detail.dart | 13 +- lib/widget/stock_list.dart | 2 +- pubspec.lock | 189 ++++++++++++++++++++++++++ pubspec.yaml | 31 +---- requirements.txt | 4 + test/api_test.dart | 141 +++++++++++++++++++ test/preferences_test.dart | 30 ++++ test/user_profile_test.dart | 125 +++++++++++++++++ test/widget_test.dart | 6 +- 35 files changed, 893 insertions(+), 317 deletions(-) create mode 100644 .github/workflows/ci.yaml delete mode 100644 .github/workflows/lint.yaml create mode 100644 find_dart_files.py delete mode 100644 lib/app_settings.dart create mode 100644 requirements.txt create mode 100644 test/api_test.dart create mode 100644 test/preferences_test.dart create mode 100644 test/user_profile_test.dart diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index a9d4940..4199cf2 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -6,9 +6,6 @@ on: push: branches: - master - pull_request: - branches: - - master jobs: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..f3ae7c7 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,70 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INVENTREE_DB_ENGINE: django.db.backends.sqlite3 + INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3 + INVENTREE_MEDIA_ROOT: ../test_inventree_media + INVENTREE_STATIC_ROOT: ../test_inventree_static + INVENTREE_ADMIN_USER: testuser + INVENTREE_ADMIN_PASSWORD: testpassword + INVENTREE_ADMIN_EMAIL: test@test.com + INVENTREE_PYTHON_TEST_SERVER: http://localhost:12345 + INVENTREE_PYTHON_TEST_USERNAME: testuser + INVENTREE_PYTHON_TEST_PASSWORD: testpassword +jobs: + + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + submodules: recursive + - name: Setup Java + uses: actions/setup-java@v1 + with: + java-version: '12.x' + - name: Setup Flutter + uses: subosito/flutter-action@v1 + with: + flutter-version: '2.10.3' + - name: Collect Translation Files + run: | + cd lib/l10n + python3 collect_translations.py + - name: Static Analysis Tests + run: | + cp lib/dummy_dsn.dart lib/dsn.dart + python3 find_dart_files.py + flutter pub get + flutter analyze + + - name: Start InvenTree Server + run: | + sudo apt-get install python3-dev python3-pip python3-venv python3-wheel g++ + pip3 install invoke + git clone --depth 1 https://github.com/inventree/inventree ./inventree_server + cd inventree_server + invoke install + invoke migrate + invoke import-fixtures + invoke server -a 127.0.0.1:12345 & + invoke wait + - name: Unit Tests + run: | + flutter test --coverage + + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 039a6e9..3dc6338 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -6,9 +6,6 @@ on: push: branches: - master - pull_request: - branches: - - master jobs: diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml deleted file mode 100644 index 44b1ed3..0000000 --- a/.github/workflows/lint.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Run flutter linting checks - -name: lint - -on: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - - lint: - runs-on: ubuntu-latest - - env: - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: '12.x' - - name: Setup Flutter - uses: subosito/flutter-action@v1 - with: - flutter-version: '2.10.3' - - name: Collect Translation Files - run: | - cd lib/l10n - python3 collect_translations.py - - run: flutter pub get - - run: cp lib/dummy_dsn.dart lib/dsn.dart - - run: flutter analyze - - run: flutter test --coverage diff --git a/.gitignore b/.gitignore index 2f25898..07101c9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ coverage/* +# This file is auto-generated as part of the CI process +test/coverage_helper_test.dart + # Sentry API key lib/dsn.dart diff --git a/find_dart_files.py b/find_dart_files.py new file mode 100644 index 0000000..a182daa --- /dev/null +++ b/find_dart_files.py @@ -0,0 +1,46 @@ +""" +This script recursively finds any '.dart' files in the ./lib directory, +and generates a 'test' file which includes all these files. + +This is to ensure that *all* .dart files are included in test coverage. +By default, source files which are not touched by the unit tests are not included! + +Ref: https://github.com/flutter/flutter/issues/27997 +""" + +from pathlib import Path + +if __name__ == '__main__': + + dart_files = Path('lib').rglob('*.dart') + + with open("test/coverage_helper_test.dart", "w") as f: + + f.write("// ignore_for_file: unused_import\n\n") + + skips = [ + 'generated', + 'l10n', + 'dsn.dart', + ] + + for path in dart_files: + path = str(path) + + if any([s in path for s in skips]): + continue + + # Remove leading 'lib\' text + path = path[4:] + path = path.replace('\\', '/') + f.write(f'import "package:inventree/{path}";\n') + + f.write("\n\n") + + f.write("// DO NOT EDIT THIS FILE - it has been auto-generated by 'find_dart_files.py'\n") + f.write("// It has been created to ensure that *all* source file are included in coverage data\n") + + f.write('import "package:test/test.dart";\n\n'); + + f.write("// Do not actually test anything!\n") + f.write("void main() {}\n") diff --git a/lib/api.dart b/lib/api.dart index 9994b65..52bd29a 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -6,7 +6,7 @@ import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; import "package:intl/intl.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:open_file/open_file.dart"; import "package:cached_network_image/cached_network_image.dart"; @@ -16,6 +16,7 @@ import "package:flutter_cache_manager/flutter_cache_manager.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/user_profile.dart"; @@ -201,11 +202,13 @@ class InvenTreeAPI { // Authentication token (initially empty, must be requested) String _token = ""; + bool get hasToken => _token.isNotEmpty; + /* * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. */ - bool checkConnection(BuildContext context) { + bool checkConnection() { // Firstly, is the server connected? if (!isConnected()) { @@ -278,7 +281,7 @@ class InvenTreeAPI { bool _connecting = false; bool isConnected() { - return profile != null && _connected && baseUrl.isNotEmpty && _token.isNotEmpty; + return profile != null && _connected && baseUrl.isNotEmpty && hasToken; } bool isConnecting() { @@ -289,14 +292,10 @@ class InvenTreeAPI { static final InvenTreeAPI _api = InvenTreeAPI._internal(); // API endpoint for receiving purchase order line items was introduced in v12 - bool supportPoReceive() { - return apiVersion >= 12; - } + bool get supportsPoReceive => apiVersion >= 12; // "Modern" API transactions were implemented in API v14 - bool supportModernStockTransactions() { - return apiVersion >= 14; - } + bool get supportsModernStockTransactions => apiVersion >= 14; /* * Connect to the remote InvenTree server: @@ -338,7 +337,7 @@ class InvenTreeAPI { // Clear the list of available plugins _plugins.clear(); - print("Connecting to ${apiUrl} -> username=${username}"); + debug("Connecting to ${apiUrl} -> username=${username}"); APIResponse response; @@ -431,7 +430,7 @@ class InvenTreeAPI { // Return the received token _token = (data["token"] ?? "") as String; - print("Received token - $_token"); + debug("Received token from server"); // Request user role information (async) getUserRoles(); @@ -445,7 +444,7 @@ class InvenTreeAPI { } void disconnectFromServer() { - print("InvenTreeAPI().disconnectFromServer()"); + debug("API : disconnectFromServer()"); _connected = false; _connecting = false; @@ -501,7 +500,7 @@ class InvenTreeAPI { roles.clear(); - print("Requesting user role data"); + debug("API: Requesting user role data"); // Next we request the permissions assigned to the current user // Note: 2021-02-27 this "roles" feature for the API was just introduced. @@ -531,7 +530,7 @@ class InvenTreeAPI { return; } - print("Requesting plugin information"); + debug("API: getPluginInformation()"); // Request a list of plugins from the server final List results = await InvenTreePlugin().list(); @@ -661,7 +660,7 @@ class InvenTreeAPI { _request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale()); } on SocketException catch (error) { - print("SocketException at ${url}: ${error.toString()}"); + debug("SocketException at ${url}: ${error.toString()}"); showServerError(L10().connectionRefused, error.toString()); return; } on TimeoutException { @@ -670,7 +669,7 @@ class InvenTreeAPI { return; } on HandshakeException catch (error) { print("HandshakeException at ${url}:"); - print(error.toString()); + debug(error.toString()); showServerError(L10().serverCertificateError, error.toString()); return; } catch (error, stackTrace) { @@ -1233,8 +1232,6 @@ class InvenTreeAPI { var plugins = getPlugins(mixin: "locate"); - print("locateItemOrLocation"); - if (plugins.isEmpty) { // TODO: Error message return; diff --git a/lib/api_form.dart b/lib/api_form.dart index 07221a1..588658b 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -335,7 +335,7 @@ class APIFormField { controller.text = hash; data["value"] = hash; - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeAssigned, diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 99d8138..2f0395f 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -1,5 +1,3 @@ - - import "dart:ui"; const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1); diff --git a/lib/app_settings.dart b/lib/app_settings.dart deleted file mode 100644 index e009b78..0000000 --- a/lib/app_settings.dart +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Class for managing app-level configuration options - */ - -import "package:sembast/sembast.dart"; -import "package:inventree/preferences.dart"; - -// Settings key values -const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; -const String INV_HOME_SHOW_PO = "homeShowPo"; -const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; -const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; -const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; - -const String INV_SOUNDS_BARCODE = "barcodeSounds"; -const String INV_SOUNDS_SERVER = "serverSounds"; - -const String INV_PART_SUBCATEGORY = "partSubcategory"; - -const String INV_STOCK_SUBLOCATION = "stockSublocation"; -const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; - -const String INV_REPORT_ERRORS = "reportErrors"; - -const String INV_STRICT_HTTPS = "strictHttps"; - -class InvenTreeSettingsManager { - - factory InvenTreeSettingsManager() { - return _manager; - } - - InvenTreeSettingsManager._internal(); - - final store = StoreRef("settings"); - - Future get _db async => InvenTreePreferencesDB.instance.database; - - Future getValue(String key, dynamic backup) async { - - final value = await store.record(key).get(await _db); - - if (value == null) { - return backup; - } - - return value; - } - - // Load a boolean setting - Future getBool(String key, bool backup) async { - final dynamic value = await getValue(key, backup); - - if (value is bool) { - return value; - } else { - return backup; - } - } - - Future setValue(String key, dynamic value) async { - - await store.record(key).put(await _db, value); - } - - // Ensure we only ever create a single instance of this class - static final InvenTreeSettingsManager _manager = InvenTreeSettingsManager._internal(); -} diff --git a/lib/barcode.dart b/lib/barcode.dart index 8781f2d..85702e0 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -11,15 +11,38 @@ import "package:qr_code_scanner/qr_code_scanner.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/stock_detail.dart"; +/* + * Play an audible 'success' alert to the user. + */ +Future barcodeSuccessTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_scan.mp3"); + } +} + +Future barcodeFailureTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_error.mp3"); + } +} + + class BarcodeHandler { /* * Class which "handles" a barcode, by communicating with the InvenTree server, @@ -44,7 +67,7 @@ class BarcodeHandler { // Called when the server does not know about a barcode // Override this function - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeNoMatch, @@ -55,7 +78,7 @@ class BarcodeHandler { Future onBarcodeUnhandled(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); // Called when the server returns an unhandled response showServerError(L10().responseUnknown, data.toString()); @@ -125,7 +148,7 @@ class BarcodeScanHandler extends BarcodeHandler { @override Future onBarcodeUnknown(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeNoMatch, @@ -146,7 +169,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreeStockLocation().get(pk).then((var loc) { if (loc is InvenTreeStockLocation) { @@ -156,7 +179,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockLocation, @@ -170,7 +193,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreeStockItem().get(pk).then((var item) { @@ -183,7 +206,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockItem, @@ -196,7 +219,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (pk > 0) { - successTone(); + barcodeSuccessTone(); InvenTreePart().get(pk).then((var part) { @@ -209,7 +232,7 @@ class BarcodeScanHandler extends BarcodeHandler { }); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidPart, @@ -218,7 +241,7 @@ class BarcodeScanHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeUnknown, @@ -275,7 +298,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { if (result) { - successTone(); + barcodeSuccessTone(); Navigator.of(context).pop(); @@ -285,7 +308,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { ); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeScanIntoLocationFailure, @@ -294,7 +317,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockLocation, @@ -329,14 +352,14 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { if (item == null) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().invalidStockItem, success: false, ); } else if (item.locationId == location.pk) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().itemInLocation, @@ -347,7 +370,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { if (result) { - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeScanIntoLocationSuccess, @@ -355,7 +378,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { ); } else { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeScanIntoLocationFailure, @@ -365,7 +388,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { } } else { - failureTone(); + barcodeFailureTone(); // Does not match a valid stock item! showSnackIcon( @@ -401,7 +424,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(BuildContext context, Map data) async { - failureTone(); + barcodeFailureTone(); // If the barcode is known, we can"t assign it to the stock item! showSnackIcon( @@ -424,7 +447,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { String hash = (data["hash"] ?? "") as String; if (hash.isEmpty) { - failureTone(); + barcodeFailureTone(); showSnackIcon( L10().barcodeError, @@ -432,7 +455,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { ); } else { - successTone(); + barcodeSuccessTone(); // Close the barcode scanner Navigator.of(context).pop(); diff --git a/lib/helpers.dart b/lib/helpers.dart index 524cd92..24dc6e8 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -7,8 +7,22 @@ * supressing trailing zeroes */ +import "dart:io"; + import "package:audioplayers/audioplayers.dart"; -import "package:inventree/app_settings.dart"; +import "package:one_context/one_context.dart"; + + +/* + * Display a debug message if we are in testing mode, or running in debug mode + */ +void debug(dynamic msg) { + + if (Platform.environment.containsKey("FLUTTER_TEST")) { + print("DEBUG: ${msg.toString()}"); + } +} + String simpleNumberString(double number) { // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart @@ -16,22 +30,19 @@ String simpleNumberString(double number) { return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1); } -Future successTone() async { +/* + * Play an audio file from the requested path. + * + * Note: If OneContext module fails the 'hasContext' check, + * we will not attempt to play the sound + */ +Future playAudioFile(String path) async { - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - final player = AudioCache(); - player.play("sounds/barcode_scan.mp3"); + if (!OneContext.hasContext) { + return; } + + final player = AudioCache(); + player.play(path); + } - -Future failureTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - final player = AudioCache(); - player.play("sounds/barcode_error.mp3"); - } -} \ No newline at end of file diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 429a50a..cd05a14 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,7 +1,7 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 3dc4f2b..2bb741f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -533,7 +533,7 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; // Note: Format of adjustment API was updated in API v14 - if (api.supportModernStockTransactions()) { + if (api.supportsModernStockTransactions) { // Modern (> 14) API data = { "items": [ @@ -560,7 +560,7 @@ class InvenTreeStockItem extends InvenTreeModel { } // Expected API return code depends on server API version - final int expected_response = api.supportModernStockTransactions() ? 201 : 200; + final int expected_response = api.supportsModernStockTransactions ? 201 : 200; var response = await api.post( endpoint, diff --git a/lib/l10.dart b/lib/l10.dart index ce9f319..2b44f96 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -7,16 +7,18 @@ import "package:flutter/material.dart"; // Shortcut function to reduce boilerplate! I18N L10() { - BuildContext? _ctx = OneContext().context; + if (OneContext.hasContext) { + BuildContext? _ctx = OneContext().context; - if (_ctx != null) { - I18N? i18n = I18N.of(_ctx); + if (_ctx != null) { + I18N? i18n = I18N.of(_ctx); - if (i18n != null) { - return i18n; + if (i18n != null) { + return i18n; + } } } // Fallback for "null" context - return I18NEn(); + return I18NEn(); } \ No newline at end of file diff --git a/lib/preferences.dart b/lib/preferences.dart index 2c52a88..b804cbd 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -6,6 +6,26 @@ import "package:sembast/sembast_io.dart"; import "package:path/path.dart"; +// Settings key values +const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; +const String INV_HOME_SHOW_PO = "homeShowPo"; +const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; +const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; +const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; + +const String INV_SOUNDS_BARCODE = "barcodeSounds"; +const String INV_SOUNDS_SERVER = "serverSounds"; + +const String INV_PART_SUBCATEGORY = "partSubcategory"; + +const String INV_STOCK_SUBLOCATION = "stockSublocation"; +const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; + +const String INV_REPORT_ERRORS = "reportErrors"; + +const String INV_STRICT_HTTPS = "strictHttps"; + + /* * Class for storing InvenTree preferences in a NoSql DB */ @@ -40,46 +60,59 @@ class InvenTreePreferencesDB { // Get a platform-specific directory where persistent app data can be stored final appDocumentDir = await getApplicationDocumentsDirectory(); - print("Documents Dir: ${appDocumentDir.toString()}"); - - print("Path: ${appDocumentDir.path}"); - // Path with the form: /platform-specific-directory/demo.db final dbPath = join(appDocumentDir.path, "InvenTreeSettings.db"); final database = await databaseFactoryIo.openDatabase(dbPath); - // Any code awaiting the Completer's future will now start executing _dbOpenCompleter.complete(database); } } -class InvenTreePreferences { - factory InvenTreePreferences() { - return _api; +/* + * InvenTree setings manager class. + * Provides functions for loading and saving settings, with provision for default values + */ +class InvenTreeSettingsManager { + + factory InvenTreeSettingsManager() { + return _manager; } - InvenTreePreferences._internal(); + InvenTreeSettingsManager._internal(); - /* The following settings are not stored to persistent storage, - * instead they are only used as "session preferences". - * They are kept here as a convenience only. - */ + final store = StoreRef("settings"); - // Expand subcategory list in PartCategory view - bool expandCategoryList = false; + Future get _db async => InvenTreePreferencesDB.instance.database; - // Expand part list in PartCategory view - bool expandPartList = true; + Future getValue(String key, dynamic backup) async { - // Expand sublocation list in StockLocation view - bool expandLocationList = false; + final value = await store.record(key).get(await _db); - // Expand item list in StockLocation view - bool expandStockList = true; + if (value == null) { + return backup; + } - // Ensure we only ever create a single instance of the preferences class - static final InvenTreePreferences _api = InvenTreePreferences._internal(); + return value; + } -} \ No newline at end of file + // Load a boolean setting + Future getBool(String key, bool backup) async { + final dynamic value = await getValue(key, backup); + + if (value is bool) { + return value; + } else { + return backup; + } + } + + Future setValue(String key, dynamic value) async { + + await store.record(key).put(await _db, value); + } + + // Ensure we only ever create a single instance of this class + static final InvenTreeSettingsManager _manager = InvenTreeSettingsManager._internal(); +} diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 124246d..f322bf7 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -3,7 +3,7 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/l10.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class InvenTreeAppSettingsWidget extends StatefulWidget { diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index c5776c6..13e19cd 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -5,7 +5,7 @@ import "package:inventree/l10.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class HomeScreenSettingsWidget extends StatefulWidget { @override diff --git a/lib/settings/login.dart b/lib/settings/login.dart index a998af4..e61c08b 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -344,7 +344,6 @@ class _ProfileEditState extends State { Uri uri = Uri.parse(value); if (uri.hasScheme) { - print("Scheme: ${uri.scheme}"); if (!["http", "https"].contains(uri.scheme.toLowerCase())) { return L10().serverStart; } diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 251aa30..9eff1ed 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -1,6 +1,7 @@ import "package:sembast/sembast.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/preferences.dart"; class UserProfile { @@ -62,75 +63,94 @@ class UserProfileDBManager { Future get _db async => InvenTreePreferencesDB.instance.database; + /* + * Check if a profile with the specified name exists in the database + */ Future profileNameExists(String name) async { - final finder = Finder(filter: Filter.equals("name", name)); + final profiles = await getAllProfiles(); - final profiles = await store.find(await _db, finder: finder); + for (var prf in profiles) { + if (name == prf.name) { + return true; + } + } - return profiles.isNotEmpty; + // No match found! + return false; } - Future addProfile(UserProfile profile) async { + /* + * Add a new UserProfile to the profiles database. + */ + Future addProfile(UserProfile profile) async { + + if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + debug("addProfile() : Profile missing required values - not adding to database"); + return false; + } // Check if a profile already exists with the name final bool exists = await profileNameExists(profile.name); if (exists) { - print("UserProfile '${profile.name}' already exists"); - return; + debug("addProfile() : UserProfile '${profile.name}' already exists"); + return false; } int key = await store.add(await _db, profile.toJson()) as int; - print("Added user profile <${key}> - '${profile.name}'"); - // Record the key profile.key = key; + + return true; } - Future selectProfile(int key) async { - /* - * Mark the particular profile as selected - */ + /* + * Update the selected profile in the database. + * The unique integer is used to determine if the profile already exists. + */ + Future updateProfile(UserProfile profile) async { - final result = await store.record("selected").put(await _db, key); - - return result; - } - - Future updateProfile(UserProfile profile) async { - - if (profile.key == null) { - await addProfile(profile); - return; + // Prevent invalid profile data from being updated + if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + debug("updateProfile() : Profile missing required values - not updating"); + return false; } - final result = await store.record(profile.key).update(await _db, profile.toJson()); + if (profile.key == null) { + bool result = await addProfile(profile); + return result; + } - print("Updated user profile <${profile.key}> - '${profile.name}'"); + await store.record(profile.key).update(await _db, profile.toJson()); - return result; + return true; } + /* + * Remove a user profile from the database + */ Future deleteProfile(UserProfile profile) async { await store.record(profile.key).delete(await _db); - print("Deleted user profile <${profile.key}> - '${profile.name}'"); } + /* + * Return the currently selected profile. + * The key of the UserProfile should match the "selected" property + */ Future getSelectedProfile() async { - /* - * Return the currently selected profile. - * - * key should match the "selected" property - */ final selected = await store.record("selected").get(await _db); final profiles = await store.find(await _db); + debug("getSelectedProfile() : ${profiles.length} profiles available - selected = ${selected}"); + for (int idx = 0; idx < profiles.length; idx++) { + debug("- Checking ${idx} - key = ${profiles[idx].key} - ${profiles[idx].value.toString()}"); + if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( profiles[idx].key as int, @@ -158,14 +178,43 @@ class UserProfileDBManager { if (profiles[idx].key is int) { profileList.add( - UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, - profiles[idx].key == selected, - )); + UserProfile.fromJson( + profiles[idx].key as int, + profiles[idx].value as Map, + profiles[idx].key == selected, + ) + ); } } return profileList; } + + /* + * Mark the particular profile as selected + */ + Future selectProfile(int key) async { + await store.record("selected").put(await _db, key); + } + + /* + * Look-up and select a profile by name. + * Return true if the profile was selected + */ + Future selectProfileByName(String name) async { + var profiles = await getAllProfiles(); + + for (var prf in profiles) { + if (prf.name == name) { + int key = prf.key ?? -1; + + if (key >= 0) { + await selectProfile(key); + return true; + } + } + } + + return false; + } } diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 357983b..5fbe20b 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -1,12 +1,12 @@ - -import "package:inventree/app_settings.dart"; -import "package:inventree/widget/snacks.dart"; -import "package:audioplayers/audioplayers.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; import "package:one_context/one_context.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; +import "package:inventree/widget/snacks.dart"; + Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; @@ -108,8 +108,7 @@ Future showServerError(String title, String description) async { final bool tones = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; if (tones) { - final player = AudioCache(); - player.play("sounds/server_error.mp3"); + playAudioFile("sounds/server_error.mp3"); } showSnackIcon( diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 85a3025..cff24de 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -34,7 +34,7 @@ class InvenTreeDrawer extends StatelessWidget { void _search() { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; _closeDrawer(); @@ -51,7 +51,7 @@ class InvenTreeDrawer extends StatelessWidget { * Upon successful scan, data are passed off to be decoded. */ Future _scan() async { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; _closeDrawer(); scanQrCode(context); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 64c566d..19f1c95 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -6,7 +6,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/login.dart"; @@ -71,13 +71,13 @@ class _InvenTreeHomePageState extends State { UserProfile? _profile; void _scan(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; scanQrCode(context); } void _showParts(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } @@ -87,7 +87,7 @@ class _InvenTreeHomePageState extends State { } void _showStarredParts(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, @@ -100,13 +100,13 @@ class _InvenTreeHomePageState extends State { } void _showStock(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); } void _showPurchaseOrders(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, @@ -118,19 +118,19 @@ class _InvenTreeHomePageState extends State { /* void _showSuppliers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"}))); } void _showManufacturers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().manufacturers, {"is_manufacturer": "true"}))); } void _showCustomers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"}))); } diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index ca4d158..528273f 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -6,7 +6,7 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/api.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/l10.dart"; diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 2748696..2abe56c 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -247,7 +247,7 @@ class _PurchaseOrderDetailState extends RefreshableState | - */ - import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; +/* + * Display a configurable 'snackbar' at the bottom of the screen + */ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? success, String? actionText}) { + // Escape quickly if we do not have context + if (!OneContext.hasContext) { + return; + } + BuildContext? context = OneContext().context; if (context != null) { diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index b0b3cda..e477375 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -19,10 +19,9 @@ import "package:inventree/widget/stock_item_history.dart"; import "package:inventree/widget/stock_item_test_results.dart"; import "package:inventree/widget/stock_notes.dart"; import "package:inventree/l10.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class StockDetailWidget extends StatefulWidget { @@ -312,7 +311,7 @@ class _StockItemDisplayState extends RefreshableState { Future _addStockDialog() async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { @@ -392,7 +391,7 @@ class _StockItemDisplayState extends RefreshableState { void _removeStockDialog() { // TODO: In future, deprecate support for the older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { "parent": "items", @@ -464,7 +463,7 @@ class _StockItemDisplayState extends RefreshableState { Future _countStockDialog() async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { @@ -567,7 +566,7 @@ class _StockItemDisplayState extends RefreshableState { Future _transferStockDialog(BuildContext context) async { // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { + if (InvenTreeAPI().supportsModernStockTransactions) { Map fields = { "pk": { @@ -1008,7 +1007,7 @@ class _StockItemDisplayState extends RefreshableState { } ).then((result) { if (result) { - successTone(); + barcodeSuccessTone(); showSnackIcon( L10().barcodeAssigned, diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index 09d0dc3..90481c7 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -5,7 +5,7 @@ import "package:inventree/inventree/stock.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/stock_detail.dart"; import "package:inventree/api.dart"; diff --git a/pubspec.lock b/pubspec.lock index 4fb3ba9..0f7c12f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "31.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.0" archive: dependency: transitive description: @@ -99,6 +113,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -113,6 +134,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" cross_file: dependency: transitive description: @@ -280,6 +315,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "9.2.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" http: dependency: "direct main" description: @@ -287,6 +336,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" http_parser: dependency: transitive description: @@ -336,6 +392,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -350,6 +413,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" markdown: dependency: transitive description: @@ -378,6 +448,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" octo_image: dependency: transitive description: @@ -399,6 +483,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.2.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" package_info_plus: dependency: "direct main" description: @@ -525,6 +616,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" process: dependency: transitive description: @@ -532,6 +630,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" qr_code_scanner: dependency: "direct main" description: @@ -630,6 +735,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -642,6 +775,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.5" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" source_span: dependency: transitive description: @@ -705,6 +852,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + test: + dependency: "direct dev" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.19.5" test_api: dependency: transitive description: @@ -712,6 +866,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.8" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" typed_data: dependency: transitive description: @@ -789,6 +950,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "7.5.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9031ea5..33932d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,10 +38,11 @@ dependencies: url_launcher: ^6.0.9 # Open link in system browser dev_dependencies: - flutter_launcher_icons: + flutter_launcher_icons: ^0.9.0 flutter_test: sdk: flutter - lint: ^1.0.0 + lint: ^1.8.0 + test: ^1.19.0 flutter_icons: android: true @@ -64,29 +65,3 @@ flutter: - assets/sounds/barcode_scan.mp3 - assets/sounds/barcode_error.mp3 - assets/sounds/server_error.mp3 - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, 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 from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..94f990c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# Python requirements for devops + +coverage==5.3 # Unit test coverage +coveralls==2.1.2 # Coveralls linking (for code coverage reporting) \ No newline at end of file diff --git a/test/api_test.dart b/test/api_test.dart new file mode 100644 index 0000000..b46cab6 --- /dev/null +++ b/test/api_test.dart @@ -0,0 +1,141 @@ +/* + * Unit tests for the InvenTree API code + */ + +import "package:test/test.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/user_profile.dart"; + + + +void main() { + + setUp(() async { + + if (! await UserProfileDBManager().profileNameExists("Test Profile")) { + // Create and select a profile to user + + print("TEST: Creating profile for user 'testuser'"); + + await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", + server: "http://localhost:12345", + username: "testuser", + password: "testpassword", + selected: true, + )); + } + + var prf = await UserProfileDBManager().getSelectedProfile(); + + // Ensure that the server settings are correct by default, + // as they can get overwritten by subsequent tests + + if (prf != null) { + prf.name = "Test Profile"; + prf.server = "http://localhost:12345"; + prf.username = "testuser"; + prf.password = "testpassword"; + + await UserProfileDBManager().updateProfile(prf); + } + + // Ensure the profile is selected + assert(! await UserProfileDBManager().selectProfileByName("Missing Profile")); + assert(await UserProfileDBManager().selectProfileByName("Test Profile")); + + }); + + group("Login Tests:", () { + + test("Disconnected", () async { + // Test that calling disconnect() does the right thing + var api = InvenTreeAPI(); + + api.disconnectFromServer(); + + // Check expected values + expect(api.isConnected(), equals(false)); + expect(api.isConnecting(), equals(false)); + expect(api.hasToken, equals(false)); + + }); + + test("Login Failure", () async { + // Tests for various types of login failures + var api = InvenTreeAPI(); + + // Incorrect server address + var profile = await UserProfileDBManager().getSelectedProfile(); + + assert(profile != null); + + if (profile != null) { + profile.server = "http://localhost:5555"; + await UserProfileDBManager().updateProfile(profile); + + bool result = await api.connectToServer(); + assert(!result); + + // TODO: Test the the right 'error message' is returned + // TODO: The request above should throw a 'SockeException' + + // Test incorrect login details + profile.server = "http://localhost:12345"; + profile.username = "invalidusername"; + + await UserProfileDBManager().updateProfile(profile); + + await api.connectToServer(); + assert(!result); + + // TODO: Test that the connection attempt above throws an authentication error + + assert(!api.checkConnection()); + + } else { + assert(false); + } + + }); + + test("Login Success", () async { + // Test that we can login to the server successfully + var api = InvenTreeAPI(); + + // Attempt to connect + final bool result = await api.connectToServer(); + + // Check expected values + assert(result); + assert(api.hasToken); + expect(api.baseUrl, equals("http://localhost:12345/")); + + assert(api.isConnected()); + assert(!api.isConnecting()); + assert(api.checkConnection()); + }); + + test("Version Checks", () async { + // Test server version information + var api = InvenTreeAPI(); + + assert(await api.connectToServer()); + + // Check supported functions + assert(api.apiVersion >= 50); + assert(api.supportsSettings); + assert(api.supportsNotifications); + assert(api.supportsModernStockTransactions); + assert(api.supportsPoReceive); + + // Check available permissions + assert(api.checkPermission("part", "change")); + assert(api.checkPermission("stocklocation", "delete")); + assert(api.checkPermission("part", "weirdpermission")); + assert(api.checkPermission("blah", "bloo")); + }); + + }); +} \ No newline at end of file diff --git a/test/preferences_test.dart b/test/preferences_test.dart new file mode 100644 index 0000000..b402b7a --- /dev/null +++ b/test/preferences_test.dart @@ -0,0 +1,30 @@ +/* + * Unit tests for the preferences manager + */ + +import "package:test/test.dart"; +import "package:inventree/preferences.dart"; + +void main() { + + setUp(() async { + + }); + + group("Settings Tests:", () { + test("Default Values", () async { + // Boolean values + expect(await InvenTreeSettingsManager().getBool("test", false), equals(false)); + expect(await InvenTreeSettingsManager().getBool("test", true), equals(true)); + + // String values + expect(await InvenTreeSettingsManager().getValue("test", "x"), equals("x")); + }); + + test("Set value", () async { + await InvenTreeSettingsManager().setValue("abc", "xyz"); + + expect(await InvenTreeSettingsManager().getValue("abc", "123"), equals("xyz")); + }); + }); +} \ No newline at end of file diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart new file mode 100644 index 0000000..9b672ad --- /dev/null +++ b/test/user_profile_test.dart @@ -0,0 +1,125 @@ +/* + * Unit tests for the API class + */ + +import "package:test/test.dart"; +import "package:inventree/user_profile.dart"; + +void main() { + + setUp(() async { + // Ensure we have a user profile available + // This profile will match the dockerized InvenTree setup, running locally + + // To start with, there should not be *any* profiles available + var profiles = await UserProfileDBManager().getAllProfiles(); + + for (var prf in profiles) { + await UserProfileDBManager().deleteProfile(prf); + } + + // Check that there are *no* profiles in the database + profiles = await UserProfileDBManager().getAllProfiles(); + expect(profiles.length, equals(0)); + + // Now, create one! + bool result = await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", + username: "testuser", + password: "testpassword""", + server: "http://localhost:12345", + selected: true, + )); + + expect(result, equals(true)); + + // Ensure we have one profile available + // expect(profiles.length, equals(1)); + profiles = await UserProfileDBManager().getAllProfiles(); + + expect(profiles.length, equals(1)); + + int key = -1; + + // Find the first available profile + for (var p in profiles) { + if (p.key != null) { + key = p.key ?? key; + break; + } + } + + // Select the profile + await UserProfileDBManager().selectProfile(key); + }); + + // Run a set of tests for user profile functionality + group("Profile Tests:", () { + + test("Add Invalid Profiles", () async { + // Add a profile with missing data + bool result = await UserProfileDBManager().addProfile( + UserProfile( + username: "what", + password: "why", + ) + ); + + expect(result, equals(false)); + + // Add a profile with a name that already exists + result = await UserProfileDBManager().addProfile( + UserProfile( + name: "Test Profile", + username: "xyz", + password: "hunter42", + ) + ); + + expect(result, equals(false)); + + // Check that the number of protocols available is still the same + var profiles = await UserProfileDBManager().getAllProfiles(); + + expect(profiles.length, equals(1)); + }); + + test("Profile Name Check", () async { + bool result = await UserProfileDBManager().profileNameExists("doesnotexist"); + expect(result, equals(false)); + + result = await UserProfileDBManager().profileNameExists("Test Profile"); + expect(result, equals(true)); + }); + + test("Select Profile", () async { + // Ensure that we can select a user profile + final prf = await UserProfileDBManager().getSelectedProfile(); + + expect(prf, isNot(null)); + + if (prf != null) { + UserProfile p = prf; + + expect(p.name, equals("Test Profile")); + expect(p.username, equals("testuser")); + expect(p.password, equals("testpassword")); + expect(p.server, equals("http://localhost:12345")); + + expect(p.toString(), equals("<${p.key}> Test Profile : http://localhost:12345 - testuser:testpassword")); + + // Test that we can update the profile + p.name = "different name"; + + bool result = await UserProfileDBManager().updateProfile(p); + expect(result, equals(true)); + + // Trying to update with an invalid value will fail! + p.password = ""; + result = await UserProfileDBManager().updateProfile(p); + expect(result, equals(false)); + } + }); + }); + +} \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart index 3c73102..4e838ac 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,9 +5,9 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import "package:flutter_test/flutter_test.dart"; +// import "package:flutter_test/flutter_test.dart"; void main() { - testWidgets("Counter increments smoke test", (WidgetTester tester) async { - }); + // testWidgets("Counter increments smoke test", (WidgetTester tester) async { + // }); } From 9f7e0a8dbfe4d71493bfebd9f0d70f739ef00817 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 10:12:31 +1000 Subject: [PATCH 158/746] Merge remote-tracking branch 'origin/l10n_master' (cherry picked from commit 55f713e3aa31c254002f00feb62dca4170bca176) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 4075b80..da16480 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -545,6 +545,8 @@ "@search": { "description": "search" }, + "searching": "Keresés", + "@searching": {}, "searchLocation": "Hely keresése", "@searchLocation": {}, "searchParts": "Alkatrészek keresése", From 69e00a5fd8baefd52887f2b68f133701b10ad89f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 10:23:27 +1000 Subject: [PATCH 159/746] Attempt to capture stacktrace data when uploading a custom message to sentry --- lib/inventree/sentry.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index cd05a14..0e8e696 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -129,6 +129,9 @@ Future sentryReportMessage(String message, {Map? context}) if (context != null) { scope.setExtra("context", context); } + + // Catch stacktrace data if possible + scope.setExtra("stacktrace", StackTrace.current.toString()); }); try { From 850c2b8c12bb3e2cc298a801a8cb27124352c682 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 15:59:19 +1000 Subject: [PATCH 160/746] Remove support for legacy stock transfer API code - Relies on modern API now - Checks for error messages against hidden fields in stock items --- assets/release_notes.md | 3 + lib/api.dart | 5 +- lib/api_form.dart | 70 +++++- lib/inventree/stock.dart | 37 +-- lib/widget/stock_detail.dart | 427 +++++++++-------------------------- 5 files changed, 189 insertions(+), 353 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e240c26..23c44dc 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,9 @@ --- - Fixes issue which prevented text input in search window +- Remove support for legacy stock adjustment API +- App now requires server API version 20 (or newer) +- Updated translation files ### 0.7.0 - May 2022 --- diff --git a/lib/api.dart b/lib/api.dart index 52bd29a..99b4242 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -144,7 +144,7 @@ class InvenTreeAPI { InvenTreeAPI._internal(); // Minimum required API version for server - static const _minApiVersion = 7; + static const _minApiVersion = 20; bool _strictHttps = false; @@ -294,9 +294,6 @@ class InvenTreeAPI { // API endpoint for receiving purchase order line items was introduced in v12 bool get supportsPoReceive => apiVersion >= 12; - // "Modern" API transactions were implemented in API v14 - bool get supportsModernStockTransactions => apiVersion >= 14; - /* * Connect to the remote InvenTree server: * diff --git a/lib/api_form.dart b/lib/api_form.dart index 588658b..04a51dd 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1161,6 +1161,72 @@ class _APIFormWidgetState extends State { nonFieldErrors = errors; } + /* Check for errors relating to an *unhandled* field name + * These errors will not be displayed and potentially confuse the user + * So, we need to know if these are ever happening + */ + void checkInvalidErrors(APIResponse response) { + var errors = response.asMap(); + + for (String fieldName in errors.keys) { + + bool match = false; + + switch (fieldName) { + case "__all__": + case "non_field_errors": + case "errors": + // ignore these global fields + match = true; + continue; + default: + for (var field in fields) { + + // Hidden fields can't display errors, so we won't match + if (field.hidden) { + continue; + } + + if (field.name == fieldName) { + // Direct Match found! + match = true; + break; + } else if (field.parent == fieldName) { + + var error = errors[fieldName]; + + if (error is List) { + for (var el in error) { + if (el is Map && el.containsKey(field.name)) { + match = true; + break; + } + } + } else if (error is Map && error.containsKey(field.name)) { + match = true; + break; + } + } + } + + break; + } + + if (!match) { + // Match for an unknown / unsupported field + sentryReportMessage( + "API form returned error for unsupported field", + context: { + "url": response.url, + "status_code": response.statusCode.toString(), + "field": fieldName, + "error_message": response.data.toString(), + } + ); + } + } + } + /* * Submit the form data to the server, and handle the results */ @@ -1234,8 +1300,6 @@ class _APIFormWidgetState extends State { // Hide this form Navigator.pop(context); - // TODO: Display a snackBar - if (successFunc != null) { // Ensure the response is a valid JSON structure @@ -1263,7 +1327,7 @@ class _APIFormWidgetState extends State { } extractNonFieldErrors(response); - + checkInvalidErrors(response); break; case 401: showSnackIcon( diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 2bb741f..50b5ebe 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -517,7 +517,6 @@ class InvenTreeStockItem extends InvenTreeModel { * - Remove * - Count */ - // TODO: Remove this function when we deprecate support for the old API Future adjustStock(BuildContext context, String endpoint, double q, {String? notes, int? location}) async { // Serialized stock cannot be adjusted (unless it is a "transfer") @@ -532,46 +531,29 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; - // Note: Format of adjustment API was updated in API v14 - if (api.supportsModernStockTransactions) { - // Modern (> 14) API - data = { - "items": [ - { - "pk": "${pk}", - "quantity": "${quantity}", - } - ], - }; - } else { - // Legacy (<= 14) API - data = { - "item": { + data = { + "items": [ + { "pk": "${pk}", "quantity": "${quantity}", - }, - }; - } - - data["notes"] = notes ?? ""; + } + ], + "notes": notes ?? "", + }; if (location != null) { data["location"] = location; } - // Expected API return code depends on server API version - final int expected_response = api.supportsModernStockTransactions ? 201 : 200; - var response = await api.post( endpoint, body: data, - expectedStatusCode: expected_response, + expectedStatusCode: 200, ); return response.isValid(); } - // TODO: Remove this function when we deprecate support for the old API Future countStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/count/", q, notes: notes); @@ -579,7 +561,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future addStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/add/", q, notes: notes); @@ -587,7 +568,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future removeStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes); @@ -595,7 +575,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future transferStock(BuildContext context, int location, {double? quantity, String? notes}) async { double q = this.quantity; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index e477375..ab59a70 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -295,76 +295,37 @@ class _StockItemDisplayState extends RefreshableState { } - Future _addStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.addStock(context, quantity, notes: _notesController.text); - _notesController.clear(); - - _stockUpdateMessage(result); - - refresh(context); - } - + /* + * Launch a dialog to 'add' quantity to this StockItem + */ Future _addStockDialog() async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { - - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, - "notes": {}, - }; - - launchApiForm( - context, - L10().addStock, - InvenTreeStockItem.addStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.plusCircle, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.clear(); - _notesController.clear(); - - showFormDialog( L10().addStock, - key: _addStockKey, - callback: () { - _addStock(); + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, }, - fields: [ - Text("Current stock: ${item.quantity}"), - QuantityField( - label: L10().addStock, - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ], + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.addStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.plusCircle, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } @@ -375,149 +336,68 @@ class _StockItemDisplayState extends RefreshableState { } } - Future _removeStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.removeStock(context, quantity, notes: _notesController.text); - - _stockUpdateMessage(result); - - refresh(context); - - } - + /* + * Launch a dialog to 'remove' quantity from this StockItem + */ void _removeStockDialog() { - // TODO: In future, deprecate support for the older API - if (InvenTreeAPI().supportsModernStockTransactions) { - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, - "notes": {}, - }; + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; - launchApiForm( - context, - L10().removeStock, - InvenTreeStockItem.removeStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.minusCircle, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.clear(); - _notesController.clear(); - - showFormDialog(L10().removeStock, - key: _removeStockKey, - callback: () { - _removeStock(); - }, - fields: [ - Text("Current stock: ${item.quantity}"), - QuantityField( - label: L10().removeStock, - controller: _quantityController, - max: item.quantity, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ), - ], + launchApiForm( + context, + L10().removeStock, + InvenTreeStockItem.removeStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.minusCircle, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } - Future _countStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.countStock(context, quantity, notes: _notesController.text); - - _stockUpdateMessage(result); - - refresh(context); - } - Future _countStockDialog() async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { - - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": item.quantity, - }, - "notes": {}, - }; - - launchApiForm( - context, - L10().countStock, - InvenTreeStockItem.countStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.clipboardCheck, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.text = item.quantity.toString(); - _notesController.clear(); - - showFormDialog(L10().countStock, - key: _countStockKey, - callback: () { - _countStock(); + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, }, - acceptText: L10().count, - fields: [ - QuantityField( - label: L10().countStock, - hint: "${item.quantityString}", - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ] + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().countStock, + InvenTreeStockItem.countStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.clipboardCheck, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } @@ -542,130 +422,43 @@ class _StockItemDisplayState extends RefreshableState { } - // TODO: Delete this function once support for old API is deprecated - Future _transferStock(int locationId) async { - - double quantity = double.tryParse(_quantityController.text) ?? item.quantity; - String notes = _notesController.text; - - _quantityController.clear(); - _notesController.clear(); - - var result = await item.transferStock(context, locationId, quantity: quantity, notes: notes); - - refresh(context); - - if (result) { - showSnackIcon(L10().stockItemTransferred, success: true); - } - } - /* * Launches an API Form to transfer this stock item to a new location */ Future _transferStockDialog(BuildContext context) async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "location": {}, + "notes": {}, + }; - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": item.quantity, - }, - "location": {}, - "notes": {}, - }; - - launchApiForm( - context, - L10().transferStock, - InvenTreeStockItem.transferStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.dolly, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; + if (item.isSerialized()) { + // Prevent editing of 'quantity' field if the item is serialized + fields["quantity"]["hidden"] = true; } - int? location_pk; - - _quantityController.text = "${item.quantity}"; - - showFormDialog(L10().transferStock, - key: _moveStockKey, - callback: () { - var _pk = location_pk; - - if (_pk != null) { - _transferStock(_pk); - } - }, - fields: [ - QuantityField( - label: L10().quantity, - controller: _quantityController, - max: item.quantity, - ), - DropdownSearch( - mode: Mode.BOTTOM_SHEET, - showSelectedItem: false, - autoFocusSearchBox: true, - selectedItem: null, - errorBuilder: (context, entry, exception) { - print("entry: $entry"); - print(exception.toString()); - - return Text( - exception.toString(), - style: TextStyle( - fontSize: 10, - ) - ); - }, - onFind: (String filter) async { - - final results = await InvenTreeStockLocation().search(filter); - - List items = []; - - for (InvenTreeModel loc in results) { - if (loc is InvenTreeStockLocation) { - items.add(loc.jsondata); - } - } - - return items; - }, - label: L10().stockLocation, - hint: L10().searchLocation, - onChanged: null, - itemAsString: (dynamic location) { - return (location["pathstring"] ?? "") as String; - }, - onSaved: (dynamic location) { - if (location == null) { - location_pk = null; - } else { - location_pk = location["pk"] as int; - } - }, - isFilteredOnline: true, - showSearchBox: true, - ), - ], + launchApiForm( + context, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.dolly, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } From 1b901b39df51e95dd4aa40c63c6223fad401f4a5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 16:19:10 +1000 Subject: [PATCH 161/746] Remove old stuffs --- lib/widget/stock_detail.dart | 11 ----------- test/api_test.dart | 1 - 2 files changed, 12 deletions(-) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index ab59a70..62058f2 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -1,15 +1,12 @@ import "package:flutter/material.dart"; -import "package:dropdown_search/dropdown_search.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; -import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/fields.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/progress.dart"; @@ -42,14 +39,6 @@ class _StockItemDisplayState extends RefreshableState { @override String getAppBarTitle(BuildContext context) => L10().stockItem; - final TextEditingController _quantityController = TextEditingController(); - final TextEditingController _notesController = TextEditingController(); - - final _addStockKey = GlobalKey(); - final _removeStockKey = GlobalKey(); - final _countStockKey = GlobalKey(); - final _moveStockKey = GlobalKey(); - bool stockShowHistory = false; @override diff --git a/test/api_test.dart b/test/api_test.dart index b46cab6..4f9723b 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -127,7 +127,6 @@ void main() { assert(api.apiVersion >= 50); assert(api.supportsSettings); assert(api.supportsNotifications); - assert(api.supportsModernStockTransactions); assert(api.supportsPoReceive); // Check available permissions From bf722d6b76bf0356dd52ebe6155cdcffefc0a0e8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 22 May 2022 16:26:57 +1000 Subject: [PATCH 162/746] Merge pull request #140 from inventree/legacy-api Remove support for legacy stock transfer API code (cherry picked from commit 333e5bb41d24466077d3f1c2de15cc03baab276e) --- assets/release_notes.md | 3 + lib/api.dart | 5 +- lib/api_form.dart | 70 +++++- lib/inventree/stock.dart | 37 +-- lib/widget/stock_detail.dart | 438 +++++++++-------------------------- test/api_test.dart | 1 - 6 files changed, 189 insertions(+), 365 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e240c26..23c44dc 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,9 @@ --- - Fixes issue which prevented text input in search window +- Remove support for legacy stock adjustment API +- App now requires server API version 20 (or newer) +- Updated translation files ### 0.7.0 - May 2022 --- diff --git a/lib/api.dart b/lib/api.dart index 52bd29a..99b4242 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -144,7 +144,7 @@ class InvenTreeAPI { InvenTreeAPI._internal(); // Minimum required API version for server - static const _minApiVersion = 7; + static const _minApiVersion = 20; bool _strictHttps = false; @@ -294,9 +294,6 @@ class InvenTreeAPI { // API endpoint for receiving purchase order line items was introduced in v12 bool get supportsPoReceive => apiVersion >= 12; - // "Modern" API transactions were implemented in API v14 - bool get supportsModernStockTransactions => apiVersion >= 14; - /* * Connect to the remote InvenTree server: * diff --git a/lib/api_form.dart b/lib/api_form.dart index 588658b..04a51dd 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1161,6 +1161,72 @@ class _APIFormWidgetState extends State { nonFieldErrors = errors; } + /* Check for errors relating to an *unhandled* field name + * These errors will not be displayed and potentially confuse the user + * So, we need to know if these are ever happening + */ + void checkInvalidErrors(APIResponse response) { + var errors = response.asMap(); + + for (String fieldName in errors.keys) { + + bool match = false; + + switch (fieldName) { + case "__all__": + case "non_field_errors": + case "errors": + // ignore these global fields + match = true; + continue; + default: + for (var field in fields) { + + // Hidden fields can't display errors, so we won't match + if (field.hidden) { + continue; + } + + if (field.name == fieldName) { + // Direct Match found! + match = true; + break; + } else if (field.parent == fieldName) { + + var error = errors[fieldName]; + + if (error is List) { + for (var el in error) { + if (el is Map && el.containsKey(field.name)) { + match = true; + break; + } + } + } else if (error is Map && error.containsKey(field.name)) { + match = true; + break; + } + } + } + + break; + } + + if (!match) { + // Match for an unknown / unsupported field + sentryReportMessage( + "API form returned error for unsupported field", + context: { + "url": response.url, + "status_code": response.statusCode.toString(), + "field": fieldName, + "error_message": response.data.toString(), + } + ); + } + } + } + /* * Submit the form data to the server, and handle the results */ @@ -1234,8 +1300,6 @@ class _APIFormWidgetState extends State { // Hide this form Navigator.pop(context); - // TODO: Display a snackBar - if (successFunc != null) { // Ensure the response is a valid JSON structure @@ -1263,7 +1327,7 @@ class _APIFormWidgetState extends State { } extractNonFieldErrors(response); - + checkInvalidErrors(response); break; case 401: showSnackIcon( diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 2bb741f..50b5ebe 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -517,7 +517,6 @@ class InvenTreeStockItem extends InvenTreeModel { * - Remove * - Count */ - // TODO: Remove this function when we deprecate support for the old API Future adjustStock(BuildContext context, String endpoint, double q, {String? notes, int? location}) async { // Serialized stock cannot be adjusted (unless it is a "transfer") @@ -532,46 +531,29 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; - // Note: Format of adjustment API was updated in API v14 - if (api.supportsModernStockTransactions) { - // Modern (> 14) API - data = { - "items": [ - { - "pk": "${pk}", - "quantity": "${quantity}", - } - ], - }; - } else { - // Legacy (<= 14) API - data = { - "item": { + data = { + "items": [ + { "pk": "${pk}", "quantity": "${quantity}", - }, - }; - } - - data["notes"] = notes ?? ""; + } + ], + "notes": notes ?? "", + }; if (location != null) { data["location"] = location; } - // Expected API return code depends on server API version - final int expected_response = api.supportsModernStockTransactions ? 201 : 200; - var response = await api.post( endpoint, body: data, - expectedStatusCode: expected_response, + expectedStatusCode: 200, ); return response.isValid(); } - // TODO: Remove this function when we deprecate support for the old API Future countStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/count/", q, notes: notes); @@ -579,7 +561,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future addStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/add/", q, notes: notes); @@ -587,7 +568,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future removeStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes); @@ -595,7 +575,6 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Remove this function when we deprecate support for the old API Future transferStock(BuildContext context, int location, {double? quantity, String? notes}) async { double q = this.quantity; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index e477375..62058f2 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -1,15 +1,12 @@ import "package:flutter/material.dart"; -import "package:dropdown_search/dropdown_search.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; -import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/fields.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/progress.dart"; @@ -42,14 +39,6 @@ class _StockItemDisplayState extends RefreshableState { @override String getAppBarTitle(BuildContext context) => L10().stockItem; - final TextEditingController _quantityController = TextEditingController(); - final TextEditingController _notesController = TextEditingController(); - - final _addStockKey = GlobalKey(); - final _removeStockKey = GlobalKey(); - final _countStockKey = GlobalKey(); - final _moveStockKey = GlobalKey(); - bool stockShowHistory = false; @override @@ -295,76 +284,37 @@ class _StockItemDisplayState extends RefreshableState { } - Future _addStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.addStock(context, quantity, notes: _notesController.text); - _notesController.clear(); - - _stockUpdateMessage(result); - - refresh(context); - } - + /* + * Launch a dialog to 'add' quantity to this StockItem + */ Future _addStockDialog() async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { - - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, - "notes": {}, - }; - - launchApiForm( - context, - L10().addStock, - InvenTreeStockItem.addStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.plusCircle, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.clear(); - _notesController.clear(); - - showFormDialog( L10().addStock, - key: _addStockKey, - callback: () { - _addStock(); + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, }, - fields: [ - Text("Current stock: ${item.quantity}"), - QuantityField( - label: L10().addStock, - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ], + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.addStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.plusCircle, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } @@ -375,149 +325,68 @@ class _StockItemDisplayState extends RefreshableState { } } - Future _removeStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.removeStock(context, quantity, notes: _notesController.text); - - _stockUpdateMessage(result); - - refresh(context); - - } - + /* + * Launch a dialog to 'remove' quantity from this StockItem + */ void _removeStockDialog() { - // TODO: In future, deprecate support for the older API - if (InvenTreeAPI().supportsModernStockTransactions) { - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, - "notes": {}, - }; + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; - launchApiForm( - context, - L10().removeStock, - InvenTreeStockItem.removeStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.minusCircle, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.clear(); - _notesController.clear(); - - showFormDialog(L10().removeStock, - key: _removeStockKey, - callback: () { - _removeStock(); - }, - fields: [ - Text("Current stock: ${item.quantity}"), - QuantityField( - label: L10().removeStock, - controller: _quantityController, - max: item.quantity, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ), - ], + launchApiForm( + context, + L10().removeStock, + InvenTreeStockItem.removeStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.minusCircle, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } - Future _countStock() async { - - double quantity = double.parse(_quantityController.text); - _quantityController.clear(); - - final bool result = await item.countStock(context, quantity, notes: _notesController.text); - - _stockUpdateMessage(result); - - refresh(context); - } - Future _countStockDialog() async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { - - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": item.quantity, - }, - "notes": {}, - }; - - launchApiForm( - context, - L10().countStock, - InvenTreeStockItem.countStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.clipboardCheck, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; - } - - _quantityController.text = item.quantity.toString(); - _notesController.clear(); - - showFormDialog(L10().countStock, - key: _countStockKey, - callback: () { - _countStock(); + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, }, - acceptText: L10().count, - fields: [ - QuantityField( - label: L10().countStock, - hint: "${item.quantityString}", - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ] + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().countStock, + InvenTreeStockItem.countStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.clipboardCheck, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } @@ -542,130 +411,43 @@ class _StockItemDisplayState extends RefreshableState { } - // TODO: Delete this function once support for old API is deprecated - Future _transferStock(int locationId) async { - - double quantity = double.tryParse(_quantityController.text) ?? item.quantity; - String notes = _notesController.text; - - _quantityController.clear(); - _notesController.clear(); - - var result = await item.transferStock(context, locationId, quantity: quantity, notes: notes); - - refresh(context); - - if (result) { - showSnackIcon(L10().stockItemTransferred, success: true); - } - } - /* * Launches an API Form to transfer this stock item to a new location */ Future _transferStockDialog(BuildContext context) async { - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportsModernStockTransactions) { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "location": {}, + "notes": {}, + }; - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": item.quantity, - }, - "location": {}, - "notes": {}, - }; - - launchApiForm( - context, - L10().transferStock, - InvenTreeStockItem.transferStockUrl(), - fields, - method: "POST", - icon: FontAwesomeIcons.dolly, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } - ); - - return; + if (item.isSerialized()) { + // Prevent editing of 'quantity' field if the item is serialized + fields["quantity"]["hidden"] = true; } - int? location_pk; - - _quantityController.text = "${item.quantity}"; - - showFormDialog(L10().transferStock, - key: _moveStockKey, - callback: () { - var _pk = location_pk; - - if (_pk != null) { - _transferStock(_pk); - } - }, - fields: [ - QuantityField( - label: L10().quantity, - controller: _quantityController, - max: item.quantity, - ), - DropdownSearch( - mode: Mode.BOTTOM_SHEET, - showSelectedItem: false, - autoFocusSearchBox: true, - selectedItem: null, - errorBuilder: (context, entry, exception) { - print("entry: $entry"); - print(exception.toString()); - - return Text( - exception.toString(), - style: TextStyle( - fontSize: 10, - ) - ); - }, - onFind: (String filter) async { - - final results = await InvenTreeStockLocation().search(filter); - - List items = []; - - for (InvenTreeModel loc in results) { - if (loc is InvenTreeStockLocation) { - items.add(loc.jsondata); - } - } - - return items; - }, - label: L10().stockLocation, - hint: L10().searchLocation, - onChanged: null, - itemAsString: (dynamic location) { - return (location["pathstring"] ?? "") as String; - }, - onSaved: (dynamic location) { - if (location == null) { - location_pk = null; - } else { - location_pk = location["pk"] as int; - } - }, - isFilteredOnline: true, - showSearchBox: true, - ), - ], + launchApiForm( + context, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.dolly, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + } ); } diff --git a/test/api_test.dart b/test/api_test.dart index b46cab6..4f9723b 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -127,7 +127,6 @@ void main() { assert(api.apiVersion >= 50); assert(api.supportsSettings); assert(api.supportsNotifications); - assert(api.supportsModernStockTransactions); assert(api.supportsPoReceive); // Check available permissions From bbe56aba5526845e8c8948153bf6ddf198fba921 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 16:44:11 +1000 Subject: [PATCH 163/746] Bump version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 33932d5..4a04b5d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.7.0+41 +version: 0.7.1+42 environment: sdk: ">=2.16.0 <3.0.0" From 7d24e1818fd9e4b9512aaff5d946a7d0aa2bc365 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 22 May 2022 10:40:01 +1000 Subject: [PATCH 164/746] Merge pull request #138 from inventree/stacktrace-data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attempt to capture stacktrace data when uploading a custom message to… (cherry picked from commit 6f885d3a5ccca56cc1fca574031505b920d1b5cf) --- lib/inventree/sentry.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index cd05a14..0e8e696 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -129,6 +129,9 @@ Future sentryReportMessage(String message, {Map? context}) if (context != null) { scope.setExtra("context", context); } + + // Catch stacktrace data if possible + scope.setExtra("stacktrace", StackTrace.current.toString()); }); try { From 6e93b9c7faa3685c76458ccb9509416d0c026ab2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 22 May 2022 16:57:52 +1000 Subject: [PATCH 165/746] Increment build number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4a04b5d..96f91d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.7.1+42 +version: 0.7.1+43 environment: sdk: ">=2.16.0 <3.0.0" From e0cb8512b16ae5788b30a910dec93bd57fdcdf5a Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 26 May 2022 12:39:36 +1000 Subject: [PATCH 166/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 099b892..35469d5 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -295,6 +295,10 @@ "@lineItem": {}, "lineItems": "Positionen", "@lineItems": {}, + "locateItem": "Lagerbestand lokalisieren", + "@locateItem": {}, + "locateLocation": "Lagerort lokalisieren", + "@locateLocation": {}, "locationCreate": "Neuer Lagerort", "@locationCreate": {}, "locationCreateDetail": "Neuen Lagerort erstellen", From 44bc20c55c3d7962c89a95e92d7282d5f9e4ba1e Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 27 May 2022 12:50:30 +1000 Subject: [PATCH 167/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 133 +++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index b026218..cfe6eca 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -202,12 +202,17 @@ "@feedbackError": {}, "feedbackSuccess": "Feedback verzonden", "@feedbackSuccess": {}, + "formatException": "Formaat fout", + "@formatException": {}, "formatExceptionJson": "JSON gegevensformaat exceptie", "@formatExceptionJson": {}, + "formError": "Fout in formulier", + "@formError": {}, "history": "Geschiedenis", "@history": { "description": "history" }, + "home": "Home", "@homeScreen": {}, "homeScreen": "Startscherm", "homeScreenSettings": "Configureer Startscherminstellingen", @@ -278,6 +283,8 @@ "@itemInLocation": {}, "keywords": "Trefwoorden", "@keywords": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, "lastStocktake": "Laatste Voorraadcontrole", "@lastStocktake": {}, "lastUpdated": "Laatst Bijgewerkt", @@ -286,6 +293,10 @@ "@lineItem": {}, "lineItems": "Regelartikelen", "@lineItems": {}, + "locateItem": "Zoek voorraad item", + "@locateItem": {}, + "locateLocation": "Zoek voorraad locatie", + "@locateLocation": {}, "locationCreate": "Nieuwe Locatie", "@locationCreate": {}, "locationCreateDetail": "Creëer nieuwe voorraadlocatie", @@ -298,12 +309,134 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturers": "Fabrikanten", + "@manufacturers": {}, + "missingData": "Ontbrekende gegevens", + "@missingData": {}, + "name": "Naam", + "@name": {}, + "notConnected": "Niet verbonden", + "@notConnected": {}, + "notes": "Opmerkingen", + "@notes": { + "description": "Notes" + }, + "notifications": "Meldingen", + "@notifications": {}, + "notificationsEmpty": "Geen ongelezen meldingen", + "@notificationsEmpty": {}, + "noResponse": "Geen reactie van de server", + "@noResponse": {}, + "noResults": "Geen Resultaten", + "@noResults": {}, + "noSubcategories": "Geen Subcategorieën", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Geen subcategorieën beschikbaar", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ongeldig nummer", + "@numberInvalid": {}, + "onOrder": "In bestelling", + "@onOrder": {}, + "onOrderDetails": "Items momenteel in bestelling", + "@onOrderDetails": {}, + "packaging": "Verpakkingen", + "@packaging": {}, + "parent": "Bovenliggend", + "@parent": {}, + "parentCategory": "Bovenliggende categorie", + "@parentCategory": {}, + "parentLocation": "Bovenliggende Locatie", + "@parentLocation": {}, + "part": "Onderdeel", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nieuw onderdeel", + "@partCreate": {}, + "partCreateDetail": "Nieuw onderdeel in deze categorie maken", + "@partCreateDetail": {}, + "partEdited": "Onderdeel bijgewerkt", + "@partEdited": {}, + "parts": "Onderdelen", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Geen onderdelen", + "@partsNone": {}, + "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", + "@partNoResults": {}, "profileNotSelected": "Geen Profiel Geselecteerd", "@profileNotSelected": {}, "profileSelect": "Selecteer InvenTree Server", "@profileSelect": {}, + "removeStock": "Uit Voorraad Verwijderen", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Fout melden", + "@reportBug": {}, + "reportBugDescription": "Verstuur bugrapport (GitHub account vereist)", + "@reportBugDescription": {}, + "results": "Resultaten", + "@results": {}, + "required": "Vereist", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Niet gemachtigd", + "@response401": {}, + "response403": "Permissie geweigerd", + "@response403": {}, + "response404": "Pagina niet gevonden", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Server fout", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service niet beschikbaar", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "salesOrders": "Verkooporders", + "@salesOrders": {}, + "save": "Bewaren", + "@save": { + "description": "Save" + }, "scanBarcode": "Streepjescode Scannen", "@scanBarcode": {}, + "search": "Zoeken", + "@search": { + "description": "search" + }, + "searching": "Zoeken...", + "@searching": {}, + "searchStock": "Zoek Voorraad", + "@searchStock": {}, + "select": "Selecteer", + "@select": {}, + "selectFile": "Selecteer Bestand", + "@selectFile": {}, + "selectImage": "Selecteer afbeelding", + "@selectImage": {}, + "selectLocation": "Selecteer een locatie", + "@selectLocation": {}, + "send": "Verzenden", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "server": "Server", + "@server": {}, "soundOnBarcodeAction": "Speel hoorbare toon bij streepjescode actie", "@soundOnBarcodeAction": {} } \ No newline at end of file From b26a6377ffae35cfdf196f55f4665940fcd1149c Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 28 May 2022 01:06:37 +1000 Subject: [PATCH 168/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index cfe6eca..a34a62c 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -134,6 +134,8 @@ "@countStock": { "description": "Count Stock" }, + "credits": "Credits", + "@credits": {}, "customers": "Klanten", "@customers": {}, "damaged": "Beschadigd", @@ -365,10 +367,50 @@ "@partsNone": {}, "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", "@partNoResults": {}, + "partsStarred": "Geabonneerde Onderdelen", + "@partsStarred": {}, + "password": "Wachtwoord", + "@password": {}, + "passwordEmpty": "Wachtwoord mag niet leeg zijn", + "@passwordEmpty": {}, + "permissionAccountDenied": "U heeft niet de vereiste rechten om deze actie uit te voeren", + "@permissionAccountDenied": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, "profileNotSelected": "Geen Profiel Geselecteerd", "@profileNotSelected": {}, "profileSelect": "Selecteer InvenTree Server", "@profileSelect": {}, + "quantity": "Aantal", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Aantal is leeg", + "@quantityEmpty": {}, + "quantityInvalid": "Aantal is ongeldig", + "@quantityInvalid": {}, + "quantityPositive": "Aantal moet positief zijn", + "@quantityPositive": {}, + "queryEmpty": "Voer zoekterm in", + "@queryEmpty": {}, + "queryNoResults": "Geen resultaten", + "@queryNoResults": {}, + "received": "Ontvangen", + "@received": {}, + "refresh": "Vernieuwen", + "@refresh": {}, + "refreshing": "Verversen…", + "@refreshing": {}, + "rejected": "Geweigerd", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Verwijderen", + "@remove": { + "description": "remove" + }, "removeStock": "Uit Voorraad Verwijderen", "@removeStock": { "description": "remove stock" From 83f157536b0b58be86ecfcc46e4987a4b2b2ea59 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 18:49:36 +1000 Subject: [PATCH 169/746] Add template for auto-generation of release notes --- .github/release.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/release.yml diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..280a065 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,29 @@ +# .github/release.yml + +changelog: + exclude: + labels: + - wontfix + categories: + - title: Breaking Changes + labels: + - Semver-Major + - breaking + - title: New Features + labels: + - Semver-Minor + - enhancement + - title: Bug Fixes + labels: + - Semver-Patch + - bug + - title: Devops / Setup Changes + labels: + - docker + - setup + - demo + - CI + - security + - title: Other Changes + labels: + - "*" From aa4317a2fe403d34f230624f2b107c1aee10bda7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 19:51:08 +1000 Subject: [PATCH 170/746] Add support for "quarantined" stock item status --- assets/release_notes.md | 5 +++++ lib/inventree/stock.dart | 9 +++++++-- lib/l10n/app_en.arb | 3 +++ lib/widget/stock_detail.dart | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 23c44dc..a330e6f 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.7.2 - June 2022 +--- + +- Add "quarantined" status flag for stock items + ### 0.7.1 - May 2022 --- diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 50b5ebe..b60eb95 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -129,11 +129,12 @@ class InvenTreeStockItem extends InvenTreeModel { static const int DESTROYED = 60; static const int REJECTED = 65; static const int LOST = 70; + static const int QUARANTINED = 75; static const int RETURNED = 85; - String statusLabel(BuildContext context) { + String statusLabel() { - // TODO: Delete me - The translated status values are provided by the API! + // TODO: Delete me - The translated status values should be provided by the API! switch (status) { case OK: @@ -148,6 +149,8 @@ class InvenTreeStockItem extends InvenTreeModel { return L10().rejected; case LOST: return L10().lost; + case QUARANTINED: + return L10().quarantined; case RETURNED: return L10().returned; default: @@ -166,6 +169,8 @@ class InvenTreeStockItem extends InvenTreeModel { case DESTROYED: case REJECTED: return Color(0xFFe35a57); + case QUARANTINED: + return Color(0xFF0DCAF0); case LOST: default: return Color(0xFFAAAAAA); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f6e6064..64223dd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -664,6 +664,9 @@ "quantityPositive": "Quantity must be positive", "@quantityPositive": {}, + "quarantined": "Quarantined", + "@quarantined": {}, + "queryEmpty": "Enter search query", "@queryEmpty": {}, diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 62058f2..8c1a376 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -458,7 +458,7 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text("${item.partDescription}"), leading: InvenTreeAPI().getImage(item.partImage), trailing: Text( - item.statusLabel(context), + item.statusLabel(), style: TextStyle( color: item.statusColor ) From dbc024491caad805633d78226c66694614d9c591 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 20:23:59 +1000 Subject: [PATCH 171/746] Pass URL through to the showServeError method - Can decide, based on the URL, if we want to show an error --- lib/api.dart | 75 ++++++++++++++------------ lib/api_form.dart | 2 +- lib/barcode.dart | 3 +- lib/inventree/model.dart | 4 ++ lib/widget/dialogs.dart | 110 +++++++++------------------------------ 5 files changed, 74 insertions(+), 120 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 99b4242..edb2687 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -341,7 +341,7 @@ class InvenTreeAPI { response = await get("", expectedStatusCode: 200); if (!response.successful()) { - showStatusCodeError(response.statusCode); + showStatusCodeError(apiUrl, response.statusCode); return false; } @@ -351,6 +351,7 @@ class InvenTreeAPI { if (!data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) { showServerError( + apiUrl, L10().missingData, L10().serverMissingData, ); @@ -378,6 +379,7 @@ class InvenTreeAPI { message += "Ensure your InvenTree server version is up to date!"; showServerError( + apiUrl, L10().serverOld, message, ); @@ -401,12 +403,13 @@ class InvenTreeAPI { case 401: case 403: showServerError( + apiUrl, L10().serverAuthenticationError, L10().invalidUsernamePassword, ); break; default: - showStatusCodeError(response.statusCode); + showStatusCodeError(apiUrl, response.statusCode); break; } @@ -417,6 +420,7 @@ class InvenTreeAPI { if (!data.containsKey("token")) { showServerError( + apiUrl, L10().tokenMissing, L10().tokenMissingFromResponse, ); @@ -631,12 +635,12 @@ class InvenTreeAPI { Uri? _uri = Uri.tryParse(makeUrl(url)); if (_uri == null) { - showServerError(L10().invalidHost, L10().invalidHostDetails); + showServerError(url, L10().invalidHost, L10().invalidHostDetails); return; } if (_uri.host.isEmpty) { - showServerError(L10().invalidHost, L10().invalidHostDetails); + showServerError(url, L10().invalidHost, L10().invalidHostDetails); return; } @@ -644,7 +648,7 @@ class InvenTreeAPI { final bool strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; - var client = createClient(strictHttps: strictHttps); + var client = createClient(url, strictHttps: strictHttps); // Attempt to open a connection to the server try { @@ -658,20 +662,20 @@ class InvenTreeAPI { } on SocketException catch (error) { debug("SocketException at ${url}: ${error.toString()}"); - showServerError(L10().connectionRefused, error.toString()); + showServerError(url, L10().connectionRefused, error.toString()); return; } on TimeoutException { print("TimeoutException at ${url}"); - showTimeoutError(); + showTimeoutError(url); return; } on HandshakeException catch (error) { print("HandshakeException at ${url}:"); debug(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); return; } catch (error, stackTrace) { print("Server error at ${url}: ${error.toString()}"); - showServerError(L10().serverError, error.toString()); + showServerError(url, L10().serverError, error.toString()); sentryReportError( "api.downloadFile : client.openUrl", error, stackTrace, @@ -693,16 +697,16 @@ class InvenTreeAPI { OpenFile.open(local_path); } } else { - showStatusCodeError(response.statusCode); + showStatusCodeError(url, response.statusCode); } } on SocketException catch (error) { - showServerError(L10().connectionRefused, error.toString()); + showServerError(url, L10().connectionRefused, error.toString()); } on TimeoutException { - showTimeoutError(); + showTimeoutError(url); } catch (error, stackTrace) { print("Error downloading image:"); print(error.toString()); - showServerError(L10().downloadError, error.toString()); + showServerError(url, L10().downloadError, error.toString()); sentryReportError( "api.downloadFile : client.closeRequest", error, stackTrace, @@ -767,11 +771,12 @@ class InvenTreeAPI { ); } } on SocketException catch (error) { - showServerError(L10().connectionRefused, error.toString()); + showServerError(url, L10().connectionRefused, error.toString()); response.error = "SocketException"; response.errorDetail = error.toString(); } on FormatException { showServerError( + url, L10().formatException, L10().formatExceptionJson + ":\n${jsondata}" ); @@ -786,10 +791,10 @@ class InvenTreeAPI { ); } on TimeoutException { - showTimeoutError(); + showTimeoutError(url); response.error = "TimeoutException"; } catch (error, stackTrace) { - showServerError(L10().serverError, error.toString()); + showServerError(url, L10().serverError, error.toString()); sentryReportError( "api.uploadFile", error, stackTrace @@ -845,7 +850,7 @@ class InvenTreeAPI { ); } - HttpClient createClient({bool strictHttps = false}) { + HttpClient createClient(String url, {bool strictHttps = false}) { var client = HttpClient(); @@ -853,6 +858,7 @@ class InvenTreeAPI { if (strictHttps) { showServerError( + url, L10().serverCertificateError, L10().serverCertificateInvalid, ); @@ -897,12 +903,12 @@ class InvenTreeAPI { Uri? _uri = Uri.tryParse(_url); if (_uri == null) { - showServerError(L10().invalidHost, L10().invalidHostDetails); + showServerError(url, L10().invalidHost, L10().invalidHostDetails); return null; } if (_uri.host.isEmpty) { - showServerError(L10().invalidHost, L10().invalidHostDetails); + showServerError(url, L10().invalidHost, L10().invalidHostDetails); return null; } @@ -910,7 +916,7 @@ class InvenTreeAPI { final bool strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; - var client = createClient(strictHttps: strictHttps); + var client = createClient(url, strictHttps: strictHttps); // Attempt to open a connection to the server try { @@ -925,25 +931,25 @@ class InvenTreeAPI { return _request; } on SocketException catch (error) { print("SocketException at ${url}: ${error.toString()}"); - showServerError(L10().connectionRefused, error.toString()); + showServerError(url, L10().connectionRefused, error.toString()); return null; } on TimeoutException { print("TimeoutException at ${url}"); - showTimeoutError(); + showTimeoutError(url); return null; } on CertificateException catch (error) { print("CertificateException at ${url}:"); print(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); return null; } on HandshakeException catch (error) { print("HandshakeException at ${url}:"); print(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); return null; } catch (error, stackTrace) { print("Server error at ${url}: ${error.toString()}"); - showServerError(L10().serverError, error.toString()); + showServerError(url, L10().serverError, error.toString()); sentryReportError( "api.apiRequest : openUrl", error, stackTrace, @@ -975,6 +981,8 @@ class InvenTreeAPI { url: request.uri.toString() ); + String url = request.uri.toString(); + try { HttpClientResponse? _response = await request.close().timeout(Duration(seconds: 10)); @@ -982,7 +990,7 @@ class InvenTreeAPI { // If the server returns a server error code, alert the user if (_response.statusCode >= 500) { - showStatusCodeError(_response.statusCode); + showStatusCodeError(url, _response.statusCode); sentryReportMessage( "Server error", @@ -1001,31 +1009,31 @@ class InvenTreeAPI { if (ignoreResponse) { response.data = {}; } else { - response.data = await responseToJson(_response) ?? {}; + response.data = await responseToJson(url, _response) ?? {}; } if (statusCode != null) { // Expected status code not returned if (statusCode != _response.statusCode) { - showStatusCodeError(_response.statusCode); + showStatusCodeError(url, _response.statusCode); } } } } on SocketException catch (error) { - showServerError(L10().connectionRefused, error.toString()); + showServerError(url, L10().connectionRefused, error.toString()); response.error = "SocketException"; response.errorDetail = error.toString(); } on CertificateException catch (error) { print("CertificateException at ${request.uri.toString()}:"); print(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); } on TimeoutException { - showTimeoutError(); + showTimeoutError(url); response.error = "TimeoutException"; } catch (error, stackTrace) { - showServerError(L10().serverError, error.toString()); + showServerError(url, L10().serverError, error.toString()); sentryReportError("api.completeRequest", error, stackTrace); response.error = "UnknownError"; response.errorDetail = error.toString(); @@ -1038,7 +1046,7 @@ class InvenTreeAPI { /* * Convert a HttpClientResponse response object to JSON */ - dynamic responseToJson(HttpClientResponse response) async { + dynamic responseToJson(String url, HttpClientResponse response) async { String body = await response.transform(utf8.decoder).join(); @@ -1058,6 +1066,7 @@ class InvenTreeAPI { ); showServerError( + url, L10().formatException, L10().formatExceptionJson + ":\n${body}" ); diff --git a/lib/api_form.dart b/lib/api_form.dart index 04a51dd..23b8e75 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1288,7 +1288,7 @@ class _APIFormWidgetState extends State { final response = await _submit(data); if (!response.isValid()) { - showServerError(L10().serverError, L10().responseInvalid); + showServerError(url, L10().serverError, L10().responseInvalid); return; } diff --git a/lib/barcode.dart b/lib/barcode.dart index 85702e0..29beebb 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -81,7 +81,7 @@ class BarcodeHandler { barcodeFailureTone(); // Called when the server returns an unhandled response - showServerError(L10().responseUnknown, data.toString()); + showServerError("barcode/", L10().responseUnknown, data.toString()); _controller?.resumeCamera(); } @@ -440,6 +440,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { if (!data.containsKey("hash")) { showServerError( + "barcode/", L10().missingData, L10().barcodeMissingHash, ); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 550bc2f..5d55e9f 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -270,6 +270,7 @@ class InvenTreeModel { ); showServerError( + url, L10().serverError, L10().errorDelete, ); @@ -299,6 +300,7 @@ class InvenTreeModel { ); showServerError( + url, L10().serverError, L10().errorFetch, ); @@ -367,6 +369,7 @@ class InvenTreeModel { ); showServerError( + url, L10().serverError, L10().errorFetch, ); @@ -408,6 +411,7 @@ class InvenTreeModel { ); showServerError( + URL, L10().serverError, L10().errorCreate, ); diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 5fbe20b..a81415c 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -7,6 +7,7 @@ import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/snacks.dart"; + Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; @@ -50,30 +51,6 @@ Future confirmationDialog(String title, String text, {IconData icon = Font } -Future showInfoDialog(String title, String description, {IconData icon = FontAwesomeIcons.info, String? info, Function()? onDismissed}) async { - - String _info = info ?? L10().info; - - OneContext().showDialog( - builder: (BuildContext context) => SimpleDialog( - title: ListTile( - title: Text(_info), - leading: FaIcon(icon), - ), - children: [ - ListTile( - title: Text(title), - subtitle: Text(description) - ) - ] - ) - ).then((value) { - if (onDismissed != null) { - onDismissed(); - } - }); -} - Future showErrorDialog(String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String? error, Function? onDismissed}) async { String _error = error ?? L10().error; @@ -98,7 +75,19 @@ Future showErrorDialog(String title, String description, {IconData icon = }); } -Future showServerError(String title, String description) async { +/* + * Display a message indicating the nature of a server / API error + */ +Future showServerError(String url, String title, String description) async { + + if (!OneContext.hasContext) { + return; + } + + // We ignore error messages for certain URLs + if (url.contains("notifications")) { + return; + } if (title.isEmpty) { title = L10().serverError; @@ -126,7 +115,10 @@ Future showServerError(String title, String description) async { ); } -Future showStatusCodeError(int status) async { +/* + * Displays an error indicating that the server returned an unexpected status code + */ +Future showStatusCodeError(String url, int status) async { String msg = L10().responseInvalid; String extra = "${L10().statusCode}: ${status}"; @@ -173,68 +165,16 @@ Future showStatusCodeError(int status) async { } showServerError( + url, msg, extra, ); } -Future showTimeoutError() async { - await showServerError(L10().timeout, L10().noResponse); + +/* + * Displays a message indicating that the server timed out on a certain request + */ +Future showTimeoutError(String url) async { + await showServerError(url, L10().timeout, L10().noResponse); } - -void showFormDialog(String title, {String? acceptText, String? cancelText, GlobalKey? key, List? fields, Function? callback}) { - - - String _accept = acceptText ?? L10().save; - String _cancel = cancelText ?? L10().cancel; - - List _fields = fields ?? []; - - OneContext().showDialog( - builder: (BuildContext context) { - return AlertDialog( - title: Text(title), - actions: [ - TextButton( - child: Text(_cancel), - onPressed: () { - // Close the form - Navigator.pop(context); - } - ), - TextButton( - child: Text(_accept), - onPressed: () { - - var _key = key; - - if (_key != null && _key.currentState != null) { - if (_key.currentState!.validate()) { - _key.currentState!.save(); - - Navigator.pop(context); - - // Callback - if (callback != null) { - callback(); - } - } - } - } - ) - ], - content: Form( - key: key, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: _fields - ) - ) - ) - ); - } - ); -} \ No newline at end of file From aac215678b2f99091f9c5aefb2dbfa90894c42da Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 3 Jun 2022 20:26:56 +1000 Subject: [PATCH 172/746] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 844a040..00ec0c7 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Android](https://github.com/inventree/inventree-app/actions/workflows/android.yaml/badge.svg) ![iOS](https://github.com/inventree/inventree-app/actions/workflows/ios.yaml/badge.svg) +[![Coverage Status](https://coveralls.io/repos/github/inventree/inventree-app/badge.svg?branch=master)](https://coveralls.io/github/inventree/inventree-app?branch=master) The InvenTree mobile / tablet application is a companion app for the [InvenTree stock management system](https://github.com/inventree/InvenTree). From 21e7a976eef43ecd611cff5cafe2cd7aecfa2e20 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 20:42:25 +1000 Subject: [PATCH 173/746] Improve checks for API user permissions --- .github/workflows/ci.yaml | 1 + lib/api.dart | 8 ++++++-- test/api_test.dart | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f3ae7c7..f2f695a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -60,6 +60,7 @@ jobs: invoke import-fixtures invoke server -a 127.0.0.1:12345 & invoke wait + sleep 30 - name: Unit Tests run: | flutter test --coverage diff --git a/lib/api.dart b/lib/api.dart index edb2687..63f29db 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -497,7 +497,7 @@ class InvenTreeAPI { /* * Request the user roles (permissions) from the InvenTree server */ - Future getUserRoles() async { + Future getUserRoles() async { roles.clear(); @@ -511,7 +511,7 @@ class InvenTreeAPI { final response = await get(_URL_GET_ROLES, expectedStatusCode: 200); if (!response.successful()) { - return; + return false; } var data = response.asMap(); @@ -519,6 +519,10 @@ class InvenTreeAPI { if (data.containsKey("roles")) { // Save a local copy of the user roles roles = (response.data["roles"] ?? {}) as Map; + + return true; + } else { + return false; } } diff --git a/test/api_test.dart b/test/api_test.dart index 4f9723b..fdc3ad6 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -129,10 +129,13 @@ void main() { assert(api.supportsNotifications); assert(api.supportsPoReceive); + // Ensure we can request (and receive) user roles + assert(await api.getUserRoles()); + // Check available permissions assert(api.checkPermission("part", "change")); assert(api.checkPermission("stocklocation", "delete")); - assert(api.checkPermission("part", "weirdpermission")); + assert(!api.checkPermission("part", "weirdpermission")); assert(api.checkPermission("blah", "bloo")); }); From 17696936870c4ffde5cba715ab76e0624418ec2a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 20:55:17 +1000 Subject: [PATCH 174/746] Initial tests for grabbing model data from server --- test/models_test.dart | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/models_test.dart diff --git a/test/models_test.dart b/test/models_test.dart new file mode 100644 index 0000000..7cd21b8 --- /dev/null +++ b/test/models_test.dart @@ -0,0 +1,54 @@ +/* + * Unit tests for accessing various model classes via the API + */ + +import 'package:inventree/inventree/model.dart'; +import "package:test/test.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/user_profile.dart"; +import "package:inventree/inventree/part.dart"; + + +void main() { + + setUp(() async { + await UserProfileDBManager().addProfile(UserProfile( + name: "Test Profile", + server: "http://localhost:12345", + username: "testuser", + password: "testpassword", + selected: true, + )); + + assert(await UserProfileDBManager().selectProfileByName("Test Profile")); + assert(await InvenTreeAPI().connectToServer()); + }); + + group("Part Tests:", () { + + test("List Parts", () async { + List results; + + // List *all* parts + results = await InvenTreePart().list(); + assert(results.length == 13); + + for (var result in results) { + // results must be InvenTreePart instances + assert(result is InvenTreePart); + } + + // Filter by category + results = await InvenTreePart().list( + filters: { + "category": "2", + } + ); + + assert(results.length == 2); + }); + + }); + +} \ No newline at end of file From 7d1735b1b7129888026e9841bfdd37b4063c9bbd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 20:57:08 +1000 Subject: [PATCH 175/746] Fix import quotes --- test/models_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models_test.dart b/test/models_test.dart index 7cd21b8..3cd6bec 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -2,7 +2,7 @@ * Unit tests for accessing various model classes via the API */ -import 'package:inventree/inventree/model.dart'; +import "package:inventree/inventree/model.dart"; import "package:test/test.dart"; import "package:inventree/api.dart"; From 8ee10a342449821de115d693a4325ef798f8ea82 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 21:14:39 +1000 Subject: [PATCH 176/746] Adds more unit tests for the part model --- test/models_test.dart | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test/models_test.dart b/test/models_test.dart index 3cd6bec..91aac97 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -27,6 +27,10 @@ void main() { group("Part Tests:", () { + test("Basics", () async { + assert(InvenTreePart().URL == "part/"); + }); + test("List Parts", () async { List results; @@ -49,6 +53,64 @@ void main() { assert(results.length == 2); }); + test("Part Detail", () async { + final result = await InvenTreePart().get(1); + + assert(result != null); + assert(result is InvenTreePart); + + if (result != null) { + InvenTreePart part = result as InvenTreePart; + + // Check some basic properties of the part + assert(part.name == "M2x4 LPHS"); + assert(part.fullname == "M2x4 LPHS"); + assert(part.description == "M2x4 low profile head screw"); + assert(part.categoryId == 8); + assert(part.categoryName == "Fasteners"); + assert(part.image == part.thumbnail); + assert(part.thumbnail == "/static/img/blank_image.thumbnail.png"); + + // Stock information + assert(part.unallocatedStockString == "9000"); + assert(part.inStockString == "9000"); + } + + }); + + test("Part Adjust", () async { + // Test that we can update part data + final result = await InvenTreePart().get(1); + + assert(result != null); + assert(result is InvenTreePart); + + if (result != null) { + InvenTreePart part = result as InvenTreePart; + assert(part.name == "M2x4 LPHS"); + + // Change the name to something else + assert(await part.update( + values: { + "name": "Woogle", + } + )); + + assert(await part.reload()); + assert(part.name == "Woogle"); + + // And change it back again + assert(await part.update( + values: { + "name": "M2x4 LPHS" + } + )); + + assert(await part.reload()); + assert(part.name == "M2x4 LPHS"); + } + }); + }); } \ No newline at end of file From b40a0f8dad5a260e0915e7295f2e41613341649d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 3 Jun 2022 21:23:22 +1000 Subject: [PATCH 177/746] Adds basic unit tests for part category --- test/models_test.dart | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/models_test.dart b/test/models_test.dart index 91aac97..e3d8814 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -25,6 +25,33 @@ void main() { assert(await InvenTreeAPI().connectToServer()); }); + group("Category Tests:", () { + test("Basics", () async { + assert(InvenTreePartCategory().URL == "part/category/"); + }); + + test("List Categories", () async { + List results; + + // List *all* categories + results = await InvenTreePartCategory().list(); + assert(results.length == 8); + + for (var result in results) { + assert(result is InvenTreePartCategory); + } + + // Filter by parent category + results = await InvenTreePartCategory().list( + filters: { + "parent": "1", + } + ); + + assert(results.length == 3); + }); + }); + group("Part Tests:", () { test("Basics", () async { From 10783cd1c44a9ae777fe656827564b2351143945 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 00:12:44 +1000 Subject: [PATCH 178/746] Refactor PartAttachmentWidget - Now displays generic attachments - Augment the InvenTreeAttachment class to "know" about its model reference --- lib/inventree/model.dart | 15 ++- lib/inventree/part.dart | 3 + ...nts_widget.dart => attachment_widget.dart} | 91 ++++++++++--------- lib/widget/part_detail.dart | 7 +- 4 files changed, 67 insertions(+), 49 deletions(-) rename lib/widget/{part_attachments_widget.dart => attachment_widget.dart} (50%) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 5d55e9f..75d31a4 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -636,6 +636,9 @@ class InvenTreeAttachment extends InvenTreeModel { InvenTreeAttachment.fromJson(Map json) : super.fromJson(json); + // Override this reference field for any subclasses + String get REFERENCE_FIELD => ""; + String get attachment => (jsondata["attachment"] ?? "") as String; // Return the filename of the attachment @@ -684,19 +687,27 @@ class InvenTreeAttachment extends InvenTreeModel { } } - Future uploadAttachment(File attachment, {String comment = "", Map fields = const {}}) async { + Future uploadAttachment(File attachment, int parentId, {String comment = "", Map fields = const {}}) async { + + // Ensure that the correct reference field is set + Map data = Map.from(fields); + + data[REFERENCE_FIELD] = parentId.toString(); final APIResponse response = await InvenTreeAPI().uploadFile( URL, attachment, method: "POST", name: "attachment", - fields: fields + fields: data ); return response.successful(); } + /* + * Download this attachment file + */ Future downloadAttachment() async { await InvenTreeAPI().downloadFile(attachment); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 7467012..c528a58 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -422,6 +422,9 @@ class InvenTreePartAttachment extends InvenTreeAttachment { InvenTreePartAttachment.fromJson(Map json) : super.fromJson(json); + @override + String get REFERENCE_FIELD => "part"; + @override String get URL => "part/attachment/"; diff --git a/lib/widget/part_attachments_widget.dart b/lib/widget/attachment_widget.dart similarity index 50% rename from lib/widget/part_attachments_widget.dart rename to lib/widget/attachment_widget.dart index 5fada01..e590325 100644 --- a/lib/widget/part_attachments_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -1,33 +1,42 @@ +/* + * A generic widget for displaying a list of attachments. + * + * To allow use with different "types" of attachments, + * we pass a subclassed instance of the InvenTreeAttachment model. + */ + import "dart:io"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/model.dart"; import "package:inventree/widget/fields.dart"; -import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; - -import "package:inventree/api.dart"; +import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; -class PartAttachmentsWidget extends StatefulWidget { +class AttachmentWidget extends StatefulWidget { - const PartAttachmentsWidget(this.part, {Key? key}) : super(key: key); + const AttachmentWidget(this.attachment, this.referenceId, this.hasUploadPermission) : super(); - final InvenTreePart part; + final InvenTreeAttachment attachment; + final int referenceId; + final bool hasUploadPermission; @override - _PartAttachmentDisplayState createState() => _PartAttachmentDisplayState(part); + _AttachmentWidgetState createState() => _AttachmentWidgetState(attachment, referenceId, hasUploadPermission); } -class _PartAttachmentDisplayState extends RefreshableState { +class _AttachmentWidgetState extends RefreshableState { - _PartAttachmentDisplayState(this.part); + _AttachmentWidgetState(this.attachment, this.referenceId, this.hasUploadPermission); - final InvenTreePart part; + final InvenTreeAttachment attachment; + final int referenceId; + final bool hasUploadPermission; - List attachments = []; + List attachments = []; @override String getAppBarTitle(BuildContext context) => L10().attachments; @@ -37,20 +46,19 @@ class _PartAttachmentDisplayState extends RefreshableState actions = []; - if (InvenTreeAPI().checkPermission("part", "change")) { - + if (hasUploadPermission) { // File upload actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), - onPressed: () async { - FilePickerDialog.pickFile( - onPicked: (File file) { - upload(file); - } - ); - }, - ) + IconButton( + icon: FaIcon(FontAwesomeIcons.plusCircle), + onPressed: () async { + FilePickerDialog.pickFile( + onPicked: (File file) { + upload(file); + } + ); + }, + ) ); } @@ -58,12 +66,8 @@ class _PartAttachmentDisplayState extends RefreshableState upload(File file) async { - final bool result = await InvenTreePartAttachment().uploadAttachment( - file, - fields: { - "part": "${part.pk}" - } - ); + + final bool result = await attachment.uploadAttachment(file, referenceId); if (result) { showSnackIcon(L10().uploadSuccess, success: true); @@ -77,32 +81,31 @@ class _PartAttachmentDisplayState extends RefreshableState request(BuildContext context) async { - await InvenTreePartAttachment().list( + await attachment.list( filters: { - "part": "${part.pk}" + attachment.REFERENCE_FIELD: referenceId.toString() } ).then((var results) { attachments.clear(); for (var result in results) { - if (result is InvenTreePartAttachment) { + if (result is InvenTreeAttachment) { attachments.add(result); } } }); - } @override Widget getBody(BuildContext context) { return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: attachmentTiles(context) - ).toList(), - ) + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: attachmentTiles(context) + ).toList(), + ) ); } @@ -126,14 +129,12 @@ class _PartAttachmentDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => PartAttachmentsWidget(part) + builder: (context) => AttachmentWidget( + InvenTreePartAttachment(), + part.pk, + InvenTreeAPI().checkPermission("part", "change")) ) ); }, From fcfda4ebff784464fdbf0c6b1c4552c2fe0e1c4c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 00:15:34 +1000 Subject: [PATCH 179/746] Display number of attachments on part view --- lib/widget/part_detail.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index b260739..376d548 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -39,6 +39,8 @@ class _PartDisplayState extends RefreshableState { InvenTreePart? parentPart; + int attachmentCount = 0; + @override String getAppBarTitle(BuildContext context) => L10().partDetails; @@ -110,6 +112,12 @@ class _PartDisplayState extends RefreshableState { } await part.getTestTemplates(); + + attachmentCount = await InvenTreePartAttachment().count( + filters: { + "part": part.pk.toString() + } + ); } Future _toggleStar() async { @@ -405,7 +413,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().attachments), leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), - trailing: Text(""), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( context, From ada64f397143c65700650ebd426077343046ed4c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 00:23:10 +1000 Subject: [PATCH 180/746] Adds attachment support for the StockItem model --- lib/inventree/part.dart | 4 +++- lib/inventree/stock.dart | 23 +++++++++++++++++++++++ lib/widget/stock_detail.dart | 28 ++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index c528a58..85ee6d8 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -415,7 +415,9 @@ class InvenTreePart extends InvenTreeModel { } } - +/* + * Class representing an attachment file against a Part object + */ class InvenTreePartAttachment extends InvenTreeAttachment { InvenTreePartAttachment() : super(); diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index b60eb95..46b0c75 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -601,6 +601,29 @@ class InvenTreeStockItem extends InvenTreeModel { } +/* + * Class representing an attachment file against a StockItem object + */ +class InvenTreeStockItemAttachment extends InvenTreeAttachment { + + InvenTreeStockItemAttachment() : super(); + + InvenTreeStockItemAttachment.fromJson(Map json) : super.fromJson(json); + + @override + String get REFERENCE_FIELD => "stock_item"; + + @override + String get URL => "stock/attachment/"; + + @override + InvenTreeModel createFromJson(Map json) { + return InvenTreeStockItemAttachment.fromJson(json); + } + +} + + class InvenTreeStockLocation extends InvenTreeModel { InvenTreeStockLocation() : super(); diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 8c1a376..d8c43ad 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -7,6 +7,7 @@ import "package:inventree/barcode.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/progress.dart"; @@ -94,6 +95,8 @@ class _StockItemDisplayState extends RefreshableState { // Part object InvenTreePart? part; + int attachmentCount = 0; + @override Future onBuild(BuildContext context) async { @@ -126,6 +129,12 @@ class _StockItemDisplayState extends RefreshableState { }); }); + attachmentCount = await InvenTreeStockItemAttachment().count( + filters: { + "stock_item": item.pk.toString() + } + ); + // Request information on labels available for this stock item if (InvenTreeAPI().pluginsEnabled()) { _getLabels(); @@ -694,6 +703,25 @@ class _StockItemDisplayState extends RefreshableState { ) ); + tiles.add( + ListTile( + title: Text(L10().attachments), + leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeStockItemAttachment(), + item.pk, + InvenTreeAPI().checkPermission("stock", "change")) + ) + ); + }, + ) + ); + return tiles; } From 0237e9c819d42973d478ce15948df8c766defed5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 00:28:39 +1000 Subject: [PATCH 181/746] Adds attachment support for purchase orders --- lib/inventree/purchase_order.dart | 21 +++++++++++++++++++ lib/widget/purchase_order_detail.dart | 29 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 6b8595c..59dff7e 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -203,3 +203,24 @@ class InvenTreePOLineItem extends InvenTreeModel { return InvenTreePOLineItem.fromJson(json); } } + +/* + * Class representing an attachment file against a StockItem object + */ +class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { + + InvenTreePurchaseOrderAttachment() : super(); + + InvenTreePurchaseOrderAttachment.fromJson(Map json) : super.fromJson(json); + + @override + String get REFERENCE_FIELD => "order"; + + @override + String get URL => "order/po/attachment/"; + + @override + InvenTreeModel createFromJson(Map json) { + return InvenTreePurchaseOrderAttachment.fromJson(json); + } +} diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 2abe56c..2b51144 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -9,6 +9,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/company_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; @@ -37,6 +38,8 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { @@ -177,6 +186,26 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreePurchaseOrderAttachment(), + order.pk, + InvenTreeAPI().checkPermission("purchase_order", "change")) + ) + ); + }, + ) + ); + return tiles; } From 302532f5a4bc6094b776cbabcb74c9d54e381dd3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 00:34:50 +1000 Subject: [PATCH 182/746] Update release notes --- assets/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index a330e6f..1754b7c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,8 @@ --- - Add "quarantined" status flag for stock items +- Extends attachment support to stock items +- Extends attachment support to purchase orders ### 0.7.1 - May 2022 --- From 2a685a743f425538562db8f35fe1ef2d2fdc6d45 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 4 Jun 2022 09:31:34 +1000 Subject: [PATCH 183/746] Wrap search queries in permission checks --- lib/widget/search.dart | 104 +++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/lib/widget/search.dart b/lib/widget/search.dart index c2bc63f..4966247 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -8,6 +8,7 @@ import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/purchase_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/api.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; @@ -115,6 +116,8 @@ class _SearchDisplayState extends RefreshableState { */ Future search(String term) async { + var api = InvenTreeAPI(); + setState(() { // Do not search on an empty string nPartResults = 0; @@ -132,45 +135,53 @@ class _SearchDisplayState extends RefreshableState { } // Search parts - InvenTreePart().count(searchQuery: term).then((int n) { - if (term == searchController.text) { - setState(() { - nPartResults = n; - nSearchResults++; - }); - } - }); + if (api.checkPermission("part", "view")) { + InvenTreePart().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nPartResults = n; + nSearchResults++; + }); + } + }); + } // Search part categories - InvenTreePartCategory().count(searchQuery: term,).then((int n) { - if (term == searchController.text) { - setState(() { - nCategoryResults = n; - nSearchResults++; - }); - } - }); + if (api.checkPermission("part_category", "view")) { + InvenTreePartCategory().count(searchQuery: term,).then((int n) { + if (term == searchController.text) { + setState(() { + nCategoryResults = n; + nSearchResults++; + }); + } + }); + } // Search stock items - InvenTreeStockItem().count(searchQuery: term).then((int n) { - if (term == searchController.text) { - setState(() { - nStockResults = n; - nSearchResults++; - }); - } - }); + if (api.checkPermission("stock", "view")) { + InvenTreeStockItem().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nStockResults = n; + nSearchResults++; + }); + } + }); + } // Search stock locations - InvenTreeStockLocation().count(searchQuery: term).then((int n) { - if (term == searchController.text) { - setState(() { - nLocationResults = n; + if (api.checkPermission("stock_location", "view")) { + InvenTreeStockLocation().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + setState(() { + nLocationResults = n; - nSearchResults++; - }); - } - }); + nSearchResults++; + }); + } + }); + } // TDOO: Re-implement this once display for companies has been fixed /* @@ -188,20 +199,21 @@ class _SearchDisplayState extends RefreshableState { */ // Search purchase orders - InvenTreePurchaseOrder().count( - searchQuery: term, - filters: { - "outstanding": "true" - } - ).then((int n) { - if (term == searchController.text) { - setState(() { - nPurchaseOrderResults = n; - nSearchResults++; - }); - } - }); - + if (api.checkPermission("purchase_order", "view")) { + InvenTreePurchaseOrder().count( + searchQuery: term, + filters: { + "outstanding": "true" + } + ).then((int n) { + if (term == searchController.text) { + setState(() { + nPurchaseOrderResults = n; + nSearchResults++; + }); + } + }); + } } List _tiles(BuildContext context) { From 3d0afa37986265a3a9e7973728734c20b69c4646 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 5 Jun 2022 00:03:03 +1000 Subject: [PATCH 184/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index da16480..074bdbb 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -453,6 +453,8 @@ "@quantityInvalid": {}, "quantityPositive": "Mennyiség pozitív kell legyen", "@quantityPositive": {}, + "quarantined": "Karanténban", + "@quarantined": {}, "queryEmpty": "Add meg a keresési lekérdezést", "@queryEmpty": {}, "queryNoResults": "Nincs találat", From f0d91b12de874f5bf220c8d91e3348ad83496dfd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 Jun 2022 09:46:12 +1000 Subject: [PATCH 185/746] Bump release version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 96f91d0..16a3506 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.7.1+43 +version: 0.7.2+44 environment: sdk: ">=2.16.0 <3.0.0" From 4a695fa4efcc53fbe752add396492de4d314b76e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Jun 2022 21:15:58 +1000 Subject: [PATCH 186/746] String fixes --- assets/release_notes.md | 5 +++++ lib/l10n/app_en.arb | 4 ++-- lib/widget/attachment_widget.dart | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 1754b7c..4c172f6 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.7.3 - June 2022 +--- + +- + ### 0.7.2 - June 2022 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 64223dd..332692e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -67,8 +67,8 @@ "attachmentNone": "No attachments found", "@attachmentNone": {}, - "attachmentNonePartDetail": "No attachments found for this part", - "@attachmentNonePartDetail": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, "attachmentSelect": "Select attachment", "@attachmentSelect": {}, diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index e590325..9653553 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -129,7 +129,7 @@ class _AttachmentWidgetState extends RefreshableState { tiles.add(ListTile( title: Text(L10().attachmentNone), subtitle: Text( - L10().attachmentNonePartDetail, + L10().attachmentNoneDetail, style: TextStyle(fontStyle: FontStyle.italic), ), )); From 590036f08202ab63a3f436548d6b296d7a67572c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:03 +1000 Subject: [PATCH 187/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 780036a..dcff556 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -48,8 +48,6 @@ }, "attachmentNone": "Aucune pièce jointe trouvée", "@attachmentNone": {}, - "attachmentNonePartDetail": "Aucune pièce jointe trouvée pour cette pièce", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Sélectionner une pièce jointe", "@attachmentSelect": {}, "attention": "Avertissement", From d1bd8890c009091f5e7e91326a630849d13dd962 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:04 +1000 Subject: [PATCH 188/746] New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 1848474..337d917 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -40,8 +40,6 @@ }, "attachmentNone": "Não foram encontrados quaisquer anexos", "@attachmentNone": {}, - "attachmentNonePartDetail": "Nenhum anexo encontrado para esta peça", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Selecionar anexo", "@attachmentSelect": {}, "attention": "Aviso", From c534f4196d2d144619dfadb1d90f0b9db8cbaf8b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:10 +1000 Subject: [PATCH 189/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 8008b52..be4ac63 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -44,8 +44,6 @@ }, "attachmentNone": "Hiçbir ek bulunamadı", "@attachmentNone": {}, - "attachmentNonePartDetail": "Bu parça için ekler bulunamadı", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Ek seçin", "@attachmentSelect": {}, "attention": "Dikkat", From 5a0e5d252d8aadc5fafde6cb49ae936520cb015d Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:13 +1000 Subject: [PATCH 190/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index d499412..dd9103d 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -40,8 +40,6 @@ }, "attachmentNone": "Nie znaleziono załączników", "@attachmentNone": {}, - "attachmentNonePartDetail": "Brak załączników dla tego komponentu", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Wybierz załącznik", "@attachmentSelect": {}, "attention": "Uwaga", From bc8514026464c79069348e5a3231e6ef57c52a52 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:15 +1000 Subject: [PATCH 191/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index a34a62c..1f997a6 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -48,8 +48,6 @@ }, "attachmentNone": "Geen bijlagen gevonden", "@attachmentNone": {}, - "attachmentNonePartDetail": "Geen bijlagen voor dit onderdeel gevonden", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Bijlage selecteren", "@attachmentSelect": {}, "attention": "Let op", From 3db0f004c2a2efd880cff11736d4ecd4ec4a3fbd Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:17 +1000 Subject: [PATCH 192/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 2eb648e..fa56abe 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -40,8 +40,6 @@ }, "attachmentNone": "添付ファイルが見つかりません。", "@attachmentNone": {}, - "attachmentNonePartDetail": "この部品の添付ファイルが見つかりません", - "@attachmentNonePartDetail": {}, "attachmentSelect": "添付ファイルを選択", "@attachmentSelect": {}, "attention": "注意", From e7be7b4bf2e5a543ebd7cb3b3f79e22fa0be69c1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:18 +1000 Subject: [PATCH 193/746] New translations app_en.arb (Italian) --- lib/l10n/it_IT/app_it_IT.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index b9a1b84..e8ca508 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -36,8 +36,6 @@ }, "attachmentNone": "Nessun allegato trovato", "@attachmentNone": {}, - "attachmentNonePartDetail": "Nessun allegato trovato in questa parte", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Seleziona allegato", "@attachmentSelect": {}, "attention": "Attenzione", From fe5587b3eb20637ccaf3ebc6cb149cb76bed3708 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:19 +1000 Subject: [PATCH 194/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 074bdbb..988deb3 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -48,8 +48,6 @@ }, "attachmentNone": "Nem találhatók mellékletek", "@attachmentNone": {}, - "attachmentNonePartDetail": "Nincsenek mellékletek ehhez az alkarészhez", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Melléklet kiválasztása", "@attachmentSelect": {}, "attention": "Figyelem", From 46dd454c4ae9d0c60fef61303d5657bf64604e6e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 7 Jun 2022 00:47:22 +1000 Subject: [PATCH 195/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 35469d5..7e00186 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -48,8 +48,6 @@ }, "attachmentNone": "Keine Anhänge gefunden", "@attachmentNone": {}, - "attachmentNonePartDetail": "Keine Anhänge für dieses Teil gefunden", - "@attachmentNonePartDetail": {}, "attachmentSelect": "Anhang auswählen", "@attachmentSelect": {}, "attention": "Achtung", From 184de1c01e67e4765e744e5c187a200c066dc438 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 Jun 2022 04:35:29 +1000 Subject: [PATCH 196/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 988deb3..c938253 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -48,6 +48,8 @@ }, "attachmentNone": "Nem találhatók mellékletek", "@attachmentNone": {}, + "attachmentNoneDetail": "Nem találhatók mellékletek", + "@attachmentNoneDetail": {}, "attachmentSelect": "Melléklet kiválasztása", "@attachmentSelect": {}, "attention": "Figyelem", From deb8666172c9f2c2e9903113c00149cd948f189a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 14 Jun 2022 00:23:42 +1000 Subject: [PATCH 197/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 266 ++++++++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 1 deletion(-) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 1f997a6..cb8e10c 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -48,6 +48,8 @@ }, "attachmentNone": "Geen bijlagen gevonden", "@attachmentNone": {}, + "attachmentNoneDetail": "Geen bijlage gevonden", + "@attachmentNoneDetail": {}, "attachmentSelect": "Bijlage selecteren", "@attachmentSelect": {}, "attention": "Let op", @@ -367,20 +369,74 @@ "@partNoResults": {}, "partsStarred": "Geabonneerde Onderdelen", "@partsStarred": {}, + "partSuppliers": "Onderdeel Leveranciers", + "@partSuppliers": {}, + "partCategory": "Onderdeel Categorie", + "@partCategory": {}, + "partCategoryTopLevel": "Hoogste onderdeel categorie", + "@partCategoryTopLevel": {}, + "partCategories": "Onderdeel Categorieën", + "@partCategories": {}, + "partDetails": "Details Onderdeel", + "@partDetails": {}, + "partStock": "Voorraad Onderdeel", + "@partStock": { + "description": "part stock" + }, "password": "Wachtwoord", "@password": {}, "passwordEmpty": "Wachtwoord mag niet leeg zijn", "@passwordEmpty": {}, "permissionAccountDenied": "U heeft niet de vereiste rechten om deze actie uit te voeren", "@permissionAccountDenied": {}, + "permissionRequired": "Toestemming Vereist", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, "pluginPrinter": "Printer", "@pluginPrinter": {}, + "pluginSupport": "Plugin Ondersteuning Ingeschakeld", + "@pluginSupport": {}, + "pluginSupportDetail": "De server ondersteunt eigen plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label drukken mislukt", + "@printLabelFailure": {}, + "printLabelSuccess": "Label verzonden naar printer", + "@printLabelSuccess": {}, + "profile": "Profiel", + "@profile": {}, + "profileAdd": "Serverprofiel toevoegen", + "@profileAdd": {}, + "profileConnect": "Verbinden met Server", + "@profileConnect": {}, + "profileEdit": "Serverprofiel Aanpassen", + "@profileEdit": {}, + "profileDelete": "Serverprofiel Verwijderen", + "@profileDelete": {}, + "profileName": "Profielnaam", + "@profileName": {}, + "profileNone": "Geen profielen beschikbaar", + "@profileNone": {}, "profileNotSelected": "Geen Profiel Geselecteerd", "@profileNotSelected": {}, "profileSelect": "Selecteer InvenTree Server", "@profileSelect": {}, + "profileSelectOrCreate": "Selecteer server of maak een nieuw profiel aan", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tik om een profiel aan te maken of te selecteren", + "@profileTapToCreate": {}, + "purchaseOrder": "Inkooporder", + "@purchaseOrder": {}, + "purchaseOrderEdit": "Bewerk Inkooporder", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Inkooporders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Inkooporder bijgewerkt", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Inkoopprijs", + "@purchasePrice": {}, "quantity": "Aantal", "@quantity": { "description": "Quantity" @@ -391,12 +447,18 @@ "@quantityInvalid": {}, "quantityPositive": "Aantal moet positief zijn", "@quantityPositive": {}, + "quarantined": "In quarantaine geplaatst", + "@quarantined": {}, "queryEmpty": "Voer zoekterm in", "@queryEmpty": {}, "queryNoResults": "Geen resultaten", "@queryNoResults": {}, "received": "Ontvangen", "@received": {}, + "receiveItem": "Ontvang Artikel", + "@receiveItem": {}, + "receivedItem": "Ontvangen Voorraad Artikelen", + "@receivedItem": {}, "refresh": "Vernieuwen", "@refresh": {}, "refreshing": "Verversen…", @@ -419,6 +481,12 @@ "@reportBugDescription": {}, "results": "Resultaten", "@results": {}, + "request": "Verzoek", + "@request": {}, + "requestSuccessful": "Verzoek successvol", + "@requestSuccessful": {}, + "requestingData": "Gegevens Opvragen", + "@requestingData": {}, "required": "Vereist", "@required": { "description": "This field is required" @@ -447,6 +515,14 @@ "@response504": {}, "response505": "HTTP Version Not Supported", "@response505": {}, + "responseData": "Responsgegevens", + "@responseData": {}, + "result": "Resultaat", + "@result": { + "description": "" + }, + "returned": "Teruggestuurd", + "@returned": {}, "salesOrders": "Verkooporders", "@salesOrders": {}, "save": "Bewaren", @@ -455,12 +531,18 @@ }, "scanBarcode": "Streepjescode Scannen", "@scanBarcode": {}, + "scanIntoLocation": "Scan Naar Locatie", + "@scanIntoLocation": {}, "search": "Zoeken", "@search": { "description": "search" }, "searching": "Zoeken...", "@searching": {}, + "searchLocation": "Zoeken naar locatie", + "@searchLocation": {}, + "searchParts": "Zoek Onderdelen", + "@searchParts": {}, "searchStock": "Zoek Voorraad", "@searchStock": {}, "select": "Selecteer", @@ -477,6 +559,188 @@ "@serialNumber": {}, "server": "Server", "@server": {}, + "serverAddress": "Server Adres", + "@serverAddress": {}, + "serverApiRequired": "Vereiste API Versie", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Versie", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authenticatiefout", + "@serverAuthenticationError": {}, + "serverCertificateError": "Certificaatfout", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificaat is ongeldig", + "@serverCertificateInvalid": {}, + "serverConnected": "Verbonden met Server", + "@serverConnected": {}, + "serverConnecting": "Verbinden met server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Kan geen verbinding maken met de server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server kan niet leeg zijn", + "@serverEmpty": {}, + "serverError": "Serverfout", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverOld": "Oude Serverversie", + "@serverOld": {}, + "serverSettings": "Serverinstellingen", + "@serverSettings": {}, + "serverStart": "Server moet beginnen met http[s]", + "@serverStart": {}, + "settings": "Instellingen", + "@settings": {}, + "serverInstance": "Serverinstantie", + "@serverInstance": {}, + "serverNotConnected": "Server niet verbonden", + "@serverNotConnected": {}, + "sounds": "Geluid", + "@sounds": {}, "soundOnBarcodeAction": "Speel hoorbare toon bij streepjescode actie", - "@soundOnBarcodeAction": {} + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Speel hoorbare toon af bij serverfout", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuscode", + "@statusCode": {}, + "stock": "Voorraad", + "@stock": { + "description": "stock" + }, + "stockDetails": "Huidige beschikbare voorraad", + "@stockDetails": {}, + "stockItem": "Voorraadartikel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Voorraadartikelen", + "@stockItems": {}, + "stockItemCreate": "Nieuw Voorraadartikel", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Voeg een nieuw voorraadartikel toe aan deze locatie", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Verwijder Voorraadartikel", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Weet u zeker dat u dit voorraadartikel wil verwijderen?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Kon voorraadartikel niet verwijderen", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Voorraadartikel verwijderd", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Voorraad Geschiedenis", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Toon historische voorraad tracking informatie", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Voorraadartikel verplaatst", + "@stockItemTransferred": {}, + "stockItemUpdated": "Voorraadartikel bijgewerkt", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Geen voorraadartikel beschikbaar", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Opmerkingen Voorraadartikel", + "@stockItemNotes": {}, + "stockLocation": "Voorraadlocatie", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Voorraadlocaties", + "@stockLocations": {}, + "strictHttps": "Gebruik Strict HTTPS", + "@strictHttps": {}, + "subcategory": "Subcategorie", + "@subcategory": {}, + "subcategories": "Subcategorieën", + "@subcategories": {}, + "sublocation": "Sublocatie", + "@sublocation": {}, + "sublocations": "Sublocaties", + "@sublocations": {}, + "sublocationNone": "Geen Sublocaties", + "@sublocationNone": {}, + "sublocationNoneDetail": "Geen sublocaties beschikbaar", + "@sublocationNoneDetail": {}, + "submitFeedback": "Feedback Indienen", + "@submitFeedback": {}, + "suppliedParts": "Geleverde Onderdelen", + "@suppliedParts": {}, + "supplier": "Leverancier", + "@supplier": {}, + "suppliers": "Leveranciers", + "@suppliers": {}, + "supplierReference": "Leveranciers Referentie", + "@supplierReference": {}, + "takePicture": "Neem een Foto", + "@takePicture": {}, + "targetDate": "Streefdatum", + "@targetDate": {}, + "testName": "Test Naam", + "@testName": {}, + "testPassedOrFailed": "Test geslaagd of mislukt", + "@testPassedOrFailed": {}, + "testsRequired": "Vereiste Tests", + "@testsRequired": {}, + "testResults": "Testresultaten", + "@testResults": { + "description": "" + }, + "testResultAdd": "Voeg Testresultaat Toe", + "@testResultAdd": {}, + "testResultNone": "Geen Testresultaten", + "@testResultNone": {}, + "testResultNoneDetail": "Geen testresultaten beschikbaar", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fout bij uploaden testresultaat", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testresultaat geüpload", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Fout", + "@tokenError": {}, + "tokenMissing": "Ontbrekende Token", + "@tokenMissing": {}, + "transfer": "Verplaats", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Voorraad Verplaatsen", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Vertalen", + "@translate": {}, + "translateHelp": "Help de InvenTree app te vertalen", + "@translateHelp": {}, + "units": "Eenheden", + "@units": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "Bestand uploaden mislukt", + "@uploadFailed": {}, + "uploadSuccess": "Bestand geüpload", + "@uploadSuccess": {}, + "usedIn": "Wordt Gebruikt In", + "@usedIn": {}, + "username": "Gebruikersnaam", + "@username": {}, + "usernameEmpty": "Gebruikersnaam mag niet leeg zijn", + "@usernameEmpty": {}, + "value": "Waarde", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Waarde kan niet leeg zijn", + "@valueCannotBeEmpty": {}, + "valueRequired": "Waarde is vereist", + "@valueRequired": {}, + "version": "Versie", + "@version": {}, + "viewSupplierPart": "Bekijk Leverancier van Onderdeel", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file From a84f082bd64dc02a3f2b5b98707a9985a08da8fb Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 14 Jun 2022 12:18:58 +1000 Subject: [PATCH 198/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index cb8e10c..a4f0763 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -641,6 +641,10 @@ "@stockItemsNotAvailable": {}, "stockItemNotes": "Opmerkingen Voorraadartikel", "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Voorraadartikel bijgewerkt", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Voorraadartikel bijwerken mislukt", + "@stockItemUpdateFailure": {}, "stockLocation": "Voorraadlocatie", "@stockLocation": { "description": "stock location" From ec94e3b1d370f864a4d3d1fbcfe6d16b84bae424 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 19 Jun 2022 11:21:19 +1000 Subject: [PATCH 199/746] New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/pt_BR/app_pt_BR.arb | 443 ++++++++++++++++++++++++++++++++++- 1 file changed, 442 insertions(+), 1 deletion(-) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 36d80aa..e6658fa 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -1,5 +1,446 @@ { "@@locale": "en", + "appTitle": "CONTEXTO", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "&Sobre", + "@about": {}, + "accountDetails": "Detalhes da Conta", + "@accountDetails": {}, + "actions": "Acoes", + "@actions": { + "description": "" + }, + "actionsNone": "Nenhuma acao disponivel", + "@actionsNone": {}, + "add": "Adicionar", + "@add": { + "description": "add" + }, + "addStock": "Novo item", + "@addStock": { + "description": "add stock" + }, + "address": "Endereco", + "@address": {}, + "appAbout": "Sobre InvenTree", + "@appAbout": {}, + "appCredits": "Outros creditos do aplicativo", + "@appCredits": {}, + "appDetails": "Detalhes do aplicativo", + "@appDetails": {}, + "appReleaseNotes": "Mostrar detalhes do release", + "@appReleaseNotes": {}, + "appSettings": "Configuracoes", + "@appSettings": {}, + "appSettingsDetails": "Configuracoes do InvenTree", + "@appSettingsDetails": {}, + "attachments": "Anexos", + "@attachments": {}, + "attachImage": "Anexar imagem", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nenhum anexo encontrado", + "@attachmentNone": {}, + "attachmentNoneDetail": "Nenhum anexo encontrado", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Selecionar anexo", + "@attachmentSelect": {}, + "attention": "Atencao", + "@attention": {}, + "availableStock": "Estoque disponivel", + "@availableStock": {}, + "barcodeAssign": "Adiconar codigo de barras", + "@barcodeAssign": {}, + "barcodeAssigned": "Cod Barras adicionado", + "@barcodeAssigned": {}, + "barcodeError": "Erro ao scanear Cod Bar", + "@barcodeError": {}, + "barcodeInUse": "Cod Bar ja adiciconado", + "@barcodeInUse": {}, + "barcodeMissingHash": "Hash do cod bar nao encontrado", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Cod Bar nao encontrado", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Cod Bar inexistente", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Scanear para adicionar Cod Bar", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Scanear um Cod Bar InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scanear itens de stock na localizacao", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scanear localizacao do stock", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Localizacao scaneada", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item nao scaneado", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scanear item de estoque", + "@barcodeScanItem": {}, + "barcodeTones": "Tom de Cod Bar", + "@barcodeTones": {}, + "barcodeUnassign": "Cod Bar nao selecionado", + "@barcodeUnassign": {}, + "barcodeUnknown": "Cod Bar nao reconhecido", + "@barcodeUnknown": {}, + "batchCode": "Codigo batch", + "@batchCode": {}, + "billOfMaterials": "Conta de materiais", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "build": "Construcao", + "@build": {}, + "building": "Construindo", + "@building": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nova categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Criar categoria de produtos", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria de produtos atualizada", + "@categoryUpdated": {}, + "company": "Companhia", + "@company": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowSuppliers": "Mostrar fornecedores", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Mostrar botao de fornecedores na pagina inicial", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show fabricantes", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Mostrar botao de fabricantes no menu inicial", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Mostrar clientes", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Mostrar botao clientes na tela inicial", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Upload da imagem falhou", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Upload completo", + "@imageUploadSuccess": {}, + "inactive": "Inativo", + "@inactive": {}, + "inactiveDetail": "Este produto esta marcado como inativo", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir sub-categorias", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar sub-categorias na lista de produtos", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incuir Sub-Locacoes", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar sub-locacoes na lista", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Detalhes incompletos", + "@incompleteDetails": {}, + "internalPartNumber": "Numero interno do produto", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "Em producao", + "@inProduction": {}, + "inProductionDetail": "Este item esta em producao", + "@inProductionDetail": {}, + "invalidHost": "Hostname invalido", + "@invalidHost": {}, + "invalidHostDetails": "Hostname invalido", + "@invalidHostDetails": {}, + "invalidPart": "Produto invalido", + "@invalidPart": {}, + "invalidPartCategory": "Categoria de produto invalida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Localizacao no stock invalida", + "@invalidStockLocation": {}, + "invalidStockItem": "Item de estoque invalido", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Usuario ou senha invalidos", + "@invalidUsernamePassword": {}, + "issueDate": "Data de emissao", + "@issueDate": {}, + "itemInLocation": "Item ja na localizacao", + "@itemInLocation": {}, + "keywords": "Palavras chave", + "@keywords": {}, + "labelTemplate": "Modelo de descricao", + "@labelTemplate": {}, + "lastStocktake": "Ultimo dado de estoque", + "@lastStocktake": {}, + "lastUpdated": "Ultima atualizacao", + "@lastUpdated": {}, + "lineItem": "Linha do item", + "@lineItem": {}, + "lineItems": "Linhas do item", + "@lineItems": {}, + "locateItem": "Localizar produto no estoque", + "@locateItem": {}, + "locateLocation": "Localizar no estoque", + "@locateLocation": {}, + "locationCreate": "Nova localizacao", + "@locationCreate": {}, + "locationCreateDetail": "Criar nova localizacao no estoque", + "@locationCreateDetail": {}, + "locationNotSet": "Nenhuma localizacao especificada", + "@locationNotSet": {}, + "locationUpdated": "Localizacao no estoque atualizada", + "@locationUpdated": {}, + "link": "Link", + "@link": {}, + "lost": "Perdido", + "@lost": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "missingData": "Dados indisponiveis", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "notConnected": "Nao conectado", + "@notConnected": {}, + "notes": "Notas", + "@notes": { + "description": "Notes" + }, + "notifications": "Notificacoes", + "@notifications": {}, + "notificationsEmpty": "Nenhuma notificao pendente", + "@notificationsEmpty": {}, + "noResponse": "Sem resposta do servidor", + "@noResponse": {}, + "purchaseOrderEdit": "Editar ordem de compra", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Ordens de compras", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Ordem de compra atualizada", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Preco de compra", + "@purchasePrice": {}, + "quantity": "Quantidade", + "@quantity": { + "description": "Quantity" + }, + "quantityEmpty": "Quantidade esta em branco", + "@quantityEmpty": {}, + "quantityInvalid": "Quantidade invalida", + "@quantityInvalid": {}, + "quantityPositive": "Quantidade precisa ser positiva", + "@quantityPositive": {}, + "quarantined": "Quarantina", + "@quarantined": {}, + "queryEmpty": "Entre dados para busca", + "@queryEmpty": {}, + "queryNoResults": "Nenhuma resultado para busca", + "@queryNoResults": {}, + "received": "Recebido", + "@received": {}, + "receiveItem": "Item recebido", + "@receiveItem": {}, + "receivedItem": "Item de estoque recebido", + "@receivedItem": {}, + "refresh": "Atualizar", + "@refresh": {}, + "refreshing": "Atualizando", + "@refreshing": {}, + "rejected": "Rejeitado", + "@rejected": {}, + "releaseNotes": "Notas deste release", + "@releaseNotes": {}, + "remove": "Remover", + "@remove": { + "description": "remove" + }, + "removeStock": "Remover estoque", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Reportar erro", + "@reportBug": {}, + "reportBugDescription": "Adicionar reporte de erro (conta no github)", + "@reportBugDescription": {}, + "results": "Resultado", + "@results": {}, + "request": "Pedido", + "@request": {}, + "requestSuccessful": "Pedido recebido com sucesso", + "@requestSuccessful": {}, + "requestingData": "Requisitando dados", + "@requestingData": {}, + "required": "Requerido", + "@required": { + "description": "This field is required" + }, + "response400": "Pedido invalido", + "@response400": {}, + "response401": "Nao autorizado", + "@response401": {}, + "response403": "Permissao negada", + "@response403": {}, + "response404": "Recurso nao encontrado", + "@response404": {}, + "response405": "Metodo nao aceito", + "@response405": {}, + "response429": "Muitos pedidos no momento", + "@response429": {}, + "response500": "Erro interno", + "@response500": {}, + "response501": "Nao implementado", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Servico indisponivel", + "@response503": {}, + "response504": "Gateway expirou", + "@response504": {}, + "response505": "Versao de HTTP nao suportada", + "@response505": {}, + "responseData": "Resposta de dados", + "@responseData": {}, + "responseInvalid": "Code de resposta invalido", + "@responseInvalid": {}, + "responseUnknown": "Resposta invalida", + "@responseUnknown": {}, + "result": "Resultado", + "@result": { + "description": "" + }, + "returned": "Retornado", + "@returned": {}, + "salesOrders": "Pedido de vendas", + "@salesOrders": {}, + "save": "Salvar", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanear Cod Bar", + "@scanBarcode": {}, + "scanIntoLocation": "Scan para localizacao", + "@scanIntoLocation": {}, + "search": "Buscar", + "@search": { + "description": "search" + }, + "searching": "Buscando", + "@searching": {}, + "stockItemUpdateSuccess": "Item de estoque atualizado", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Atualizacao de item falhou", + "@stockItemUpdateFailure": {}, + "stockLocation": "Localizacao do estoque", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Localizacoes do estoque", + "@stockLocations": {}, + "stockTopLevel": "Localizacao de nivel superior", + "@stockTopLevel": {}, + "strictHttps": "Utilizar somente HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Utilizar certificados HTTPS", + "@strictHttpsDetails": {}, + "subcategory": "Sub-categoria", + "@subcategory": {}, + "subcategories": "Sub-categorias", + "@subcategories": {}, + "sublocation": "Sub-localizacao", + "@sublocation": {}, + "sublocations": "Sub-localizacoes", + "@sublocations": {}, + "sublocationNone": "Sem sub-localizacoes", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nenhuma sub-localizacao disponivel", + "@sublocationNoneDetail": {}, + "submitFeedback": "Enviar feeback", + "@submitFeedback": {}, + "suppliedParts": "Produtos selecionados", + "@suppliedParts": {}, + "supplier": "Fornecedor", + "@supplier": {}, + "suppliers": "Fornecedores", + "@suppliers": {}, + "supplierReference": "Referencia do fornecedor", + "@supplierReference": {}, + "takePicture": "Tirar foto", + "@takePicture": {}, + "targetDate": "Data alvo", + "@targetDate": {}, + "templatePart": "Modelo de produto", + "@templatePart": {}, + "testName": "Nome de teste", + "@testName": {}, + "testPassedOrFailed": "Teste passou ou falhou", + "@testPassedOrFailed": {}, + "testsRequired": "Testes necessarios", + "@testsRequired": {}, + "testResults": "Resultados do test", + "@testResults": { + "description": "" + }, + "testResultAdd": "Adicionar resultado do test", + "@testResultAdd": {}, + "testResultNone": "Nenhum resultado do test", + "@testResultNone": {}, + "testResultNoneDetail": "Nenhum resultado do teste disponivel", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Erro ao subir resultado do test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Resultado do test adicionado", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Error de token", + "@tokenError": {}, + "tokenMissing": "Token indisponivel", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token indisponivel na resposta", + "@tokenMissingFromResponse": {}, + "transfer": "Transferir", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transferir estoque", + "@transferStock": { + "description": "transfer stock" + }, + "translate": "Traduzir", + "@translate": {}, + "translateHelp": "Ajude a traduzir", + "@translateHelp": {}, + "units": "Unidades", + "@units": {}, + "unknownResponse": "Reposta invalida", + "@unknownResponse": {}, + "upload": "Subir", + "@upload": {}, + "uploadFailed": "Upload de arquivo falhou", + "@uploadFailed": {}, + "uploadSuccess": "Arquivo adicionado com sucesso", + "@uploadSuccess": {}, + "usedIn": "Usado em", + "@usedIn": {}, + "usedInDetails": "Item que precisa desta peca", + "@usedInDetails": {}, + "username": "Usuario", + "@username": {}, + "usernameEmpty": "Usuario nao pode estar vazio", + "@usernameEmpty": {}, + "value": "Valor", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Valor nao pode estar vazio", + "@valueCannotBeEmpty": {}, + "valueRequired": "Valor necessario", + "@valueRequired": {} } \ No newline at end of file From 6463a06b358b4a1bafc7a402b2731e9be7eebfe9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 19 Jun 2022 23:23:00 +1000 Subject: [PATCH 200/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 7e00186..2cb4443 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -48,6 +48,8 @@ }, "attachmentNone": "Keine Anhänge gefunden", "@attachmentNone": {}, + "attachmentNoneDetail": "Keine Anhänge gefunden", + "@attachmentNoneDetail": {}, "attachmentSelect": "Anhang auswählen", "@attachmentSelect": {}, "attention": "Achtung", @@ -451,6 +453,8 @@ "@quantityInvalid": {}, "quantityPositive": "Menge muss positiv sein", "@quantityPositive": {}, + "quarantined": "In Quarantäne", + "@quarantined": {}, "queryEmpty": "Suchanfrage eingeben", "@queryEmpty": {}, "queryNoResults": "Keine Ergebnisse für die Anfrage", From 0d06d07e0f7e2bd42672e67dc31cee62462bcbce Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 20 Jun 2022 15:32:36 +1000 Subject: [PATCH 201/746] Adds ability to display "links" uploaded to attachment fields --- assets/release_notes.md | 3 ++- lib/widget/attachment_widget.dart | 35 ++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 4c172f6..fe7cd9b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,7 +4,8 @@ ### 0.7.3 - June 2022 --- -- +- Adds ability to display link URLs in attachments view +- Updated translations ### 0.7.2 - June 2022 --- diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 9653553..8437ae7 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -9,11 +9,13 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/widget/fields.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; +import "package:url_launcher/url_launcher.dart"; class AttachmentWidget extends StatefulWidget { @@ -114,15 +116,32 @@ class _AttachmentWidgetState extends RefreshableState { List tiles = []; + // An "attachment" can either be a file, or a URL for (var attachment in attachments) { - tiles.add(ListTile( - title: Text(attachment.filename), - subtitle: Text(attachment.comment), - leading: FaIcon(attachment.icon), - onTap: () async { - await attachment.downloadAttachment(); - }, - )); + + if (attachment.filename.isNotEmpty) { + tiles.add(ListTile( + title: Text(attachment.filename), + subtitle: Text(attachment.comment), + leading: FaIcon(attachment.icon, color: COLOR_CLICK), + onTap: () async { + await attachment.downloadAttachment(); + }, + )); + } + + else if (attachment.link.isNotEmpty) { + tiles.add(ListTile( + title: Text(attachment.link), + subtitle: Text(attachment.comment), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + onTap: () async { + if (await canLaunch(attachment.link)) { + await launch(attachment.link); + } + } + )); + } } if (tiles.isEmpty) { From f7e045aaebc164f4bd73c44c5b30fcef26bd8662 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 29 Jun 2022 17:48:01 +1000 Subject: [PATCH 202/746] Update release.yml Change labels / etc --- .github/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/release.yml b/.github/release.yml index 280a065..57cda2a 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -4,11 +4,15 @@ changelog: exclude: labels: - wontfix + - translation categories: - title: Breaking Changes labels: - Semver-Major - breaking + - title: Security Patches + labels: + - security - title: New Features labels: - Semver-Minor @@ -23,7 +27,6 @@ changelog: - setup - demo - CI - - security - title: Other Changes labels: - "*" From e35c4df846790c85fa1a8ddc8d2bd01bd74a7cda Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 5 Jul 2022 16:59:32 +1000 Subject: [PATCH 203/746] Allows displays of Bill of Materials for assembled parts --- lib/inventree/part.dart | 3 --- lib/widget/part_detail.dart | 33 ++++++++++++++++++++++++++------- lib/widget/part_list.dart | 12 ++++++++---- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 85ee6d8..4b86896 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -303,9 +303,6 @@ class InvenTreePart extends InvenTreeModel { // Get the number of units being build for this Part double get building => double.tryParse(jsondata["building"].toString()) ?? 0; - // Get the number of BOM items in this Part (if it is an assembly) - int get bomItemCount => (jsondata["bom_items"] ?? 0) as int; - // Get the number of BOMs this Part is used in (if it is a component) int get usedInCount => (jsondata["used_in"] ?? 0) as int; diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 376d548..7ac7225 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -2,16 +2,18 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/part.dart"; + import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/part_notes.dart"; import "package:inventree/widget/progress.dart"; -import "package:inventree/inventree/part.dart"; import "package:inventree/widget/category_display.dart"; -import "package:inventree/api.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/part_image_widget.dart"; import "package:inventree/widget/snacks.dart"; @@ -41,6 +43,8 @@ class _PartDisplayState extends RefreshableState { int attachmentCount = 0; + int bomCount = 0; + @override String getAppBarTitle(BuildContext context) => L10().partDetails; @@ -118,6 +122,12 @@ class _PartDisplayState extends RefreshableState { "part": part.pk.toString() } ); + + bomCount = await InvenTreePart().count( + filters: { + "in_bom_for": part.pk.toString(), + } + ); } Future _toggleStar() async { @@ -296,14 +306,24 @@ class _PartDisplayState extends RefreshableState { // Tiles for an "assembly" part if (part.isAssembly) { - if (part.bomItemCount > 0) { + if (bomCount > 0) { tiles.add( ListTile( title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.thList), - trailing: Text("${part.bomItemCount}"), + leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), + trailing: Text("${bomCount}"), onTap: () { - // TODO + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PartList( + { + "in_bom_for": "${part.pk}", + }, + title: L10().billOfMaterials, + ) + ) + ); } ) ); @@ -583,7 +603,6 @@ class _PartDisplayState extends RefreshableState { icon: FaIcon(FontAwesomeIcons.boxes), label: L10().stock ), - // TODO - Add part actions BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.wrench), label: L10().actions, diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 528273f..2be5e55 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -12,23 +12,27 @@ import "package:inventree/l10.dart"; class PartList extends StatefulWidget { - const PartList(this.filters); + const PartList(this.filters, {this.title = ""}); + + final String title; final Map filters; @override - _PartListState createState() => _PartListState(filters); + _PartListState createState() => _PartListState(filters, title); } class _PartListState extends RefreshableState { - _PartListState(this.filters); + _PartListState(this.filters, this.title); + + final String title; final Map filters; @override - String getAppBarTitle(BuildContext context) => L10().parts; + String getAppBarTitle(BuildContext context) => title.isNotEmpty ? title : L10().parts; @override Widget getBody(BuildContext context) { From 62df40f4b3ff5cd660af63e52cb3f8b8207b22a2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 5 Jul 2022 17:14:00 +1000 Subject: [PATCH 204/746] Display "variants" in part detail view --- lib/l10n/app_en.arb | 3 +++ lib/widget/part_detail.dart | 38 +++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 332692e..83db3d4 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1119,6 +1119,9 @@ "valueRequired": "Value is required", "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", "@version": {}, diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 7ac7225..2621725 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -45,6 +45,8 @@ class _PartDisplayState extends RefreshableState { int bomCount = 0; + int variantCount = 0; + @override String getAppBarTitle(BuildContext context) => L10().partDetails; @@ -128,6 +130,14 @@ class _PartDisplayState extends RefreshableState { "in_bom_for": part.pk.toString(), } ); + + variantCount = await InvenTreePart().count( + filters: { + "variant_of": part.pk.toString(), + } + ); + + print("Variant count: ${variantCount}"); } Future _toggleStar() async { @@ -271,6 +281,30 @@ class _PartDisplayState extends RefreshableState { ); } + // Display number of "variant" parts if any exist + if (variantCount > 0) { + tiles.add( + ListTile( + title: Text(L10().variants), + leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), + trailing: Text(variantCount.toString()), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PartList( + { + "variant_of": part.pk.toString(), + }, + title: L10().variants + ) + ) + ); + }, + ) + ); + } + tiles.add( ListTile( title: Text(L10().availableStock), @@ -311,14 +345,14 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().billOfMaterials), leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), - trailing: Text("${bomCount}"), + trailing: Text(bomCount.toString()), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => PartList( { - "in_bom_for": "${part.pk}", + "in_bom_for": part.pk.toString(), }, title: L10().billOfMaterials, ) From 591c6a5592d5e3ceb5f17d420c7eb4b32adef143 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 5 Jul 2022 18:38:28 +1000 Subject: [PATCH 205/746] Update stock display to indicate allocations --- lib/inventree/stock.dart | 19 ++++++++++++++++--- lib/l10n/app_en.arb | 3 +++ lib/widget/stock_detail.dart | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 46b0c75..0bc826f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -451,7 +451,14 @@ class InvenTreeStockItem extends InvenTreeModel { String quantityString({bool includeUnits = false}){ - String q = simpleNumberString(quantity); + String q = ""; + + if (allocated > 0) { + q += simpleNumberString(available); + q += " / "; + } + + q += simpleNumberString(quantity); if (includeUnits && units.isNotEmpty) { q += " ${units}"; @@ -460,6 +467,10 @@ class InvenTreeStockItem extends InvenTreeModel { return q; } + double get allocated => double.tryParse(jsondata["allocated"].toString()) ?? 0; + + double get available => quantity - allocated; + int get locationId => (jsondata["location"] ?? -1) as int; bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; @@ -467,9 +478,11 @@ class InvenTreeStockItem extends InvenTreeModel { String serialOrQuantityDisplay() { if (isSerialized()) { return "SN ${serialNumber}"; + } else if (allocated > 0) { + return "${available} / ${quantity}"; + } else { + return simpleNumberString(quantity); } - - return simpleNumberString(quantity); } String get locationName { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 83db3d4..8183af6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -655,6 +655,9 @@ "description": "Quantity" }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", "@quantityEmpty": {}, diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index d8c43ad..8512103 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -513,7 +513,7 @@ class _StockItemDisplayState extends RefreshableState { } else { tiles.add( ListTile( - title: Text(L10().quantity), + title: item.allocated > 0 ? Text(L10().quantityAvailable) : Text(L10().quantity), leading: FaIcon(FontAwesomeIcons.cubes), trailing: Text("${item.quantityString()}"), ) From 78a5a9090d0caeba00a767622fb199b622dd217e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 5 Jul 2022 19:16:06 +1000 Subject: [PATCH 206/746] Adds new custom widget for displaying Bill of Materials data --- lib/inventree/bom.dart | 69 ++++++++++++++++++++++ lib/inventree/part.dart | 10 +++- lib/widget/bom_list.dart | 113 ++++++++++++++++++++++++++++++++++++ lib/widget/part_detail.dart | 19 +++--- 4 files changed, 200 insertions(+), 11 deletions(-) create mode 100644 lib/inventree/bom.dart create mode 100644 lib/widget/bom_list.dart diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart new file mode 100644 index 0000000..52ad578 --- /dev/null +++ b/lib/inventree/bom.dart @@ -0,0 +1,69 @@ + + +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/part.dart"; + +/* + * Class representing the BomItem database model + */ +class InvenTreeBomItem extends InvenTreeModel { + + InvenTreeBomItem() : super(); + + InvenTreeBomItem.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) { + return InvenTreeBomItem.fromJson(json); + } + + @override + String get URL => "bom/"; + + @override + Map defaultListFilters() { + return { + "sub_part_detail": "true", + }; + } + + @override + Map defaultGetFilters() { + return { + "sub_part_detail": "true", + }; + } + + // Extract the 'quantity' value associated with this BomItem + double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; + + // Extract the ID of the related part + int get partId => int.tryParse(jsondata["part"].toString()) ?? -1; + + // Return a Part instance for the referenced part + InvenTreePart? get part { + if (jsondata.containsKey("part_detail")) { + dynamic data = jsondata["part_detail"] ?? {}; + if (data is Map) { + return InvenTreePart.fromJson(data); + } + } + + return null; + } + + // Return a Part instance for the referenced sub-part + InvenTreePart? get subPart { + if (jsondata.containsKey("sub_part_detail")) { + dynamic data = jsondata["sub_part_detail"] ?? {}; + if (data is Map) { + return InvenTreePart.fromJson(data); + } + } + + return null; +} + + // Extract the ID of the related sub-part + int get subPartId => int.tryParse(jsondata["sub_part"].toString()) ?? -1; +} \ No newline at end of file diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 4b86896..8e58eaf 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -10,6 +10,9 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; +/* + * Class representing the PartCategory database model + */ class InvenTreePartCategory extends InvenTreeModel { InvenTreePartCategory() : super(); @@ -70,6 +73,9 @@ class InvenTreePartCategory extends InvenTreeModel { } +/* + * Class representing the PartTestTemplate database model + */ class InvenTreePartTestTemplate extends InvenTreeModel { InvenTreePartTestTemplate() : super(); @@ -122,6 +128,9 @@ class InvenTreePartTestTemplate extends InvenTreeModel { } +/* + * Class representing the Part database model + */ class InvenTreePart extends InvenTreeModel { InvenTreePart() : super(); @@ -219,7 +228,6 @@ class InvenTreePart extends InvenTreeModel { return _supplierParts; } - // Cached list of test templates List testingTemplates = []; diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart new file mode 100644 index 0000000..5e51fee --- /dev/null +++ b/lib/widget/bom_list.dart @@ -0,0 +1,113 @@ + + +import "package:flutter/material.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/inventree/bom.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/part.dart"; + +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/refreshable_state.dart"; + + +/* + * Widget for displaying a list of BomItems for the specified 'parent' Part instance + */ +class BomList extends StatefulWidget { + + const BomList(this.parent); + + final InvenTreePart parent; + + @override + _BomListState createState() => _BomListState(parent); + +} + + +class _BomListState extends RefreshableState { + + _BomListState(this.parent); + + final InvenTreePart parent; + + @override + String getAppBarTitle(BuildContext context) => L10().billOfMaterials; + + @override + Widget getBody(BuildContext context) { + return PaginatedBomList({ + "part": parent.pk.toString(), + }); + } +} + + +/* + * Create a paginated widget displaying a list of BomItem objects + */ +class PaginatedBomList extends StatefulWidget { + + const PaginatedBomList(this.filters, {this.onTotalChanged}); + + final Map filters; + + final Function(int)? onTotalChanged; + + @override + _PaginatedBomListState createState() => _PaginatedBomListState(filters, onTotalChanged); + +} + + +class _PaginatedBomListState extends PaginatedSearchState { + + _PaginatedBomListState(Map filters, this.onTotalChanged) : super(filters); + + Function(int)? onTotalChanged; + + @override + Future requestPage(int limit, int offset, Map params) async { + + final page = await InvenTreeBomItem().listPaginated(limit, offset, filters: params); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + + InvenTreeBomItem bomItem = model as InvenTreeBomItem; + + InvenTreePart? subPart = bomItem.subPart; + + String title = subPart?.fullname ?? "error - no name"; + String description = subPart?.description ?? "error - no description"; + + return ListTile( + title: Text(title), + subtitle: Text(description), + trailing: Text( + simpleNumberString(bomItem.quantity), + style: TextStyle(fontWeight: FontWeight.bold), + ), + leading: InvenTreeAPI().getImage( + subPart?.thumbnail ?? "", + width: 40, + height: 40, + ), + onTap: subPart == null ? null : () async { + InvenTreePart().get(bomItem.subPartId).then((var part) { + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + } + }); + }, + ); + } +} \ No newline at end of file diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 2621725..c7e36b8 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -10,6 +10,7 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/bom_list.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/part_notes.dart"; import "package:inventree/widget/progress.dart"; @@ -136,8 +137,6 @@ class _PartDisplayState extends RefreshableState { "variant_of": part.pk.toString(), } ); - - print("Variant count: ${variantCount}"); } Future _toggleStar() async { @@ -286,7 +285,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().variants), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_CLICK), trailing: Text(variantCount.toString()), onTap: () { Navigator.push( @@ -310,7 +309,12 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: Text(part.stockString()), + trailing: Text( + part.stockString(), + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), onTap: () { setState(() { tabIndex = 1; @@ -350,12 +354,7 @@ class _PartDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => PartList( - { - "in_bom_for": part.pk.toString(), - }, - title: L10().billOfMaterials, - ) + builder: (context) => BomList(part) ) ); } From c878f37ec2326f8cfaeeda78f8081e6148882543 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 5 Jul 2022 21:42:55 +1000 Subject: [PATCH 207/746] Implementing a generic "ordering" option configuration for paginated list widget --- lib/widget/bom_list.dart | 15 ++++- lib/widget/paginator.dart | 126 +++++++++++++++++++++++++++++++++++++- pubspec.yaml | 12 ++-- 3 files changed, 144 insertions(+), 9 deletions(-) diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 5e51fee..e2b6f13 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -1,8 +1,9 @@ - import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/api_form.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/bom.dart"; import "package:inventree/l10.dart"; @@ -15,6 +16,7 @@ import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; + /* * Widget for displaying a list of BomItems for the specified 'parent' Part instance */ @@ -30,7 +32,7 @@ class BomList extends StatefulWidget { } -class _BomListState extends RefreshableState { +class _BomListState extends PaginatedState { _BomListState(this.parent); @@ -39,6 +41,15 @@ class _BomListState extends RefreshableState { @override String getAppBarTitle(BuildContext context) => L10().billOfMaterials; + @override + String get prefix => "bom_"; + + @override + Map get orderingOptions => { + "quantity": L10().quantity, + "part": L10().part, + }; + @override Widget getBody(BuildContext context) { return PaginatedBomList({ diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index aa62647..26bae40 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -3,9 +3,129 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:infinite_scroll_pagination/infinite_scroll_pagination.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/l10.dart"; + import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/sentry.dart"; -import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; + +import "package:inventree/widget/refreshable_state.dart"; + + +/* + * Generic widget class for displaying a "paginated list". + * Provides some basic functionality for adjusting ordering and filtering options + */ +abstract class PaginatedState extends RefreshableState { + + // Prefix for storing and loading pagination options + String get prefix => "prefix_"; + + // Ordering options for this paginated state (override in implementing class) + Map get orderingOptions => {}; + + @override + List getAppBarActions(BuildContext context) { + List actions = []; + + // If ordering options have been provided + if (orderingOptions.isNotEmpty) { + actions.add(IconButton( + icon: FaIcon(FontAwesomeIcons.sort), + onPressed: () => _updateFilters(context), + )); + } + + return actions; + } + + // Return the selected ordering "field" for this list widget + Future orderingField() async { + dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", null); + + if (field != null) { + return field.toString(); + } else if (orderingOptions.isNotEmpty) { + // By default, return the first specified key + return orderingOptions.keys.first; + } else { + return ""; + } + } + + // Return the selected ordering "order" ("+" or "-") for this list widget + Future orderingOrder() async { + dynamic order = await InvenTreeSettingsManager().getValue("${prefix}ordering_order", "+"); + + return order == "+" ? "+" : "-"; + } + + // Update the (configurable) filters for this paginated list + Future _updateFilters(BuildContext context) async { + + // Retrieve stored setting + dynamic _field = await orderingField(); + dynamic _order = await orderingOrder(); + + // Construct the 'ordering' options + List> _opts = []; + + orderingOptions.forEach((k, v) => _opts.add({ + "value": k.toString(), + "display_name": v.toString() + })); + + if (_field == null && _opts.isNotEmpty) { + _field = _opts.first["value"]; + } + + Map fields = { + "ordering_field": { + "type": "choice", + "label": "Ordering Field", + "required": true, + "choices": _opts, + "value": _field, + }, + "ordering_order": { + "type": "choice", + "label": "Ordering Direction", + "required": true, + "value": _order, + "choices": [ + { + "value": "+", + "display_name": "Ascending", + }, + { + "value": "-", + "display_name": "Descending", + } + ] + } + }; + + launchApiForm( + context, + "...filtering...", + "", + fields, + icon: FontAwesomeIcons.checkCircle, + onSuccess: (Map data) async { + + // Extract data from the processed form + String f = (data["ordering_field"] ?? _field) as String; + String o = (data["ordering_order"] ?? _order) as String; + + // Save values to settings + await InvenTreeSettingsManager().setValue("${prefix}ordering_field", f); + await InvenTreeSettingsManager().setValue("${prefix}ordering_order", o); + } + ); + } + +} class PaginatedSearchState extends State { @@ -21,6 +141,10 @@ class PaginatedSearchState extends State { int resultCount = 0; + // List of variables by which the list can be "ordered". + // Override in any implementing sub-class + List orderingFilters = []; + // Text controller final TextEditingController searchController = TextEditingController(); diff --git a/pubspec.yaml b/pubspec.yaml index 16a3506..6528ab4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,11 +10,11 @@ dependencies: audioplayers: ^0.20.1 # Play audio files cached_network_image: ^3.2.0 # Download and cache remote images - camera: ^0.9.4 # Camera + camera: ^0.9.4 # Camera cupertino_icons: ^1.0.3 datetime_picker_formfield: ^2.0.0 # Date / time picker device_info_plus: ^3.2.2 # Information about the device - dropdown_search: ^0.6.3 # Dropdown autocomplete form fields + dropdown_search: ^0.6.3 # Dropdown autocomplete form fields file_picker: ^4.5.1 # Select files from the device flutter: sdk: flutter @@ -28,14 +28,14 @@ dependencies: infinite_scroll_pagination: ^3.1.0 # Let the server do all the work! intl: ^0.17.0 one_context: ^1.1.0 # Dialogs without requiring context - open_file: ^3.2.1 # Open local files + open_file: ^3.2.1 # Open local files package_info_plus: ^1.0.4 # App information introspection path: ^1.8.0 - path_provider: ^2.0.2 # Local file storage + path_provider: ^2.0.2 # Local file storage qr_code_scanner: ^0.7.0 # Barcode scanning sembast: ^3.1.0+2 # NoSQL data storage - sentry_flutter: ^6.4.0 # Error reporting - url_launcher: ^6.0.9 # Open link in system browser + sentry_flutter: ^6.4.0 # Error reporting + url_launcher: ^6.0.9 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.9.0 From 6c1099356f466aa58b0565d13e367201477154e0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 09:49:40 +1000 Subject: [PATCH 208/746] Enable basic ordering for BOM list --- lib/inventree/bom.dart | 3 +++ lib/widget/bom_list.dart | 7 +++++-- lib/widget/paginator.dart | 27 +++++++++++++++++++++------ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart index 52ad578..20487bc 100644 --- a/lib/inventree/bom.dart +++ b/lib/inventree/bom.dart @@ -34,6 +34,9 @@ class InvenTreeBomItem extends InvenTreeModel { }; } + // Extract the 'reference' value associated with this BomItem + String get reference => (jsondata["reference"] ?? "") as String; + // Extract the 'quantity' value associated with this BomItem double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index e2b6f13..65ee013 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -47,7 +47,7 @@ class _BomListState extends PaginatedState { @override Map get orderingOptions => { "quantity": L10().quantity, - "part": L10().part, + "sub_part": L10().part, }; @override @@ -82,6 +82,9 @@ class _PaginatedBomListState extends PaginatedSearchState { Function(int)? onTotalChanged; + @override + String get prefix => "bom_"; + @override Future requestPage(int limit, int offset, Map params) async { @@ -102,7 +105,7 @@ class _PaginatedBomListState extends PaginatedSearchState { return ListTile( title: Text(title), - subtitle: Text(description), + subtitle: Text(bomItem.reference), trailing: Text( simpleNumberString(bomItem.quantity), style: TextStyle(fontWeight: FontWeight.bold), diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 26bae40..4d721d5 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -44,7 +44,8 @@ abstract class PaginatedState extends RefreshableState Future orderingField() async { dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", null); - if (field != null) { + if (field != null && orderingOptions.containsKey(field.toString())) { + // A valid ordering field has been found return field.toString(); } else if (orderingOptions.isNotEmpty) { // By default, return the first specified key @@ -121,6 +122,9 @@ abstract class PaginatedState extends RefreshableState // Save values to settings await InvenTreeSettingsManager().setValue("${prefix}ordering_field", f); await InvenTreeSettingsManager().setValue("${prefix}ordering_order", o); + + // Refresh the widget + setState(() {}); } ); } @@ -136,15 +140,15 @@ class PaginatedSearchState extends State { static const _pageSize = 25; + // Prefix for storing and loading pagination options + // Override in implementing class + String get prefix => "prefix_"; + // Search query term String searchTerm = ""; int resultCount = 0; - // List of variables by which the list can be "ordered". - // Override in any implementing sub-class - List orderingFilters = []; - // Text controller final TextEditingController searchController = TextEditingController(); @@ -172,11 +176,19 @@ class PaginatedSearchState extends State { return null; } + Future get ordering async { + dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", ""); + dynamic order = await InvenTreeSettingsManager().getValue("${prefix}ordering_order", "+"); + + return "${order}${field}"; + } + Future _fetchPage(int pageKey) async { try { Map params = filters; params["search"] = "${searchTerm}"; + params["ordering"] = await ordering; final page = await requestPage( _pageSize, @@ -299,7 +311,10 @@ class PaginatedSearchWidget extends StatelessWidget { ), trailing: Text( "${results}", - style: TextStyle(fontWeight: FontWeight.bold), + style: TextStyle( + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic + ), ), ); } From 979f9501291c69a1f7796da17e92eee41b098621 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 09:51:05 +1000 Subject: [PATCH 209/746] Update release notes --- assets/release_notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index fe7cd9b..bf6e783 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,14 @@ ## InvenTree App Release Notes --- +### 0.8.0 - July 2022 +--- + +- Display part variants in the part detail view +- Display Bill of Materials in the part detail view +- Indicate available quantity in stock detail view +- Adds configurable filtering to various list views + ### 0.7.3 - June 2022 --- From 7301243ed631b3f5e374b5eddf664fb828007e3f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 20:24:40 +1000 Subject: [PATCH 210/746] Major overhaul of "paginated list" widget class - Simplify implementation - Create mixin class for code reuse - Allow custom app-bar - Allow custom ordering / sorting options - Improve code commenting / readability --- lib/widget/bom_list.dart | 54 +++---------- lib/widget/notifications.dart | 2 +- lib/widget/paginator.dart | 128 ++++++++++++++++++------------ lib/widget/part_detail.dart | 4 +- lib/widget/refreshable_state.dart | 85 +++++++++++--------- lib/widget/search.dart | 4 +- 6 files changed, 143 insertions(+), 134 deletions(-) diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 65ee013..56d8faa 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -17,48 +17,6 @@ import "package:inventree/widget/refreshable_state.dart"; -/* - * Widget for displaying a list of BomItems for the specified 'parent' Part instance - */ -class BomList extends StatefulWidget { - - const BomList(this.parent); - - final InvenTreePart parent; - - @override - _BomListState createState() => _BomListState(parent); - -} - - -class _BomListState extends PaginatedState { - - _BomListState(this.parent); - - final InvenTreePart parent; - - @override - String getAppBarTitle(BuildContext context) => L10().billOfMaterials; - - @override - String get prefix => "bom_"; - - @override - Map get orderingOptions => { - "quantity": L10().quantity, - "sub_part": L10().part, - }; - - @override - Widget getBody(BuildContext context) { - return PaginatedBomList({ - "part": parent.pk.toString(), - }); - } -} - - /* * Create a paginated widget displaying a list of BomItem objects */ @@ -78,13 +36,23 @@ class PaginatedBomList extends StatefulWidget { class _PaginatedBomListState extends PaginatedSearchState { - _PaginatedBomListState(Map filters, this.onTotalChanged) : super(filters); + _PaginatedBomListState(Map filters, this.onTotalChanged) : super(filters, fullscreen: true); Function(int)? onTotalChanged; @override String get prefix => "bom_"; + @override + Map get orderingOptions => { + "quantity": L10().quantity, + "sub_part": L10().part, + }; + + + @override + String getAppBarTitle(BuildContext context) => L10().billOfMaterials; + @override Future requestPage(int limit, int offset, Map params) async { diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 8c03343..0af32b8 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -24,7 +24,7 @@ class _NotificationState extends RefreshableState { List notifications = []; @override - AppBar? buildAppBar(BuildContext context) { + AppBar? buildAppBar(BuildContext context, GlobalKey key) { // No app bar for the notification widget return null; } diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 4d721d5..a9971ec 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -14,32 +14,32 @@ import "package:inventree/widget/refreshable_state.dart"; /* - * Generic widget class for displaying a "paginated list". - * Provides some basic functionality for adjusting ordering and filtering options + * Generic stateful widget for displaying paginated data retrieved via the API + * + * - Can be displayed as "full screen" (with app-bar and drawer) + * - Can be displayed as a standalone widget */ -abstract class PaginatedState extends RefreshableState { +class PaginatedSearchState extends State with BaseWidgetProperties { + + PaginatedSearchState(this.filters, {this.fullscreen = true}); + + final _key = GlobalKey(); + + final Map filters; + + static const _pageSize = 25; + + // Determine if this widget is shown "fullscreen" (i.e. with appbar) + final bool fullscreen; // Prefix for storing and loading pagination options + // Override in implementing class String get prefix => "prefix_"; - // Ordering options for this paginated state (override in implementing class) + // Return a map of sorting options available for this list + // Should be overridden by an implementing subclass Map get orderingOptions => {}; - @override - List getAppBarActions(BuildContext context) { - List actions = []; - - // If ordering options have been provided - if (orderingOptions.isNotEmpty) { - actions.add(IconButton( - icon: FaIcon(FontAwesomeIcons.sort), - onPressed: () => _updateFilters(context), - )); - } - - return actions; - } - // Return the selected ordering "field" for this list widget Future orderingField() async { dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", null); @@ -62,9 +62,21 @@ abstract class PaginatedState extends RefreshableState return order == "+" ? "+" : "-"; } - // Update the (configurable) filters for this paginated list - Future _updateFilters(BuildContext context) async { + // Return string for determining 'ordering' of paginated list + Future get orderingString async { + dynamic field = await orderingField(); + dynamic order = await orderingOrder(); + // Return an empty string if no field is provided + if (field.toString().isEmpty) { + return ""; + } + + return "${order}${field}"; + } + + // Update the (configurable) filters for this paginated list + Future _saveOrderingOptions(BuildContext context) async { // Retrieve stored setting dynamic _field = await orderingField(); dynamic _order = await orderingOrder(); @@ -96,12 +108,12 @@ abstract class PaginatedState extends RefreshableState "value": _order, "choices": [ { - "value": "+", - "display_name": "Ascending", + "value": "+", + "display_name": "Ascending", }, { - "value": "-", - "display_name": "Descending", + "value": "-", + "display_name": "Descending", } ] } @@ -123,27 +135,12 @@ abstract class PaginatedState extends RefreshableState await InvenTreeSettingsManager().setValue("${prefix}ordering_field", f); await InvenTreeSettingsManager().setValue("${prefix}ordering_order", o); - // Refresh the widget - setState(() {}); + // Refresh data from the server + _pagingController.refresh(); } ); } -} - - -class PaginatedSearchState extends State { - - PaginatedSearchState(this.filters); - - final Map filters; - - static const _pageSize = 25; - - // Prefix for storing and loading pagination options - // Override in implementing class - String get prefix => "prefix_"; - // Search query term String searchTerm = ""; @@ -176,19 +173,12 @@ class PaginatedSearchState extends State { return null; } - Future get ordering async { - dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", ""); - dynamic order = await InvenTreeSettingsManager().getValue("${prefix}ordering_order", "+"); - - return "${order}${field}"; - } - Future _fetchPage(int pageKey) async { try { Map params = filters; params["search"] = "${searchTerm}"; - params["ordering"] = await ordering; + params["ordering"] = await orderingString; final page = await requestPage( _pageSize, @@ -234,6 +224,8 @@ class PaginatedSearchState extends State { _pagingController.refresh(); } + // Function to construct a single paginated item + // Must be overridden in an implementing subclass Widget buildItem(BuildContext context, InvenTreeModel item) { // This method must be overridden by the child class @@ -243,10 +235,31 @@ class PaginatedSearchState extends State { ); } + // Return a string which is displayed when there are no results + // Can be overridden by an implementing subclass String get noResultsText => L10().noResults; @override Widget build (BuildContext context) { + + if (fullscreen) { + return Scaffold( + key: _key, + appBar: buildAppBar(context, _key), + drawer: getDrawer(context), + body: Builder( + builder: (BuildContext ctx) { + return getBody(ctx); + } + ) + ); + } else { + return getBody(context); + } + } + + @override + Widget getBody(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -277,6 +290,21 @@ class PaginatedSearchState extends State { ); } + @override + List getAppBarActions(BuildContext context) { + List actions = []; + + // If ordering options have been provided + if (orderingOptions.isNotEmpty) { + actions.add(IconButton( + icon: FaIcon(FontAwesomeIcons.sort), + onPressed: () => _saveOrderingOptions(context), + )); + } + + return actions; + } + } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index c7e36b8..abf1742 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -354,7 +354,9 @@ class _PartDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => BomList(part) + builder: (context) => PaginatedBomList({ + "part": part.pk.toString(), + }) ) ); } diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 3518569..dc29c7d 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -3,7 +3,53 @@ import "package:inventree/widget/drawer.dart"; import "package:flutter/material.dart"; -abstract class RefreshableState extends State { +/* + * Simple mixin class which defines simple methods for defining widget properties + */ +mixin BaseWidgetProperties { + + // Return a list of appBar actions (default = None) + List getAppBarActions(BuildContext context) { + return []; + } + + // Return a title for the appBar + String getAppBarTitle(BuildContext context) { return "--- app bar ---"; } + + // Function to construct a drawer (override if needed) + Widget getDrawer(BuildContext context) { + return InvenTreeDrawer(context); + } + + // Function to construct a body (MUST BE PROVIDED) + Widget getBody(BuildContext context) { + + // Default return is an empty ListView + return ListView(); + } + + Widget? getBottomNavBar(BuildContext context) { + return null; + } + + AppBar? buildAppBar(BuildContext context, GlobalKey key) { + return AppBar( + title: Text(getAppBarTitle(context)), + actions: getAppBarActions(context), + leading: backButton(context, key), + ); + } + +} + + +/* + * Abstract base class which provides generic "refresh" functionality. + * + * - Drag down and release to 'refresh' the widget + * - Define some method which runs to 'refresh' the widget state + */ +abstract class RefreshableState extends State with BaseWidgetProperties { final refreshableKey = GlobalKey(); @@ -25,12 +71,6 @@ abstract class RefreshableState extends State { }); } - List getAppBarActions(BuildContext context) { - return []; - } - - String getAppBarTitle(BuildContext context) { return "App Bar Title"; } - @override void initState() { super.initState(); @@ -60,34 +100,6 @@ abstract class RefreshableState extends State { }); } - // Function to construct a drawer (override if needed) - Widget getDrawer(BuildContext context) { - return InvenTreeDrawer(context); - } - - // Function to construct a body (MUST BE PROVIDED) - Widget getBody(BuildContext context) { - - // Default return is an empty ListView - return ListView(); - } - - Widget? getBottomNavBar(BuildContext context) { - return null; - } - - Widget? getFab(BuildContext context) { - return null; - } - - AppBar? buildAppBar(BuildContext context) { - return AppBar( - title: Text(getAppBarTitle(context)), - actions: getAppBarActions(context), - leading: backButton(context, refreshableKey), - ); - } - @override Widget build(BuildContext context) { @@ -96,9 +108,8 @@ abstract class RefreshableState extends State { return Scaffold( key: refreshableKey, - appBar: buildAppBar(context), + appBar: buildAppBar(context, refreshableKey), drawer: getDrawer(context), - floatingActionButton: getFab(context), body: Builder( builder: (BuildContext context) { return RefreshIndicator( diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 4966247..dcbe47e 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -53,9 +53,9 @@ class _SearchDisplayState extends RefreshableState { String getAppBarTitle(BuildContext context) => L10().search; @override - AppBar? buildAppBar(BuildContext context) { + AppBar? buildAppBar(BuildContext context, GlobalKey key) { if (hasAppBar) { - return super.buildAppBar(context); + return super.buildAppBar(context, key); } else { return null; } From 6d247f426cacb81f9bb38d3abd37f7a717a69d94 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 20:54:17 +1000 Subject: [PATCH 211/746] Further refactoring --- lib/widget/bom_list.dart | 36 ++++++++++++--- lib/widget/paginator.dart | 89 +++++++++---------------------------- lib/widget/part_detail.dart | 4 +- 3 files changed, 53 insertions(+), 76 deletions(-) diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 56d8faa..14cd490 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -16,6 +16,35 @@ import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; +/* + * Widget for displaying a Bill of Materials for a specified Part instance + */ +class BillOfMaterialsWidget extends StatefulWidget { + + const BillOfMaterialsWidget(this.part, {Key? key}) : super(key: key); + + final InvenTreePart part; + + @override + _BillOfMaterialsState createState() => _BillOfMaterialsState(part); +} + +class _BillOfMaterialsState extends RefreshableState { + _BillOfMaterialsState(this.part); + + final InvenTreePart part; + + @override + String getAppBarTitle(BuildContext context) => L10().billOfMaterials; + + @override + Widget getBody(BuildContext context) { + return PaginatedBomList({ + "part": part.pk.toString(), + }); + } +} + /* * Create a paginated widget displaying a list of BomItem objects @@ -31,12 +60,13 @@ class PaginatedBomList extends StatefulWidget { @override _PaginatedBomListState createState() => _PaginatedBomListState(filters, onTotalChanged); + } class _PaginatedBomListState extends PaginatedSearchState { - _PaginatedBomListState(Map filters, this.onTotalChanged) : super(filters, fullscreen: true); + _PaginatedBomListState(Map filters, this.onTotalChanged) : super(filters); Function(int)? onTotalChanged; @@ -49,10 +79,6 @@ class _PaginatedBomListState extends PaginatedSearchState { "sub_part": L10().part, }; - - @override - String getAppBarTitle(BuildContext context) => L10().billOfMaterials; - @override Future requestPage(int limit, int offset, Map params) async { diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index a9971ec..7781a3d 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -21,7 +21,7 @@ import "package:inventree/widget/refreshable_state.dart"; */ class PaginatedSearchState extends State with BaseWidgetProperties { - PaginatedSearchState(this.filters, {this.fullscreen = true}); + PaginatedSearchState(this.filters); final _key = GlobalKey(); @@ -29,9 +29,6 @@ class PaginatedSearchState extends State with BaseW static const _pageSize = 25; - // Determine if this widget is shown "fullscreen" (i.e. with appbar) - final bool fullscreen; - // Prefix for storing and loading pagination options // Override in implementing class String get prefix => "prefix_"; @@ -242,35 +239,16 @@ class PaginatedSearchState extends State with BaseW @override Widget build (BuildContext context) { - if (fullscreen) { - return Scaffold( - key: _key, - appBar: buildAppBar(context, _key), - drawer: getDrawer(context), - body: Builder( - builder: (BuildContext ctx) { - return getBody(ctx); - } - ) - ); - } else { - return getBody(context); - } - } - - @override - Widget getBody(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.start, children: [ - PaginatedSearchWidget(searchController, updateSearchTerm, resultCount), + buildSearchInput(context), Expanded( child: CustomScrollView( shrinkWrap: true, physics: ClampingScrollPhysics(), scrollDirection: Axis.vertical, slivers: [ - // TODO - Search input PagedSliverList.separated( pagingController: _pagingController, builderDelegate: PagedChildBuilderDelegate( @@ -290,64 +268,39 @@ class PaginatedSearchState extends State with BaseW ); } - @override - List getAppBarActions(BuildContext context) { - List actions = []; - - // If ordering options have been provided - if (orderingOptions.isNotEmpty) { - actions.add(IconButton( - icon: FaIcon(FontAwesomeIcons.sort), - onPressed: () => _saveOrderingOptions(context), - )); - } - - return actions; - } - -} - - -class PaginatedSearchWidget extends StatelessWidget { - - const PaginatedSearchWidget(this.controller, this.onChanged, this.results); - - final Function onChanged; - - final int results; - - final TextEditingController controller; - - @override - Widget build(BuildContext context) { + /* + * Construct a search input text field for the user to enter a search term + */ + Widget buildSearchInput(BuildContext context) { return ListTile( - leading: GestureDetector( - child: FaIcon(controller.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace), + leading: orderingOptions.isEmpty ? null : GestureDetector( + child: FaIcon(FontAwesomeIcons.sort), + onTap: () async { + _saveOrderingOptions(context); + }, + ), + trailing: GestureDetector( + child: FaIcon(searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace), onTap: () { - controller.clear(); - onChanged(); + searchController.clear(); + updateSearchTerm(); }, ), title: TextFormField( - controller: controller, + controller: searchController, onChanged: (value) { - onChanged(); + updateSearchTerm(); }, decoration: InputDecoration( hintText: L10().search, + helperText: resultCount.toString(), ), - ), - trailing: Text( - "${results}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontStyle: FontStyle.italic - ), - ), + ) ); } } + class NoResultsWidget extends StatelessWidget { const NoResultsWidget(this.description); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index abf1742..8dc162f 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -354,9 +354,7 @@ class _PartDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => PaginatedBomList({ - "part": part.pk.toString(), - }) + builder: (context) => BillOfMaterialsWidget(part) ) ); } From 61929323223da7350d24b1aaca5507b3f0b0ba06 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 20:59:38 +1000 Subject: [PATCH 212/746] Add ordering options for "Part" list --- lib/widget/part_list.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 2be5e55..fcec2c0 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -61,6 +61,16 @@ class _PaginatedPartListState extends PaginatedSearchState { Function(int)? onTotalChanged; + @override + String get prefix => "part_"; + + @override + Map get orderingOptions => { + "name": L10().name, + "in_stock": L10().stock, + "IPN": L10().internalPartNumber, + }; + @override Future requestPage(int limit, int offset, Map params) async { From a450154bacf60764fb4a7d28e64e5de6fa9cdafd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:07:19 +1000 Subject: [PATCH 213/746] Add sorting options for the StockItem list --- lib/l10n/app_en.arb | 3 +++ lib/widget/category_list.dart | 9 +++++++++ lib/widget/stock_list.dart | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8183af6..449fa45 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -425,6 +425,9 @@ "lastUpdated": "Last Updated", "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItem": "Line Item", "@lineItem": {}, diff --git a/lib/widget/category_list.dart b/lib/widget/category_list.dart index 8bb2465..0a6ca60 100644 --- a/lib/widget/category_list.dart +++ b/lib/widget/category_list.dart @@ -50,6 +50,15 @@ class _PaginatedPartCategoryListState extends PaginatedSearchState filters) : super(filters); + @override + String get prefix => "category_"; + + @override + Map get orderingOptions => { + "name": L10().name, + "level": L10().level, + }; + @override Future requestPage(int limit, int offset, Map params) async { diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index 90481c7..19edcd5 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -52,6 +52,20 @@ class _PaginatedStockItemListState extends PaginatedSearchState filters) : super(filters); + @override + String get prefix => "stock_"; + + @override + Map get orderingOptions => { + "part__name": L10().name, + "part__IPN": L10().internalPartNumber, + "quantity": L10().quantity, + "status": L10().status, + "batch": L10().batchCode, + "updated": L10().lastUpdated, + "stocktake_date": L10().lastStocktake, + }; + @override Future requestPage(int limit, int offset, Map params) async { From c3e6d3f9026d9b937bed4458526d89c77d0e136b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:13:07 +1000 Subject: [PATCH 214/746] Widget cleanup --- lib/l10n/app_en.arb | 3 +++ lib/widget/paginator.dart | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 449fa45..558418f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -294,6 +294,9 @@ "feedbackSuccess": "Feedback submitted", "@feedbackSuccess": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", "@formatException": {}, diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 7781a3d..1acf068 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -4,6 +4,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:infinite_scroll_pagination/infinite_scroll_pagination.dart"; import "package:inventree/api_form.dart"; +import 'package:inventree/app_colors.dart'; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; @@ -118,7 +119,7 @@ class PaginatedSearchState extends State with BaseW launchApiForm( context, - "...filtering...", + L10().filteringOptions, "", fields, icon: FontAwesomeIcons.checkCircle, @@ -143,6 +144,15 @@ class PaginatedSearchState extends State with BaseW int resultCount = 0; + String resultsString() { + + if (resultCount <= 0) { + return noResultsText; + } else { + return "${resultCount} ${L10().results}"; + } + } + // Text controller final TextEditingController searchController = TextEditingController(); @@ -274,13 +284,16 @@ class PaginatedSearchState extends State with BaseW Widget buildSearchInput(BuildContext context) { return ListTile( leading: orderingOptions.isEmpty ? null : GestureDetector( - child: FaIcon(FontAwesomeIcons.sort), + child: FaIcon(FontAwesomeIcons.sort, color: COLOR_CLICK), onTap: () async { _saveOrderingOptions(context); }, ), trailing: GestureDetector( - child: FaIcon(searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace), + child: FaIcon( + searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, + color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK, + ), onTap: () { searchController.clear(); updateSearchTerm(); @@ -293,7 +306,7 @@ class PaginatedSearchState extends State with BaseW }, decoration: InputDecoration( hintText: L10().search, - helperText: resultCount.toString(), + helperText: resultsString(), ), ) ); From bb73fb74005b611113c622b736bfbd000df70f5d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:17:52 +1000 Subject: [PATCH 215/746] Cleanup --- lib/widget/paginator.dart | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 1acf068..7b6f803 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -4,7 +4,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:infinite_scroll_pagination/infinite_scroll_pagination.dart"; import "package:inventree/api_form.dart"; -import 'package:inventree/app_colors.dart'; +import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; @@ -117,6 +117,7 @@ class PaginatedSearchState extends State with BaseW } }; + // Launch an interactive form for the user to select options launchApiForm( context, L10().filteringOptions, @@ -174,18 +175,32 @@ class PaginatedSearchState extends State with BaseW super.dispose(); } + /* + * Custom function to request a single page of results from the server. + * Each implementing class must override this function, + * and return an InvenTreePageResponse object with the correct data format + */ Future requestPage(int limit, int offset, Map params) async { // Default implementation returns null - must be overridden return null; } + /* + * Request a single page of results from the server + */ Future _fetchPage(int pageKey) async { try { Map params = filters; + // Include user search term params["search"] = "${searchTerm}"; - params["ordering"] = await orderingString; + + // Use custom query ordering if available + String o = await orderingString; + if (o.isNotEmpty) { + params["ordering"] = o; + } final page = await requestPage( _pageSize, @@ -226,6 +241,7 @@ class PaginatedSearchState extends State with BaseW } } + // Callback function when the search term is updated void updateSearchTerm() { searchTerm = searchController.text; _pagingController.refresh(); From 2e7abf8a1ee824c6d0b30097039c252e84d14a64 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:21:19 +1000 Subject: [PATCH 216/746] Allow "trailing" widget to be displayed on home screen entries --- lib/widget/home.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 19f1c95..0870b02 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -192,7 +192,7 @@ class _InvenTreeHomePageState extends State { } - Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = ""}) { + Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = "", Widget? trailing}) { bool connected = InvenTreeAPI().isConnected(); @@ -211,6 +211,7 @@ class _InvenTreeHomePageState extends State { child: ListTile( leading: FaIcon(icon, color: connected && allowed ? COLOR_CLICK : Colors.grey), title: Text(label), + trailing: trailing, ), ), onTap: () { @@ -257,7 +258,7 @@ class _InvenTreeHomePageState extends State { FontAwesomeIcons.shapes, callback: () { _showParts(context); - } + }, )); // Starred parts From 847fda7652d07bc42ecc8037e705cca130d93a8e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:24:26 +1000 Subject: [PATCH 217/746] Enable ordering for purchase order list --- lib/l10n/app_en.arb | 3 +++ lib/widget/purchase_order_list.dart | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 558418f..4c00ca1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -691,6 +691,9 @@ "receivedItem": "Received Stock Item", "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", "@refresh": {}, diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index ec3b1a0..ef3c6a7 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -58,6 +58,17 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState "po_"; + + @override + Map get orderingOptions => { + "reference": L10().reference, + "supplier__name": L10().supplier, + "status": L10().status, + "target_date": L10().targetDate, + }; + @override Future requestPage(int limit, int offset, Map params) async { From ed2523c3c57b4430482638cf04f366a74f7707b5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:29:26 +1000 Subject: [PATCH 218/746] Linting fixes --- lib/widget/attachment_widget.dart | 12 ++++++------ lib/widget/back.dart | 7 +++---- lib/widget/bom_list.dart | 3 --- lib/widget/paginator.dart | 2 -- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 8437ae7..0a95d0f 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -1,9 +1,3 @@ -/* - * A generic widget for displaying a list of attachments. - * - * To allow use with different "types" of attachments, - * we pass a subclassed instance of the InvenTreeAttachment model. - */ import "dart:io"; @@ -17,6 +11,12 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; import "package:url_launcher/url_launcher.dart"; +/* + * A generic widget for displaying a list of attachments. + * + * To allow use with different "types" of attachments, + * we pass a subclassed instance of the InvenTreeAttachment model. + */ class AttachmentWidget extends StatefulWidget { const AttachmentWidget(this.attachment, this.referenceId, this.hasUploadPermission) : super(); diff --git a/lib/widget/back.dart b/lib/widget/back.dart index 9797e4b..27a9c23 100644 --- a/lib/widget/back.dart +++ b/lib/widget/back.dart @@ -1,11 +1,10 @@ +import "package:flutter/material.dart"; + /* - * A custom implementation of a "Back" button for display in the app drawer + * Construct a custom back button with special feature! * * Long-pressing on this will return the user to the home screen */ - -import "package:flutter/material.dart"; - Widget backButton(BuildContext context, GlobalKey key) { return GestureDetector( diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 14cd490..3014fb0 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -1,9 +1,7 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; -import "package:inventree/api_form.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/bom.dart"; import "package:inventree/l10.dart"; @@ -95,7 +93,6 @@ class _PaginatedBomListState extends PaginatedSearchState { InvenTreePart? subPart = bomItem.subPart; String title = subPart?.fullname ?? "error - no name"; - String description = subPart?.description ?? "error - no description"; return ListTile( title: Text(title), diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 7b6f803..91ba215 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -24,8 +24,6 @@ class PaginatedSearchState extends State with BaseW PaginatedSearchState(this.filters); - final _key = GlobalKey(); - final Map filters; static const _pageSize = 25; From 38004228aaa6b7f073089e3d75f35be53233d6d2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 6 Jul 2022 21:38:48 +1000 Subject: [PATCH 219/746] Increment version and build numbers --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6528ab4..e4fd766 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.7.2+44 +version: 0.8.0+45 environment: sdk: ">=2.16.0 <3.0.0" From 900074f45814e3e7e74bbc0bd8f6b426e86c7ac1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 12 Jul 2022 11:41:06 +1000 Subject: [PATCH 220/746] New Crowdin updates (#168) * New translations app_en.arb (Italian) * New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 10 ++++++++++ lib/l10n/it_IT/app_it_IT.arb | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index c938253..f63b6ad 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -204,6 +204,8 @@ "@feedbackError": {}, "feedbackSuccess": "Visszajelzés elküldve", "@feedbackSuccess": {}, + "filteringOptions": "Szűrési beállítások", + "@filteringOptions": {}, "formatException": "Formátum hiba", "@formatException": {}, "formatExceptionJson": "JSON adatformátum hiba", @@ -291,6 +293,8 @@ "@lastStocktake": {}, "lastUpdated": "Utoljára módosítva", "@lastUpdated": {}, + "level": "Szint", + "@level": {}, "lineItem": "Sortétel", "@lineItem": {}, "lineItems": "Sortételek", @@ -447,6 +451,8 @@ "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Elérhető mennyiség", + "@quantityAvailable": {}, "quantityEmpty": "Mennyiség üres", "@quantityEmpty": {}, "quantityInvalid": "Mennyiség érvénytelen", @@ -465,6 +471,8 @@ "@receiveItem": {}, "receivedItem": "Beérkezett készlet", "@receivedItem": {}, + "reference": "Azonosító", + "@reference": {}, "refresh": "Frissítés", "@refresh": {}, "refreshing": "Frissítés...", @@ -765,6 +773,8 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Érték megadása szükséges", "@valueRequired": {}, + "variants": "Változatok", + "@variants": {}, "version": "Verzió", "@version": {}, "viewSupplierPart": "Beszállítói alkatrész megtekintése", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index e8ca508..52d0be2 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -1,5 +1,13 @@ { "@@locale": "en", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "Ok", + "@ok": { + "description": "OK" + }, "about": "Info", "@about": {}, "accountDetails": "Dettagli account", @@ -14,6 +22,10 @@ "@add": { "description": "add" }, + "addStock": "Aggiungi Giacenza", + "@addStock": { + "description": "add stock" + }, "address": "Indirizzo", "@address": {}, "appAbout": "Info su InvenTree", @@ -36,10 +48,14 @@ }, "attachmentNone": "Nessun allegato trovato", "@attachmentNone": {}, + "attachmentNoneDetail": "Nessun allegato trovato", + "@attachmentNoneDetail": {}, "attachmentSelect": "Seleziona allegato", "@attachmentSelect": {}, "attention": "Attenzione", "@attention": {}, + "availableStock": "Giacenza Disponibile", + "@availableStock": {}, "barcodeAssign": "Assegna Codice A Barre", "@barcodeAssign": {}, "barcodeAssigned": "Codice a barre assegnato", @@ -124,6 +140,8 @@ }, "editCategory": "Modifica Categoria", "@editCategory": {}, + "editNotes": "Modifica Note", + "@editNotes": {}, "enterPassword": "Inserire la password", "@enterPassword": {}, "enterUsername": "Inserisci nome utente", @@ -154,6 +172,7 @@ "@history": { "description": "history" }, + "home": "Home", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "imageUploadFailure": "Il caricamento della foto è fallito", @@ -166,6 +185,8 @@ "@includeSubcategories": {}, "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", "@incompleteDetails": {}, + "info": "Info", + "@info": {}, "invalidHost": "Nome host non valido", "@invalidHost": {}, "invalidHostDetails": "Il nome host fornito non è valido", From acbb2d2947c244b0858711323af66b8e2c9aebf1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 13 Jul 2022 20:11:49 +1000 Subject: [PATCH 221/746] Prevent specific permissions from being requested (#170) open_file package requests the REQUEST_INSTALL_PACKAGES permission by default --- android/app/src/main/AndroidManifest.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 41a7000..39d93d4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -56,4 +56,11 @@ + + + + \ No newline at end of file From c6678e201ffe9ff6e835e4d03168640e4777f71c Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 14 Jul 2022 20:31:44 +1000 Subject: [PATCH 222/746] Fix broken android manifest (#172) - Adds xmlns:tools to manifest xml file - Ref: https://stackoverflow.com/questions/55334431/facing-below-error-toolsnode-associated-with-an-element-type-uses-permission --- android/app/src/main/AndroidManifest.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 39d93d4..cfb3762 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,6 @@ - - + + + diff --git a/android/build.gradle b/android/build.gradle index af27b36..a5b4564 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,14 +1,14 @@ buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.8.10' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:7.4.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -16,7 +16,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/android/gradle.properties b/android/gradle.properties index 5f17537..615b166 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +android.enableD8=true android.enableJetifier=true android.useAndroidX=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 9b9d49f..2b22d05 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip \ No newline at end of file diff --git a/lib/api.dart b/lib/api.dart index a096441..6d06f7f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -8,7 +8,7 @@ import "package:intl/intl.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; -import "package:open_file/open_file.dart"; +import "package:open_filex/open_filex.dart"; import "package:cached_network_image/cached_network_image.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -350,7 +350,7 @@ class InvenTreeAPI { if (address.isEmpty || username.isEmpty || password.isEmpty) { showSnackIcon( L10().incompleteDetails, - icon: FontAwesomeIcons.exclamationCircle, + icon: FontAwesomeIcons.circleExclamation, success: false ); return false; @@ -507,7 +507,7 @@ class InvenTreeAPI { showSnackIcon( L10().profileSelect, success: false, - icon: FontAwesomeIcons.exclamationCircle + icon: FontAwesomeIcons.circleExclamation ); return false; } @@ -731,7 +731,7 @@ class InvenTreeAPI { await localFile.writeAsBytes(bytes); if (openOnDownload) { - OpenFile.open(local_path); + OpenFilex.open(local_path); } } else { showStatusCodeError(url, response.statusCode); @@ -1272,7 +1272,7 @@ class InvenTreeAPI { return CachedNetworkImage( imageUrl: url, placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => FaIcon(FontAwesomeIcons.timesCircle, color: COLOR_DANGER), + errorWidget: (context, url, error) => FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER), httpHeaders: defaultHeaders(), height: height, width: width, @@ -1369,7 +1369,7 @@ class InvenTreeAPI { L10().locateLocation, "", fields, - icon: FontAwesomeIcons.searchLocation, + icon: FontAwesomeIcons.magnifyingGlassLocation, onSuccess: (Map data) async { plugin_name = (data["plugin"] ?? "") as String; } diff --git a/lib/api_form.dart b/lib/api_form.dart index e21eedb..360617a 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -415,7 +415,7 @@ class APIFormField { controller: controller, ), trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () async { FilePickerDialog.pickFile( message: L10().attachmentSelect, @@ -436,26 +436,32 @@ class APIFormField { // Field for selecting from multiple choice options Widget _constructChoiceField() { - dynamic _initial; + dynamic initial; // Check if the current value is within the allowed values for (var opt in choices) { if (opt["value"] == value) { - _initial = opt; + initial = opt; break; } } return DropdownSearch( - mode: Mode.BOTTOM_SHEET, - showSelectedItem: false, - selectedItem: _initial, + popupProps: PopupProps.bottomSheet( + showSelectedItems: false, + searchFieldProps: TextFieldProps( + autofocus: true + ) + ), + selectedItem: initial, items: choices, - label: label, - hint: helpText, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: label, + hintText: helpText, + )), onChanged: null, - autoFocusSearchBox: true, - showClearButton: !required, + clearButtonProps: ClearButtonProps(isVisible: !required), itemAsString: (dynamic item) { return (item["display_name"] ?? "") as String; }, @@ -465,8 +471,7 @@ class APIFormField { } else { data["value"] = item["value"]; } - } - ); + }); } // Construct a floating point numerical input field @@ -501,30 +506,37 @@ class APIFormField { // Construct an input for a related field Widget _constructRelatedField() { - return DropdownSearch( - mode: Mode.BOTTOM_SHEET, - showSelectedItem: true, + popupProps: PopupProps.bottomSheet( + showSelectedItems: true, + isFilterOnline: true, + showSearchBox: true, + itemBuilder: (context, item, isSelected) { + return _renderRelatedField(item, isSelected, true); + }, + emptyBuilder: (context, item) { + return _renderEmptyResult(); + }, + searchFieldProps: TextFieldProps( + autofocus: true + ) + ), selectedItem: initial_data, - onFind: (String filter) async { - - Map _filters = {}; + asyncItems: (String filter) async { + Map filters = {}; filters.forEach((key, value) { - _filters[key] = value; + filters[key] = value; }); - _filters["search"] = filter; - _filters["offset"] = "0"; - _filters["limit"] = "25"; + filters["search"] = filter; + filters["offset"] = "0"; + filters["limit"] = "25"; - final APIResponse response = await InvenTreeAPI().get( - api_url, - params: _filters - ); + final APIResponse response = + await InvenTreeAPI().get(api_url, params: filters); if (response.isValid()) { - List results = []; for (var result in response.data["results"] ?? []) { @@ -536,12 +548,16 @@ class APIFormField { return []; } }, - label: label, - hint: helpText, + clearButtonProps: ClearButtonProps( + isVisible: !required + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: label, + hintText: helpText, + )), onChanged: null, - showClearButton: !required, itemAsString: (dynamic item) { - Map data = item as Map; switch (model) { @@ -555,15 +571,9 @@ class APIFormField { return "itemAsString not implemented for '${model}'"; } }, - dropdownBuilder: (context, item, itemAsString) { + dropdownBuilder: (context, item) { return _renderRelatedField(item, true, false); }, - popupItemBuilder: (context, item, isSelected) { - return _renderRelatedField(item, isSelected, true); - }, - emptyBuilder: (context, item) { - return _renderEmptyResult(); - }, onSaved: (item) { if (item != null) { data["value"] = item["pk"]; @@ -571,9 +581,6 @@ class APIFormField { data["value"] = null; } }, - isFilteredOnline: true, - showSearchBox: true, - autoFocusSearchBox: true, compareFn: (dynamic item, dynamic selectedItem) { // Comparison is based on the PK value @@ -582,8 +589,7 @@ class APIFormField { } return item["pk"] == selectedItem["pk"]; - } - ); + }); } Widget _renderRelatedField(dynamic item, bool selected, bool extended) { @@ -672,7 +678,7 @@ class APIFormField { // Construct a widget to instruct the user that no results were found Widget _renderEmptyResult() { return ListTile( - leading: FaIcon(FontAwesomeIcons.search), + leading: FaIcon(FontAwesomeIcons.magnifyingGlass), title: Text(L10().noResults), subtitle: Text( L10().queryNoResults, @@ -865,7 +871,7 @@ Future launchApiForm( String method = "PATCH", Function(Map)? onSuccess, Function? onCancel, - IconData icon = FontAwesomeIcons.save, + IconData icon = FontAwesomeIcons.floppyDisk, }) async { showLoadingOverlay(context); @@ -889,7 +895,7 @@ Future launchApiForm( // User does not have permission to perform this action showSnackIcon( L10().response403, - icon: FontAwesomeIcons.userTimes, + icon: FontAwesomeIcons.userXmark, ); hideLoadingOverlay(); @@ -971,7 +977,7 @@ class APIFormWidget extends StatefulWidget { Key? key, this.onSuccess, this.fileField = "", - this.icon = FontAwesomeIcons.save, + this.icon = FontAwesomeIcons.floppyDisk, } ) : super(key: key); @@ -1025,7 +1031,7 @@ class _APIFormWidgetState extends State { ), ), leading: FaIcon( - FontAwesomeIcons.exclamationCircle, + FontAwesomeIcons.circleExclamation, color: COLOR_DANGER ), ) diff --git a/lib/barcode.dart b/lib/barcode.dart index e9d0262..77dbb40 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -105,7 +105,7 @@ class BarcodeHandler { showSnackIcon( L10().barcodeError, - icon: FontAwesomeIcons.exclamationCircle, + icon: FontAwesomeIcons.circleExclamation, success: false ); @@ -179,7 +179,7 @@ class BarcodeScanHandler extends BarcodeHandler { showSnackIcon( L10().barcodeNoMatch, - icon: FontAwesomeIcons.exclamationCircle, + icon: FontAwesomeIcons.circleExclamation, success: false, ); } diff --git a/lib/helpers.dart b/lib/helpers.dart index b574c60..085a051 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -74,6 +74,6 @@ Future playAudioFile(String path) async { return; } - final player = AudioCache(); - player.play(path); + final player = AudioPlayer(); + player.play(AssetSource(path)); } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index e2fe980..33d5e47 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -223,8 +223,9 @@ class InvenTreeModel { Future goToInvenTreePage() async { - if (await canLaunch(webUrl)) { - await launch(webUrl); + var uri = Uri.tryParse(webUrl); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); } else { // TODO } @@ -233,9 +234,9 @@ class InvenTreeModel { Future openLink() async { if (link.isNotEmpty) { - - if (await canLaunch(link)) { - await launch(link); + var uri = Uri.tryParse(link); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); } } } @@ -799,7 +800,7 @@ class InvenTreeAttachment extends InvenTreeModel { } } - return FontAwesomeIcons.fileAlt; + return FontAwesomeIcons.fileLines; } String get comment => (jsondata["comment"] ?? "") as String; diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 72964d6..de24733 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -37,7 +37,7 @@ Future> getDeviceInfo() async { "model": androidDeviceInfo.model, "device": androidDeviceInfo.device, "id": androidDeviceInfo.id, - "androidId": androidDeviceInfo.androidId, + "androidId": androidDeviceInfo.id, "brand": androidDeviceInfo.brand, "display": androidDeviceInfo.display, "hardware": androidDeviceInfo.hardware, @@ -202,6 +202,7 @@ Future sentryReportError(String source, dynamic error, dynamic stackTrace, Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { print("Error uploading information to Sentry.io:"); print(error); + return SentryId.empty(); }).then((response) { print("Uploaded information to Sentry.io : ${response.toString()}"); }); diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 7ba8c5d..5ac468b 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -39,27 +39,36 @@ class InvenTreeAboutWidget extends StatelessWidget { Future _openDocs() async { - const String docsUrl = "https://inventree.readthedocs.io/en/latest/app/app/"; + var docsUrl = Uri( + scheme: "https", + host: "inventree.readthedocs.io", + path: "en/latest/app/app/"); - if (await canLaunch(docsUrl)) { - await launch(docsUrl); + if (await canLaunchUrl(docsUrl)) { + await launchUrl(docsUrl); } } Future _reportBug(BuildContext context) async { - const String url = "https://github.com/inventree/inventree-app/issues/new?title=Enter+bug+description"; + var url = Uri( + scheme: "https", + host: "github.com", + path: "inventree/inventree-app/issues/new?title=Enter+bug+description"); - if (await canLaunch(url)) { - await launch(url); + if (await canLaunchUrl(url)) { + await launchUrl(url); } } Future _translate() async { - const String url = "https://crowdin.com/project/inventree"; + var url = Uri( + scheme: "https", + host: "crowdin.com", + path: "/project/inventree"); - if (await canLaunch(url)) { - await launch(url); + if (await canLaunchUrl(url)) { + await launchUrl(url); } } @@ -83,7 +92,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().address), subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected), leading: FaIcon(FontAwesomeIcons.globe), - trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.timesCircle, color: COLOR_DANGER), + trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER), ) ); @@ -91,7 +100,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().version), subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.infoCircle), + leading: FaIcon(FontAwesomeIcons.circleInfo), ) ); @@ -122,7 +131,7 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().serverNotConnected, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.exclamationCircle) + leading: FaIcon(FontAwesomeIcons.circleExclamation) ) ); } @@ -148,7 +157,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().version), subtitle: Text("${info.version} - Build ${info.buildNumber}"), - leading: FaIcon(FontAwesomeIcons.infoCircle) + leading: FaIcon(FontAwesomeIcons.circleInfo) ) ); @@ -156,7 +165,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), onTap: () { _releaseNotes(context); }, diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index a98bf9c..ad7e58d 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -81,7 +81,7 @@ class _InvenTreeAppSettingsState extends State { L10().languageSelect, "", fields, - icon: FontAwesomeIcons.checkCircle, + icon: FontAwesomeIcons.circleCheck, onSuccess: (Map data) async { String locale_name = (data["locale"] ?? "") as String; @@ -130,7 +130,7 @@ class _InvenTreeAppSettingsState extends State { L10().sounds, style: TextStyle(fontWeight: FontWeight.bold), ), - leading: FaIcon(FontAwesomeIcons.volumeUp), + leading: FaIcon(FontAwesomeIcons.volumeHigh), ), ListTile( title: Text(L10().serverError), diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 071f96f..926f31d 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -74,7 +74,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowPo), subtitle: Text(L10().homeShowPoDescription), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Switch( value: homeShowPo, onChanged: (bool value) { diff --git a/lib/settings/login.dart b/lib/settings/login.dart index abccf9b..e4606e6 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -100,7 +100,7 @@ class _InvenTreeLoginSettingsState extends State { // Selected, but (for some reason) not the same as the API... if ((InvenTreeAPI().profile?.key ?? "") != profile.key) { return FaIcon( - FontAwesomeIcons.questionCircle, + FontAwesomeIcons.circleQuestion, color: COLOR_WARNING ); } @@ -108,7 +108,7 @@ class _InvenTreeLoginSettingsState extends State { // Reflect the connection status of the server if (InvenTreeAPI().isConnected()) { return FaIcon( - FontAwesomeIcons.checkCircle, + FontAwesomeIcons.circleCheck, color: COLOR_SUCCESS ); } else if (InvenTreeAPI().isConnecting()) { @@ -118,7 +118,7 @@ class _InvenTreeLoginSettingsState extends State { ); } else { return FaIcon( - FontAwesomeIcons.timesCircle, + FontAwesomeIcons.circleXmark, color: COLOR_DANGER, ); } @@ -167,7 +167,7 @@ class _InvenTreeLoginSettingsState extends State { }, child: ListTile( title: Text(L10().profileEdit), - leading: FaIcon(FontAwesomeIcons.edit) + leading: FaIcon(FontAwesomeIcons.penToSquare) ) ), SimpleDialogOption( @@ -184,7 +184,7 @@ class _InvenTreeLoginSettingsState extends State { }, child: ListTile( title: Text(L10().profileDelete), - leading: FaIcon(FontAwesomeIcons.trashAlt), + leading: FaIcon(FontAwesomeIcons.trashCan), ) ) ], @@ -209,7 +209,7 @@ class _InvenTreeLoginSettingsState extends State { title: Text(L10().profileSelect), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () { _editProfile(context, createNew: true); }, @@ -259,7 +259,7 @@ class _ProfileEditState extends State { title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.save), + icon: FaIcon(FontAwesomeIcons.floppyDisk), onPressed: () async { if (formKey.currentState!.validate()) { formKey.currentState!.save(); diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 51282e5..50d3f0d 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -47,7 +47,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().parameters), subtitle: Text(L10().parametersSettingDetail), - leading: FaIcon(FontAwesomeIcons.thList), + leading: FaIcon(FontAwesomeIcons.tableList), trailing: Switch( value: partShowParameters, onChanged: (bool value) { @@ -75,7 +75,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().stockItemHistory), subtitle: Text(L10().stockItemHistoryDetail), - leading: FaIcon(FontAwesomeIcons.history), + leading: FaIcon(FontAwesomeIcons.clockRotateLeft), trailing: Switch( value: stockShowHistory, onChanged: (bool value) { diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index e3f9b2d..4e8bf03 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -45,7 +45,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), - leading: FaIcon(FontAwesomeIcons.home, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.house, color: COLOR_CLICK), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } @@ -53,7 +53,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); } diff --git a/lib/user_profile.dart b/lib/user_profile.dart index bee9a93..53d7c0d 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -103,7 +103,7 @@ class UserProfileDBManager { debug("Adding new profile: '${profile.name}'"); } - int key = await store.add(await _db, profile.toJson()) as int; + int? key = await store.add(await _db, profile.toJson()) as int?; // Record the key profile.key = key; @@ -156,8 +156,8 @@ class UserProfileDBManager { if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, + profiles[idx].key! as int, + profiles[idx].value! as Map, profiles[idx].key == selected, ); } @@ -182,8 +182,8 @@ class UserProfileDBManager { if (profiles[idx].key is int) { profileList.add( UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, + profiles[idx].key! as int, + profiles[idx].value! as Map, profiles[idx].key == selected, ) ); diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 6d54bdd..8320d1a 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -54,7 +54,7 @@ class _AttachmentWidgetState extends RefreshableState { // File upload actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () async { FilePickerDialog.pickFile( onPicked: (File file) async { @@ -117,7 +117,7 @@ class _AttachmentWidgetState extends RefreshableState { }, child: ListTile( title: Text(L10().delete), - leading: FaIcon(FontAwesomeIcons.trashAlt), + leading: FaIcon(FontAwesomeIcons.trashCan), ) ) ] @@ -187,8 +187,9 @@ class _AttachmentWidgetState extends RefreshableState { subtitle: Text(attachment.comment), leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), onTap: () async { - if (await canLaunch(attachment.link)) { - await launch(attachment.link); + var uri = Uri.tryParse(attachment.link.trimLeft()); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); } }, onLongPress: () { diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index a432e3a..e72ec2a 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -43,7 +43,7 @@ class _CategoryDisplayState extends RefreshableState { if ((widget.category != null) && InvenTreeAPI().checkPermission("part_category", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editCategoryDialog(context); @@ -121,7 +121,7 @@ class _CategoryDisplayState extends RefreshableState { title: Text(L10().parentCategory), subtitle: Text("${widget.category?.parentPathString}"), leading: FaIcon( - FontAwesomeIcons.levelUpAlt, + FontAwesomeIcons.turnUp, color: COLOR_CLICK, ), onTap: () async { @@ -338,7 +338,7 @@ class _CategoryDisplayState extends RefreshableState { subtitle: Text( L10().permissionAccountDenied, ), - leading: FaIcon(FontAwesomeIcons.userTimes), + leading: FaIcon(FontAwesomeIcons.userXmark), ) ); } diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index e5f0546..093ce07 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -56,7 +56,7 @@ class _CompanyDetailState extends RefreshableState { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { editCompany(context); @@ -203,7 +203,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_CLICK), trailing: Text("${outstandingOrders.length}"), onTap: () { Navigator.push( @@ -246,7 +246,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.notes.isNotEmpty) { tiles.add(ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote), + leading: FaIcon(FontAwesomeIcons.noteSticky), onTap: null, )); } diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 322e20c..ba09b30 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -13,7 +13,7 @@ import "package:inventree/widget/snacks.dart"; /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ -Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { +Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; @@ -63,7 +63,7 @@ Future confirmationDialog(String title, String text, {IconData icon = Font * @description = Simple string description of error * @data = Error response (e.g from server) */ -Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.exclamationCircle, Function? onDismissed}) async { +Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.circleExclamation, Function? onDismissed}) async { List children = []; diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 0aecc5f..c760ce2 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -96,7 +96,7 @@ class InvenTreeDrawer extends StatelessWidget { context: context, tiles: [ ListTile( - leading: FaIcon(FontAwesomeIcons.home), + leading: FaIcon(FontAwesomeIcons.house), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -110,7 +110,7 @@ class InvenTreeDrawer extends StatelessWidget { ), ListTile( title: Text(L10().search), - leading: FaIcon(FontAwesomeIcons.search), + leading: FaIcon(FontAwesomeIcons.magnifyingGlass), onTap: _search, ), ListTile( @@ -120,7 +120,7 @@ class InvenTreeDrawer extends StatelessWidget { ), ListTile( title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.infoCircle), + leading: FaIcon(FontAwesomeIcons.circleInfo), onTap: _about, ) ] diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index a5dac73..16f45e6 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -80,7 +80,7 @@ class FilePickerDialog { actions.add( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.fileUpload), + leading: FaIcon(FontAwesomeIcons.fileArrowUp), title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 0d15546..8307f15 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -237,7 +237,7 @@ class _InvenTreeHomePageState extends State { if (!allowed) { showSnackIcon( L10().permissionRequired, - icon: FontAwesomeIcons.exclamationCircle, + icon: FontAwesomeIcons.circleExclamation, success: false, ); @@ -295,7 +295,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().stock, - FontAwesomeIcons.boxes, + FontAwesomeIcons.boxesStacked, callback: () { _showStock(context); } @@ -306,7 +306,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().purchaseOrders, - FontAwesomeIcons.shoppingCart, + FontAwesomeIcons.cartShopping, callback: () { _showPurchaseOrders(context); } @@ -358,7 +358,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().settings, - FontAwesomeIcons.cogs, + FontAwesomeIcons.gears, callback: () { _showSettings(context); } @@ -377,7 +377,7 @@ class _InvenTreeHomePageState extends State { bool validAddress = serverAddress != null; bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); - Widget leading = FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_DANGER); + Widget leading = FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER); Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK); String title = L10().serverNotConnected; String subtitle = L10().profileSelectOrCreate; @@ -443,11 +443,11 @@ class _InvenTreeHomePageState extends State { List items = [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.home), + icon: FaIcon(FontAwesomeIcons.house), label: L10().home, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.search), + icon: FaIcon(FontAwesomeIcons.magnifyingGlass), label: L10().search, ), ]; diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 9f150c8..95e45ae 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -54,7 +54,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeAPI().supportsMixin("locate")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.searchLocation), + icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), tooltip: L10().locateLocation, onPressed: () async { _locateStockLocation(context); @@ -67,7 +67,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock_location", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editLocationDialog(context); }, ) @@ -202,7 +202,7 @@ class _LocationDisplayState extends RefreshableState { L10().stockTopLevel, style: TextStyle(fontStyle: FontStyle.italic) ), - leading: FaIcon(FontAwesomeIcons.boxes), + leading: FaIcon(FontAwesomeIcons.boxesStacked), ) ); } else { @@ -211,7 +211,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text("${location!.name}"), subtitle: Text("${location!.description}"), - leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxes), + leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxesStacked), ), ]; @@ -220,7 +220,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().parentLocation), subtitle: Text("${location!.parentPathString}"), - leading: FaIcon(FontAwesomeIcons.levelUpAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_CLICK), onTap: () async { int parentId = location?.parentId ?? -1; @@ -261,7 +261,7 @@ class _LocationDisplayState extends RefreshableState { label: L10().details, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), + icon: FaIcon(FontAwesomeIcons.boxesStacked), label: L10().stock, ), BottomNavigationBarItem( @@ -379,7 +379,7 @@ class _LocationDisplayState extends RefreshableState { title: Text(L10().locationCreate), subtitle: Text(L10().locationCreateDetail), leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: () async { _newLocation(context); }, @@ -390,8 +390,8 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().stockItemCreate), subtitle: Text(L10().stockItemCreateDetail), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), + trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: () async { _newStockItem(context); }, @@ -408,7 +408,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().barcodeScanItem), subtitle: Text(L10().barcodeScanInItems), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), trailing: Icon(Icons.qr_code, color: COLOR_CLICK), onTap: () { @@ -434,7 +434,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().transferStockLocation), subtitle: Text(L10().transferStockLocationDetail), - leading: FaIcon(FontAwesomeIcons.signInAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightToBracket, color: COLOR_CLICK), trailing: Icon(Icons.qr_code, color: COLOR_CLICK), onTap: () { var _loc = location; diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 71f6485..86b76c1 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -198,7 +198,7 @@ abstract class PaginatedSearchState extends Sta L10().filteringOptions, "", fields, - icon: FontAwesomeIcons.checkCircle, + icon: FontAwesomeIcons.circleCheck, onSuccess: (Map data) async { // Extract data from the processed form @@ -417,7 +417,7 @@ abstract class PaginatedSearchState extends Sta ), trailing: GestureDetector( child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, + searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK, ), onTap: () { @@ -454,7 +454,7 @@ class NoResultsWidget extends StatelessWidget { description, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_WARNING), + leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_WARNING), ); } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index b347e49..3ebab6d 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -85,7 +85,7 @@ class _PartDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("part", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editPartDialog(context); @@ -304,7 +304,7 @@ class _PartDisplayState extends RefreshableState { ) ), leading: FaIcon( - FontAwesomeIcons.exclamationCircle, + FontAwesomeIcons.circleExclamation, color: COLOR_DANGER ), ) @@ -395,7 +395,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), trailing: Text( part.stockString(), style: TextStyle( @@ -418,7 +418,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().onOrder), subtitle: Text(L10().onOrderDetails), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Text("${part.onOrderString}"), onTap: () { // TODO - Order views @@ -435,7 +435,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), trailing: Text(bomCount.toString()), onTap: () { Navigator.push( @@ -453,7 +453,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().building), - leading: FaIcon(FontAwesomeIcons.tools), + leading: FaIcon(FontAwesomeIcons.screwdriverWrench), trailing: Text("${simpleNumberString(part.building)}"), onTap: () { // TODO @@ -548,7 +548,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().parameters), - leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), trailing: parameterCount > 0 ? Text(parameterCount.toString()) : null, onTap: () { Navigator.push( @@ -566,7 +566,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), trailing: Text(""), onTap: () { Navigator.push( @@ -580,7 +580,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( @@ -749,11 +749,11 @@ class _PartDisplayState extends RefreshableState { onTap: onTabSelectionChanged, items: [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.infoCircle), + icon: FaIcon(FontAwesomeIcons.circleInfo), label: L10().details, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), + icon: FaIcon(FontAwesomeIcons.boxesStacked), label: L10().stock ), BottomNavigationBarItem( diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart index a582dce..fc4d0b9 100644 --- a/lib/widget/part_image_widget.dart +++ b/lib/widget/part_image_widget.dart @@ -47,7 +47,7 @@ class _PartImageState extends RefreshableState { // File upload actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.fileUpload), + icon: FaIcon(FontAwesomeIcons.fileArrowUp), onPressed: () async { FilePickerDialog.pickFile( diff --git a/lib/widget/part_notes.dart b/lib/widget/part_notes.dart index 6ceb23e..32bffe9 100644 --- a/lib/widget/part_notes.dart +++ b/lib/widget/part_notes.dart @@ -40,7 +40,7 @@ class _PartNotesState extends RefreshableState { if (InvenTreeAPI().checkPermission("part", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { part.editForm( diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 3b9a154..d81d176 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -52,7 +52,7 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( @@ -250,7 +250,7 @@ class _PurchaseOrderDetailState extends RefreshableState extends State with @override void initState() { super.initState(); - WidgetsBinding.instance?.addPostFrameCallback((_) => onBuild(_context!)); + WidgetsBinding.instance.addPostFrameCallback((_) => onBuild(_context!)); } // Function called after the widget is first build diff --git a/lib/widget/search.dart b/lib/widget/search.dart index ccfb180..59608c8 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -263,7 +263,7 @@ class _SearchDisplayState extends RefreshableState { ), trailing: GestureDetector( child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, + searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, color: searchController.text.isEmpty ? COLOR_CLICK : COLOR_DANGER, ), onTap: () { @@ -331,7 +331,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockItems), - leading: FaIcon(FontAwesomeIcons.boxes), + leading: FaIcon(FontAwesomeIcons.boxesStacked), trailing: Text("${nStockResults}"), onTap: () { Navigator.push( @@ -354,7 +354,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockLocations), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + leading: FaIcon(FontAwesomeIcons.locationDot), trailing: Text("${nLocationResults}"), onTap: () { Navigator.push( @@ -402,7 +402,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Text("${nPurchaseOrderResults}"), onTap: () { Navigator.push( @@ -424,7 +424,7 @@ class _SearchDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().searching), - leading: FaIcon(FontAwesomeIcons.search), + leading: FaIcon(FontAwesomeIcons.magnifyingGlass), trailing: CircularProgressIndicator(), ) ); @@ -437,7 +437,7 @@ class _SearchDisplayState extends RefreshableState { L10().queryNoResults, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.searchMinus), + leading: FaIcon(FontAwesomeIcons.magnifyingGlassMinus), ) ); } else { diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index f941443..b5341af 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -32,14 +32,14 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc // Select an icon if we do not have an action if (icon == null && onAction == null) { - icon = FontAwesomeIcons.checkCircle; + icon = FontAwesomeIcons.circleCheck; } } else if (success != null && success == false) { backgroundColor = Colors.deepOrange; if (icon == null && onAction == null) { - icon = FontAwesomeIcons.exclamationCircle; + icon = FontAwesomeIcons.circleExclamation; } } diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index e29635b..240a6d9 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -63,7 +63,7 @@ class _StockItemDisplayState extends RefreshableState { if (InvenTreeAPI().supportsMixin("locate")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.searchLocation), + icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), tooltip: L10().locateItem, onPressed: () async { InvenTreeAPI().locateItemOrLocation(context, item: widget.item.pk); @@ -75,7 +75,7 @@ class _StockItemDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editStockItem(context); }, ) @@ -189,7 +189,7 @@ class _StockItemDisplayState extends RefreshableState { confirmationDialog( L10().stockItemDelete, L10().stockItemDeleteConfirm, - icon: FontAwesomeIcons.trashAlt, + icon: FontAwesomeIcons.trashCan, onAccept: () async { final bool result = await widget.item.delete(); @@ -337,7 +337,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.addStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.plusCircle, + icon: FontAwesomeIcons.circlePlus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -378,7 +378,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.removeStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.minusCircle, + icon: FontAwesomeIcons.circleMinus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -527,7 +527,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().stockLocation), subtitle: Text("${widget.item.locationPathString}"), leading: FaIcon( - FontAwesomeIcons.mapMarkerAlt, + FontAwesomeIcons.locationDot, color: COLOR_CLICK, ), onTap: () async { @@ -549,7 +549,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().stockLocation), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + leading: FaIcon(FontAwesomeIcons.locationDot), subtitle: Text(L10().locationNotSet), ) ); @@ -587,7 +587,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().inProduction), - leading: FaIcon(FontAwesomeIcons.tools), + leading: FaIcon(FontAwesomeIcons.screwdriverWrench), subtitle: Text(L10().inProductionDetail), onTap: () { // TODO: Click through to the "build order" @@ -623,7 +623,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastUpdated), subtitle: Text(widget.item.updatedDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) + leading: FaIcon(FontAwesomeIcons.calendarDays) ) ); } @@ -634,7 +634,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastStocktake), subtitle: Text(widget.item.stocktakeDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) + leading: FaIcon(FontAwesomeIcons.calendarDays) ) ); } @@ -655,7 +655,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().testResults), - leading: FaIcon(FontAwesomeIcons.tasks, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_CLICK), trailing: Text("${widget.item.testResultCount}"), onTap: () { Navigator.push( @@ -686,7 +686,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_CLICK), trailing: Text("${widget.item.trackingItemCount}"), onTap: () { Navigator.push( @@ -705,7 +705,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), onTap: () { Navigator.push( context, @@ -718,7 +718,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( @@ -747,7 +747,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().permissionRequired), - leading: FaIcon(FontAwesomeIcons.userTimes) + leading: FaIcon(FontAwesomeIcons.userXmark) ) ); @@ -765,7 +765,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().countStock), - leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_CLICK), onTap: _countStockDialog, trailing: Text(widget.item.quantityString(includeUnits: true)), ) @@ -774,7 +774,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().removeStock), - leading: FaIcon(FontAwesomeIcons.minusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circleMinus, color: COLOR_CLICK), onTap: _removeStockDialog, ) ); @@ -782,7 +782,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().addStock), - leading: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: _addStockDialog, ) ); @@ -792,7 +792,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().transferStock), subtitle: Text(L10().transferStockDetail), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), onTap: () { _transferStockDialog(context); }, ) ); @@ -802,7 +802,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().scanIntoLocation), subtitle: Text(L10().scanIntoLocationDetail), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), trailing: Icon(Icons.qr_code_scanner), onTap: () { Navigator.push( @@ -850,7 +850,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("Delete Stock Item"), - leading: FaIcon(FontAwesomeIcons.trashAlt, color: COLOR_DANGER), + leading: FaIcon(FontAwesomeIcons.trashCan, color: COLOR_DANGER), onTap: () { _deleteItem(context); }, @@ -868,7 +868,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: onTabSelectionChanged, items: [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.infoCircle), + icon: FaIcon(FontAwesomeIcons.circleInfo), label: L10().details, ), BottomNavigationBarItem( diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index 0410a9b..3d602a9 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -34,7 +34,7 @@ class _StockItemTestResultDisplayState extends RefreshableState getAppBarActions(BuildContext context) { return [ IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () { addTestResult(context); } @@ -158,7 +158,7 @@ class _StockItemTestResultDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { item.editForm( diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index ee45e26..fdccbf7 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -43,7 +43,7 @@ class _SupplierPartDisplayState extends RefreshableState=2.16.0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index a12fa6d..4d2f8ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,44 +7,43 @@ environment: sdk: ">=2.16.0 <3.0.0" dependencies: - - audioplayers: ^0.20.1 # Play audio files + audioplayers: ^3.0.1 # Play audio files cached_network_image: ^3.2.0 # Download and cache remote images - camera: ^0.9.4 # Camera + camera: ^0.10.3 # Camera cupertino_icons: ^1.0.3 datetime_picker_formfield: ^2.0.0 # Date / time picker - device_info_plus: ^3.2.2 # Information about the device - dropdown_search: ^0.6.3 # Dropdown autocomplete form fields - file_picker: ^4.5.1 # Select files from the device + device_info_plus: ^8.0.0 # Information about the device + dropdown_search: ^5.0.5 # Dropdown autocomplete form fields + file_picker: ^5.2.5 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 flutter_localizations: sdk: flutter - flutter_localized_locales: 2.0.3 - flutter_markdown: ^0.6.9 # Rendering markdown + flutter_localized_locales: ^2.0.4 + flutter_markdown: ^0.6.13+1 # Rendering markdown flutter_overlay_loader: ^2.0.0 # Overlay screen support - font_awesome_flutter: ^9.1.0 # FontAwesome icon set + font_awesome_flutter: ^10.3.0 # FontAwesome icon set http: ^0.13.4 - image_picker: ^0.8.3 # Select or take photos + image_picker: ^0.8.6+1 # Select or take photos infinite_scroll_pagination: ^3.1.0 # Let the server do all the work! intl: ^0.17.0 - one_context: ^1.1.1 # Dialogs without requiring context - open_file: ^3.2.1 # Open local files - package_info_plus: ^1.0.4 # App information introspection - path: ^1.8.0 - path_provider: ^2.0.2 # Local file storage - qr_code_scanner: ^0.7.0 # Barcode scanning - sembast: ^3.1.0+2 # NoSQL data storage - sentry_flutter: ^6.4.0 # Error reporting - url_launcher: ^6.0.9 # Open link in system browser + one_context: ^2.1.0 # Dialogs without requiring context + open_filex: ^4.3.2 # Open local files + package_info_plus: ^3.0.2 # App information introspection + path: ^1.8.2 + path_provider: ^2.0.12 # Local file storage + qr_code_scanner: ^1.0.1 # Barcode scanning + sembast: ^3.4.0+6 # NoSQL data storage + sentry_flutter: ^6.19.0 # Error reporting + url_launcher: ^6.1.9 # Open link in system browser dev_dependencies: - flutter_launcher_icons: ^0.9.0 + flutter_launcher_icons: ^0.11.0 flutter_test: sdk: flutter - lint: ^1.8.0 - test: ^1.19.0 + lint: ^2.0.1 + test: ^1.22.0 flutter_icons: android: true diff --git a/test/api_test.dart b/test/api_test.dart index 33f2760..5990d16 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -2,15 +2,18 @@ * Unit tests for the InvenTree API code */ -import "package:test/test.dart"; +import "package:flutter_test/flutter_test.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/user_profile.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { diff --git a/test/barcode_test.dart b/test/barcode_test.dart index eaafa68..e7b3eee 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -15,7 +15,11 @@ import "package:inventree/user_profile.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; +import "setup.dart"; + + void main() { + setupTestEnv(); // Connect to the server setUpAll(() async { diff --git a/test/models_test.dart b/test/models_test.dart index 213ff56..0fe5c74 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -9,8 +9,11 @@ import "package:inventree/user_profile.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { await UserProfileDBManager().addProfile(UserProfile( diff --git a/test/preferences_test.dart b/test/preferences_test.dart index 7294159..5d42a06 100644 --- a/test/preferences_test.dart +++ b/test/preferences_test.dart @@ -2,10 +2,13 @@ * Unit tests for the preferences manager */ -import "package:test/test.dart"; +import "package:flutter_test/flutter_test.dart"; import "package:inventree/preferences.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { }); diff --git a/test/setup.dart b/test/setup.dart new file mode 100644 index 0000000..c4b5387 --- /dev/null +++ b/test/setup.dart @@ -0,0 +1,22 @@ + +import "package:flutter/services.dart"; +import "package:flutter_test/flutter_test.dart"; + +// This is the same as the following issue except it keeps the http client +// TestWidgetsFlutterBinding.ensureInitialized(); +class CustomBinding extends AutomatedTestWidgetsFlutterBinding { + @override + bool get overrideHttpClient => false; +} + +void setupTestEnv() { + // Uses custom binding to not override the http client + CustomBinding(); + + // Mock the path provider + const MethodChannel channel = MethodChannel("plugins.flutter.io/path_provider"); + TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + return "."; + }); +} \ No newline at end of file diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 9b672ad..144a146 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -5,7 +5,10 @@ import "package:test/test.dart"; import "package:inventree/user_profile.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { // Ensure we have a user profile available From 0493bb2a12c10f9e47834a4ae6205d3420e7d2f2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 11 Feb 2023 00:24:22 +1100 Subject: [PATCH 295/746] Update credits (#256) * Add contributors section (cherry picked from commit 757ac25d4c30191786e83a6acb492060d6a5411a) * Fixes for credits (cherry picked from commit b2737624f946b4b525663e32d81e2951d4382e78) * Add gorymoon --- assets/credits.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/assets/credits.md b/assets/credits.md index 525dc8d..bbc9c52 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -1,6 +1,23 @@ -## InvenTree App Credits ---- +## Contributors + +Thanks to the following contributors, for their work building this app! + +- [SchrodingersGat](https://github.com/SchrodingersGat) (*Lead Developer*) +- [Guusggg](https://github.com/Guusggg) +- [GoryMoon](https://github.com/GoryMoon) + +-------- + +## Assets + +The InvenTree App makes use of the following third party assets + +### Icons + +Icons are provided by [fontawesome](fontawesome.com) ### Sound Files -- Some sound files have been sourced from [https://www.zapsplat.com](https://www.zapsplat.com) +Sound files have been sourced from [https://www.zapsplat.com](https://www.zapsplat.com) + +-------- \ No newline at end of file From 7447a18e6480b929cd51b2b32b3148bf74b495d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20J=C3=A4rgren?= Date: Fri, 10 Feb 2023 21:13:09 +0100 Subject: [PATCH 296/746] Fix iOS CI invalid syntax (#257) --- .github/workflows/ios.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index b8afa47..61670f6 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -19,9 +19,9 @@ jobs: submodules: recursive - name: Setup Java uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '11' + with: + distribution: 'temurin' + java-version: '11' - name: Setup Flutter uses: subosito/flutter-action@v2 with: From 262a629923b4d6114f864a1ec69cc4756a0c1812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20J=C3=A4rgren?= Date: Fri, 10 Feb 2023 22:43:36 +0100 Subject: [PATCH 297/746] Bumped minimum iOS version (#258) --- ios/Podfile | 4 ++-- ios/Runner/Info.plist | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 11c9435..0564dd3 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your projects -platform :ios, '9.0' +platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -39,7 +39,7 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' end end end \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 3d514f8..74a9f38 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -67,5 +67,9 @@ UIViewControllerBasedStatusBarAppearance + LSApplicationQueriesSchemes + + https + From c7527e8b4e8e98545006a4c59ba355b2dc276313 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 16 Feb 2023 08:40:08 +1100 Subject: [PATCH 298/746] New translations app_en.arb (French) (#259) --- lib/l10n/fr_FR/app_fr_FR.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 665f7db..7941682 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -76,7 +76,7 @@ "@barcodeScanAssign": {}, "barcodeScanGeneral": "Scanner un code-barres InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scannez les items de stock dans cet l'emplacement", + "barcodeScanInItems": "Scannez les éléments de stock dans cet l'emplacement", "@barcodeScanInItems": {}, "barcodeScanLocation": "Scanner la localisation du stock", "@barcodeScanLocation": {}, @@ -226,7 +226,7 @@ "@filterComponentDetail": {}, "filterInStock": "En stock", "@filterInStock": {}, - "filterInStockDetail": "Afficher les pièces en stock", + "filterInStockDetail": "Afficher les pièces qui ont du stock", "@filterInStockDetail": {}, "filterSerialized": "Sérialisé", "@filterSerialized": {}, From 9485d858eb0cd6a8b0b90b1b3a087bf864c6f13e Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 16 Feb 2023 22:50:32 +1100 Subject: [PATCH 299/746] Add support for company attachments (#261) * Add support for company attachments - Add API version check - Add new class - Add link to company detail page - Assorted refactoring * linting fixes --- assets/release_notes.md | 5 ++++ lib/api.dart | 19 +++++++----- lib/inventree/company.dart | 20 +++++++++++++ lib/widget/attachment_widget.dart | 1 - lib/widget/company_detail.dart | 50 ++++++++++++++++++++++++++----- lib/widget/location_display.dart | 15 +++++----- lib/widget/part_detail.dart | 19 ++++++------ lib/widget/refreshable_state.dart | 8 ++++- 8 files changed, 102 insertions(+), 35 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index dab3118..3e6cee7 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.11.0 - +--- + +- Add support for attachments on Companies + ### 0.10.0 - February 2023 --- diff --git a/lib/api.dart b/lib/api.dart index 6d06f7f..d8b012d 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -258,17 +258,26 @@ class InvenTreeAPI { int get apiVersion => _apiVersion; + // API endpoint for receiving purchase order line items was introduced in v12 + bool get supportsPoReceive => apiVersion >= 12; + // Notification support requires API v25 or newer bool get supportsNotifications => isConnected() && apiVersion >= 25; + // Return True if the API supports 'settings' (requires API v46) + bool get supportsSettings => isConnected() && apiVersion >= 46; + + // Part parameter support requires API v56 or newer + bool get supportsPartParameters => isConnected() && apiVersion >= 56; + // Supports 'modern' barcode API (v80 or newer) bool get supportModernBarcodes => isConnected() && apiVersion >= 80; // Structural categories requires API v83 or newer bool get supportsStructuralCategories => isConnected() && apiVersion >= 83; - // Part parameter support requires API v56 or newer - bool get supportsPartParameters => isConnected() && apiVersion >= 56; + // Company attachments require API v95 or newer + bool get supportCompanyAttachments => isConnected() && apiVersion >= 95; // Are plugins enabled on the server? bool _pluginsEnabled = false; @@ -322,9 +331,6 @@ class InvenTreeAPI { // Ensure we only ever create a single instance of the API class static final InvenTreeAPI _api = InvenTreeAPI._internal(); - // API endpoint for receiving purchase order line items was introduced in v12 - bool get supportsPoReceive => apiVersion >= 12; - /* * Connect to the remote InvenTree server: * @@ -1280,9 +1286,6 @@ class InvenTreeAPI { ); } - // Return True if the API supports 'settings' (requires API v46) - bool get supportsSettings => isConnected() && apiVersion >= 46; - // Keep a record of which settings we have received from the server Map _globalSettings = {}; Map _userSettings = {}; diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 8584554..a0d37a0 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -86,6 +86,26 @@ class InvenTreeCompany extends InvenTreeModel { } +/* + * Class representing an attachment file against a Company object + */ +class InvenTreeCompanyAttachment extends InvenTreeAttachment { + + InvenTreeCompanyAttachment() : super(); + + InvenTreeCompanyAttachment.fromJson(Map json) : super.fromJson(json); + + @override + String get REFERENCE_FIELD => "company"; + + @override + String get URL => "company/attachment/"; + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeCompanyAttachment.fromJson(json); + +} + /* * The InvenTreeSupplierPart class represents the SupplierPart model in the InvenTree database */ diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 8320d1a..6ee694b 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -134,7 +134,6 @@ class _AttachmentWidgetState extends RefreshableState { widget.attachment.REFERENCE_FIELD: widget.referenceId.toString() } ).then((var results) { - attachments.clear(); for (var result in results) { diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index 093ce07..7cc528f 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -8,12 +8,12 @@ import "package:inventree/app_colors.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/purchase_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/supplier_part_list.dart"; - /* * Widget for displaying detail view of a single Company instance */ @@ -37,6 +37,8 @@ class _CompanyDetailState extends RefreshableState { int supplierPartCount = 0; + int attachmentCount = 0; + @override String getAppBarTitle(BuildContext context) => L10().company; @@ -70,7 +72,6 @@ class _CompanyDetailState extends RefreshableState { @override Future request(BuildContext context) async { - final bool result = await widget.company.reload(); if (!result || widget.company.pk <= 0) { @@ -78,15 +79,16 @@ class _CompanyDetailState extends RefreshableState { Navigator.of(context).pop(); return; } - + if (widget.company.isSupplier) { - outstandingOrders = await widget.company.getPurchaseOrders(outstanding: true); + outstandingOrders = + await widget.company.getPurchaseOrders(outstanding: true); } InvenTreeSupplierPart().count( - filters: { - "supplier": widget.company.pk.toString() - } + filters: { + "supplier": widget.company.pk.toString() + } ).then((value) { if (mounted) { setState(() { @@ -94,6 +96,20 @@ class _CompanyDetailState extends RefreshableState { }); } }); + + if (api.supportCompanyAttachments) { + InvenTreeCompanyAttachment().count( + filters: { + "company": widget.company.pk.toString() + } + ).then((value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } } Future editCompany(BuildContext context) async { @@ -251,6 +267,26 @@ class _CompanyDetailState extends RefreshableState { )); } + if (api.supportCompanyAttachments) { + tiles.add(ListTile( + title: Text(L10().attachments), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeCompanyAttachment(), + widget.company.pk, + api.checkPermission("purchase_order", "change") || api.checkPermission("sales_order", "change") + ) + ) + ); + } + )); + } + return tiles; } diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 95e45ae..7adcc45 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -2,7 +2,6 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; @@ -51,7 +50,7 @@ class _LocationDisplayState extends RefreshableState { if (location != null) { // Add "locate" button - if (InvenTreeAPI().supportsMixin("locate")) { + if (api.supportsMixin("locate")) { actions.add( IconButton( icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), @@ -64,7 +63,7 @@ class _LocationDisplayState extends RefreshableState { } // Add "edit" button - if (InvenTreeAPI().checkPermission("stock_location", "change")) { + if (api.checkPermission("stock_location", "change")) { actions.add( IconButton( icon: FaIcon(FontAwesomeIcons.penToSquare), @@ -86,7 +85,7 @@ class _LocationDisplayState extends RefreshableState { final _loc = location; if (_loc != null) { - InvenTreeAPI().locateItemOrLocation(context, location: _loc.pk); + api.locateItemOrLocation(context, location: _loc.pk); } } @@ -372,7 +371,7 @@ class _LocationDisplayState extends RefreshableState { tiles.add(locationDescriptionCard(includeActions: false)); - if (InvenTreeAPI().checkPermission("stock", "add")) { + if (api.checkPermission("stock", "add")) { tiles.add( ListTile( @@ -403,7 +402,7 @@ class _LocationDisplayState extends RefreshableState { if (location != null) { // Scan stock item into location - if (InvenTreeAPI().checkPermission("stock", "change")) { + if (api.checkPermission("stock", "change")) { tiles.add( ListTile( title: Text(L10().barcodeScanItem), @@ -429,7 +428,7 @@ class _LocationDisplayState extends RefreshableState { ); // Scan this location into another one - if (InvenTreeAPI().checkPermission("stock_location", "change")) { + if (api.checkPermission("stock_location", "change")) { tiles.add( ListTile( title: Text(L10().transferStockLocation), @@ -454,7 +453,7 @@ class _LocationDisplayState extends RefreshableState { ); } - if (InvenTreeAPI().supportModernBarcodes) { + if (api.supportModernBarcodes) { tiles.add( customBarcodeActionTile(context, this, location!.customBarcode, "stocklocation", location!.pk) ); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 3ebab6d..b410a27 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -2,7 +2,6 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; @@ -73,7 +72,7 @@ class _PartDisplayState extends RefreshableState { List actions = []; - if (InvenTreeAPI().checkPermission("part", "view")) { + if (api.checkPermission("part", "view")) { actions.add( IconButton( icon: FaIcon(FontAwesomeIcons.globe), @@ -82,7 +81,7 @@ class _PartDisplayState extends RefreshableState { ); } - if (InvenTreeAPI().checkPermission("part", "change")) { + if (api.checkPermission("part", "change")) { actions.add( IconButton( icon: FaIcon(FontAwesomeIcons.penToSquare), @@ -144,7 +143,7 @@ class _PartDisplayState extends RefreshableState { }); // Request the number of parameters for this part - if (InvenTreeAPI().supportsPartParameters) { + if (api.supportsPartParameters) { showParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; @@ -222,7 +221,7 @@ class _PartDisplayState extends RefreshableState { */ Future _toggleStar(BuildContext context) async { - if (InvenTreeAPI().checkPermission("part", "view")) { + if (api.checkPermission("part", "view")) { showLoadingOverlay(context); await part.update(values: {"starred": "${!part.starred}"}); hideLoadingOverlay(); @@ -256,7 +255,7 @@ class _PartDisplayState extends RefreshableState { }, ), leading: GestureDetector( - child: InvenTreeAPI().getImage(part.thumbnail), + child: api.getImage(part.thumbnail), onTap: () { Navigator.push( context, @@ -316,7 +315,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().templatePart), subtitle: Text(parentPart!.fullname), - leading: InvenTreeAPI().getImage( + leading: api.getImage( parentPart!.thumbnail, width: 32, height: 32, @@ -589,7 +588,7 @@ class _PartDisplayState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreePartAttachment(), part.pk, - InvenTreeAPI().checkPermission("part", "change")) + api.checkPermission("part", "change")) ) ); }, @@ -646,7 +645,7 @@ class _PartDisplayState extends RefreshableState { if (part.isTrackable) { // read the next available serial number showLoadingOverlay(context); - var response = await InvenTreeAPI().get("/api/part/${part.pk}/serial-numbers/", expectedStatusCode: null); + var response = await api.get("/api/part/${part.pk}/serial-numbers/", expectedStatusCode: null); hideLoadingOverlay(); if (response.isValid() && response.statusCode == 200) { @@ -701,7 +700,7 @@ class _PartDisplayState extends RefreshableState { ) ); - if (InvenTreeAPI().supportModernBarcodes) { + if (api.supportModernBarcodes) { tiles.add( customBarcodeActionTile(context, this, part.customBarcode, "part", part.pk) ); diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 6a87dac..184d8b5 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -1,6 +1,9 @@ +import "package:flutter/material.dart"; + +import "package:inventree/api.dart"; + import "package:inventree/widget/back.dart"; import "package:inventree/widget/drawer.dart"; -import "package:flutter/material.dart"; /* @@ -62,6 +65,9 @@ abstract class RefreshableState extends State with bool get loaded => !loading; + // Helper function to return API instance + InvenTreeAPI get api => InvenTreeAPI(); + // Update current tab selection void onTabSelectionChanged(int index) { From 80b83b842d1a0a513349cb4a2d49c138aa1d5869 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 18 Feb 2023 08:13:59 +1100 Subject: [PATCH 300/746] New Crowdin updates (#262) * New translations app_en.arb (Italian) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/it_IT/app_it_IT.arb | 10 +++++ lib/l10n/zh_CN/app_zh_CN.arb | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 8812076..0efa0f8 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -319,6 +319,8 @@ "@invalidStockLocation": {}, "invalidStockItem": "Elemento di magazzino non valido", "@invalidStockItem": {}, + "invalidSupplierPart": "Fornitore Articolo Non Valido", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinazione nome utente e password non valida", "@invalidUsernamePassword": {}, "issueDate": "Data di emissione", @@ -753,6 +755,14 @@ "@suppliedParts": {}, "supplier": "Fornitore", "@supplier": {}, + "supplierPart": "Articolo Fornitore", + "@supplierPart": {}, + "supplierPartEdit": "Modifica Fornitore Articolo", + "@supplierPartEdit": {}, + "supplierPartUpdated": "Articolo Fornitore Aggiornato", + "@supplierPartUpdated": {}, + "supplierParts": "Articoli Fornitore", + "@supplierParts": {}, "suppliers": "Fornitori", "@suppliers": {}, "supplierReference": "Riferimento fornitore", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 2dcc160..630506c 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -246,16 +246,71 @@ "@filterVirtualDetail": {}, "filteringOptions": "过滤选项", "@filteringOptions": {}, + "formatException": "格式异常", + "@formatException": {}, + "formatExceptionJson": "JSON数据格式异常", + "@formatExceptionJson": {}, + "formError": "表单错误", + "@formError": {}, "history": "历史", "@history": { "description": "history" }, + "home": "主页", + "@homeScreen": {}, + "homeScreen": "主屏幕", + "homeScreenSettings": "配置主屏幕设置", + "@homeScreenSettings": {}, + "homeShowPo": "显示采购订单", + "@homeShowPo": {}, + "homeShowSubscribed": "订阅的商品", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "在主屏幕上显示订阅的商品", "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "在主屏幕上显示订单按钮", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "显示供应商", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "在主屏幕上显示供应商按钮", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "显示制造商", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "在主屏幕显示制造商按钮", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "显示顾客", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "在主屏幕上显示客户按钮", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "图片上传失败", + "@imageUploadFailure": {}, + "imageUploadSuccess": "图片上传", + "@imageUploadSuccess": {}, + "inactive": "非活跃的", + "@inactive": {}, + "inactiveDetail": "这一部分被标记为非活动部分", + "@inactiveDetail": {}, + "includeSubcategories": "包含子类别", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "显示子类别的结果", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "包括子地点", + "@includeSublocations": {}, + "includeSublocationsDetail": "显示子位置的结果", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完整的个人资料详细信息", + "@incompleteDetails": {}, "internalPartNumber": "内部部件号", "@internalPartNumber": {}, "info": "信息", "@info": {}, + "inProduction": "正在生产", + "@inProduction": {}, + "inProductionDetail": "库存品正在生产", + "@inProductionDetail": {}, + "invalidHost": "无效的主机名", + "@invalidHost": {}, + "invalidHostDetails": "提供的主机名无效", + "@invalidHostDetails": {}, "invalidPart": "无效部件", "@invalidPart": {}, "invalidPartCategory": "无效部件分类", @@ -264,8 +319,24 @@ "@invalidStockLocation": {}, "invalidStockItem": "无效库存项", "@invalidStockItem": {}, + "invalidSupplierPart": "无效的供应商部件", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "无效的用户名密码组合", + "@invalidUsernamePassword": {}, + "issueDate": "签发日期", + "@issueDate": {}, + "itemInLocation": "物品已就位", + "@itemInLocation": {}, "keywords": "关键词", "@keywords": {}, + "labelTemplate": "标签模板", + "@labelTemplate": {}, + "language": "语言", + "@language": {}, + "languageDefault": "系统默认语言", + "@languageDefault": {}, + "languageSelect": "选择语言", + "@languageSelect": {}, "link": "链接", "@link": {}, "lost": "丢失", From 113b3d69a9fce874a0a6cbe1dc50f6d897e7582c Mon Sep 17 00:00:00 2001 From: simonkuehling Date: Sun, 19 Feb 2023 11:07:47 +0100 Subject: [PATCH 301/746] skip SnackIcon banner when opening a view from successful barcode scan (#266) (#267) --- lib/barcode.dart | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/barcode.dart b/lib/barcode.dart index 77dbb40..3c77cd6 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -189,11 +189,6 @@ class BarcodeScanHandler extends BarcodeHandler { */ Future handlePart(int pk) async { InvenTreePart().get(pk).then((var part) { - showSnackIcon( - L10().part, - success: true, - icon: Icons.qr_code, - ); // Dismiss the barcode scanner OneContext().pop(); @@ -208,11 +203,6 @@ class BarcodeScanHandler extends BarcodeHandler { */ Future handleStockItem(int pk) async { InvenTreeStockItem().get(pk).then((var item) { - showSnackIcon( - L10().stockItem, - success: true, - icon: Icons.qr_code, - ); OneContext().pop(); if (item is InvenTreeStockItem) { OneContext().push(MaterialPageRoute( @@ -227,11 +217,6 @@ class BarcodeScanHandler extends BarcodeHandler { Future handleStockLocation(int pk) async { InvenTreeStockLocation().get(pk).then((var loc) { if (loc is InvenTreeStockLocation) { - showSnackIcon( - L10().stockLocation, - success: true, - icon: Icons.qr_code, - ); OneContext().pop(); OneContext().navigator.push(MaterialPageRoute( builder: (context) => LocationDisplayWidget(loc))); @@ -244,12 +229,6 @@ class BarcodeScanHandler extends BarcodeHandler { */ Future handleSupplierPart(int pk) async { InvenTreeSupplierPart().get(pk).then((var supplierpart) { - showSnackIcon( - L10().supplierPart, - success: true, - icon: Icons.qr_code, - ); - OneContext().pop(); if (supplierpart is InvenTreeSupplierPart) { From 5c06e3c9de489afa62a4a0e9d44ad25f3f10b2e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 19 Feb 2023 21:08:02 +1100 Subject: [PATCH 302/746] Update credits.md (#268) Add simonkuehling as contributor --- assets/credits.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/credits.md b/assets/credits.md index bbc9c52..6546b18 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -5,6 +5,7 @@ Thanks to the following contributors, for their work building this app! - [SchrodingersGat](https://github.com/SchrodingersGat) (*Lead Developer*) - [Guusggg](https://github.com/Guusggg) - [GoryMoon](https://github.com/GoryMoon) +- [simonkuehling](https://github.com/simonkuehling) -------- @@ -20,4 +21,4 @@ Icons are provided by [fontawesome](fontawesome.com) Sound files have been sourced from [https://www.zapsplat.com](https://www.zapsplat.com) --------- \ No newline at end of file +-------- From fb80029c0ee60b1eef533a51e6fa47c2d4220728 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 22 Feb 2023 00:52:26 +1100 Subject: [PATCH 303/746] Barcode camera fix (#270) * Bug fix for multiple barcode scans - Do not resume scan until action is performed - Add in delay before re-starting camera * Change release notes to 0.10.1 * linting fixes --- assets/release_notes.md | 3 +- lib/barcode.dart | 146 +++++++++++++++++++++++----------------- 2 files changed, 88 insertions(+), 61 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3e6cee7..97fe1c2 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,10 +1,11 @@ ## InvenTree App Release Notes --- -### 0.11.0 - +### 0.10.1 - February 2023 --- - Add support for attachments on Companies +- Fix duplicate scanning of barcodes ### 0.10.0 - February 2023 --- diff --git a/lib/barcode.dart b/lib/barcode.dart index 3c77cd6..a030631 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -58,8 +58,6 @@ class BarcodeHandler { String getOverlayText(BuildContext context) => "Barcode Overlay"; - QRViewController? _controller; - Future onBarcodeMatched(Map data) async { // Called when the server "matches" a barcode // Override this function @@ -78,21 +76,18 @@ class BarcodeHandler { ); } - Future onBarcodeUnhandled(Map data) async { - + // Called when the server returns an unhandled response + Future onBarcodeUnhandled(Map data) async { barcodeFailureTone(); - - // Called when the server returns an unhandled response showServerError("barcode/", L10().responseUnknown, data.toString()); - - _controller?.resumeCamera(); } /* * Base function to capture and process barcode data. + * + * Returns true only if the barcode scanner should remain open */ Future processBarcode(QRViewController? _controller, String barcode, {String url = "barcode/"}) async { - this._controller = _controller; debug("Scanned barcode data: '${barcode}'"); @@ -122,8 +117,6 @@ class BarcodeHandler { debug("Barcode scan response" + response.data.toString()); - _controller?.resumeCamera(); - Map data = response.asMap(); // Handle strange response from the server @@ -188,53 +181,55 @@ class BarcodeScanHandler extends BarcodeHandler { * Response when a "Part" instance is scanned */ Future handlePart(int pk) async { - InvenTreePart().get(pk).then((var part) { - // Dismiss the barcode scanner - OneContext().pop(); - if (part is InvenTreePart) { - OneContext().push(MaterialPageRoute(builder: (context) => PartDetailWidget(part))); - } - }); + var part = await InvenTreePart().get(pk); + + if (part is InvenTreePart) { + OneContext().pop(); + OneContext().push(MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + } } /* * Response when a "StockItem" instance is scanned */ Future handleStockItem(int pk) async { - InvenTreeStockItem().get(pk).then((var item) { + + var item = await InvenTreeStockItem().get(pk); + + if (item is InvenTreeStockItem) { OneContext().pop(); - if (item is InvenTreeStockItem) { - OneContext().push(MaterialPageRoute( + OneContext().push(MaterialPageRoute( builder: (context) => StockDetailWidget(item))); - } - }); + } } /* * Response when a "StockLocation" instance is scanned */ Future handleStockLocation(int pk) async { - InvenTreeStockLocation().get(pk).then((var loc) { - if (loc is InvenTreeStockLocation) { - OneContext().pop(); - OneContext().navigator.push(MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc))); - } - }); + + var loc = await InvenTreeStockLocation().get(pk); + + if (loc is InvenTreeStockLocation) { + OneContext().pop(); + OneContext().navigator.push(MaterialPageRoute( + builder: (context) => LocationDisplayWidget(loc))); + } } /* * Response when a "SupplierPart" instance is scanned */ Future handleSupplierPart(int pk) async { - InvenTreeSupplierPart().get(pk).then((var supplierpart) { - OneContext().pop(); - if (supplierpart is InvenTreeSupplierPart) { - OneContext().push(MaterialPageRoute(builder: (context) => SupplierPartDetailWidget(supplierpart))); - } - }); + var supplierpart = await InvenTreeSupplierPart().get(pk); + + if (supplierpart is InvenTreeSupplierPart) { + OneContext().pop(); + OneContext().push(MaterialPageRoute( + builder: (context) => SupplierPartDetailWidget(supplierpart))); + } } @override @@ -270,19 +265,19 @@ class BarcodeScanHandler extends BarcodeHandler { switch (model) { case "part": - handlePart(pk); + await handlePart(pk); return; case "stockitem": - handleStockItem(pk); + await handleStockItem(pk); return; case "stocklocation": - handleStockLocation(pk); + await handleStockLocation(pk); return; case "supplierpart": - handleSupplierPart(pk); + await handleSupplierPart(pk); return; default: - // Fall through to failure state + // Fall through to failure state break; } } @@ -339,9 +334,8 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { if (result && OneContext.hasContext) { OneContext().pop(); + return; } - - return; } } @@ -386,13 +380,12 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { barcodeSuccessTone(); - final bool result = await onItemScanned(_item); + bool result = await onItemScanned(_item); if (result && OneContext.hasContext) { OneContext().pop(); + return; } - - return; } } @@ -410,7 +403,6 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { // Re-implement this for particular subclass return false; } - } @@ -480,10 +472,10 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { } } - showSnackIcon( - result ? L10().barcodeScanIntoLocationSuccess : L10().barcodeScanIntoLocationFailure, - success: result - ); + showSnackIcon( + result ? L10().barcodeScanIntoLocationSuccess : L10().barcodeScanIntoLocationFailure, + success: result + ); // We always return false here, to ensure the barcode scan dialog remains open return false; @@ -641,6 +633,8 @@ class _QRViewState extends State { bool flash_status = false; + bool currently_processing = false; + Future updateFlashStatus() async { final bool? status = await _controller?.getFlashStatus(); @@ -658,21 +652,53 @@ class _QRViewState extends State { void reassemble() { super.reassemble(); - if (Platform.isAndroid) { - _controller!.pauseCamera(); - } + if (mounted) { + if (Platform.isAndroid) { + _controller!.pauseCamera(); + } - _controller!.resumeCamera(); + _controller!.resumeCamera(); + } } + /* Callback function when the Barcode scanner view is initially created */ void _onViewCreated(BuildContext context, QRViewController controller) { _controller = controller; - controller.scannedDataStream.listen((barcode) { - _controller?.pauseCamera(); - if (barcode.code != null) { - widget._handler.processBarcode(_controller, barcode.code ?? ""); - } + controller.scannedDataStream.listen((barcode) { + handleBarcode(barcode.code); + }); + } + + /* Handle scanned data */ + Future handleBarcode(String? data) async { + + // Empty or missing data, or we have navigated away + if (!mounted || data == null || data.isEmpty) { + return; + } + + // Currently processing a barcode - return! + if (currently_processing) { + return; + } + + setState(() { + currently_processing = true; + }); + + // Pause camera functionality until we are done processing + _controller?.pauseCamera(); + + // processBarcode returns true if the scanner window is to remain open + widget._handler.processBarcode(_controller, data).then((value) { + // Re-start the process after some delay + Future.delayed(Duration(milliseconds: 500)).then((value) { + if (mounted) { + _controller?.resumeCamera(); + currently_processing = false; + } + }); }); } From 4b8ab304aa878648895d06f04f1e1526c8ba22bc Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 26 Feb 2023 22:08:58 +1100 Subject: [PATCH 304/746] New translations app_en.arb (Portuguese, Brazilian) (#271) --- lib/l10n/pt_BR/app_pt_BR.arb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 9db9b72..040b33c 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -389,6 +389,8 @@ "@packaging": {}, "packageName": "Nome do pacote", "@packageName": {}, + "parameters": "Parâmetros", + "@parameters": {}, "parent": "Pai", "@parent": {}, "parentCategory": "Categoria pai", @@ -423,6 +425,18 @@ "@partCategory": {}, "partCategoryTopLevel": "Categoria de peça de nível superior", "@partCategoryTopLevel": {}, + "password": "Senha", + "@password": {}, + "passwordEmpty": "A senha não pode estar em branco", + "@passwordEmpty": {}, + "permissionAccountDenied": "Sua conta não possui as permissões necessárias para realizar esta ação", + "@permissionAccountDenied": {}, + "permissionRequired": "Permissão Necessária", + "@permissionRequired": {}, + "profile": "Perfil", + "@profile": {}, + "purchaseOrder": "Ordem de Compra", + "@purchaseOrder": {}, "purchaseOrderEdit": "Editar ordem de compra", "@purchaseOrderEdit": {}, "purchaseOrders": "Ordens de compras", @@ -453,6 +467,8 @@ "@receiveItem": {}, "receivedItem": "Item de estoque recebido", "@receivedItem": {}, + "reference": "Referência", + "@reference": {}, "refresh": "Atualizar", "@refresh": {}, "refreshing": "Atualizando", @@ -537,6 +553,20 @@ }, "searching": "Buscando", "@searching": {}, + "select": "Selecionar", + "@select": {}, + "selectFile": "Selecionar Arquivo", + "@selectFile": {}, + "selectImage": "Selecionar Imagem", + "@selectImage": {}, + "selectLocation": "Selecionar um local", + "@selectLocation": {}, + "send": "Enviar", + "@send": {}, + "server": "Servidor", + "@server": {}, + "serverAddress": "Endereço do servidor", + "@serverAddress": {}, "serverError": "Erro de servidor", "@serverError": {}, "serverDetails": "Detalhes do servidor", From c8dedf2a0e09c9cbb9ce81d38c0d0acd2721ee5d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 26 Feb 2023 22:17:04 +1100 Subject: [PATCH 305/746] Bump version number to 0.10.1 (#272) --- assets/release_notes.md | 1 + pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 97fe1c2..ba2a926 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Add support for attachments on Companies - Fix duplicate scanning of barcodes +- Updated translations ### 0.10.0 - February 2023 --- diff --git a/pubspec.yaml b/pubspec.yaml index 4d2f8ac..01665da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.10.0+54 +version: 0.10.1+55 environment: sdk: ">=2.16.0 <3.0.0" From 84f7e90569250a6f297bdad10701a97248361ddd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Feb 2023 21:01:17 +1100 Subject: [PATCH 306/746] Fix icon on SupplierPartDetail widget (#273) * Fix icon on SupplierPartDetail widget * Update release notes --- assets/release_notes.md | 6 ++++++ lib/widget/supplier_part_detail.dart | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ba2a926..ac2747f 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,12 @@ ## InvenTree App Release Notes --- +### 0.10.2 - March 2023 +--- + +- Fix icon for supplier part detail widget + + ### 0.10.1 - February 2023 --- diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index fdccbf7..a295658 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -225,7 +225,7 @@ class _SupplierPartDisplayState extends RefreshableState Date: Mon, 27 Feb 2023 21:13:26 +1100 Subject: [PATCH 307/746] Update for credits display (#274) - Cleaner display - Links are now clickable --- assets/credits.md | 9 ++------- lib/settings/release.dart | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/assets/credits.md b/assets/credits.md index 6546b18..401c357 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -13,12 +13,7 @@ Thanks to the following contributors, for their work building this app! The InvenTree App makes use of the following third party assets -### Icons - -Icons are provided by [fontawesome](fontawesome.com) - -### Sound Files - -Sound files have been sourced from [https://www.zapsplat.com](https://www.zapsplat.com) +- Icons are provided by [fontawesome](https://fontawesome.com) +- Sound files have been sourced from [zapsplat](https://www.zapsplat.com) -------- diff --git a/lib/settings/release.dart b/lib/settings/release.dart index b04b1eb..728a762 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_markdown/flutter_markdown.dart"; import "package:inventree/l10.dart"; +import "package:url_launcher/url_launcher.dart"; class ReleaseNotesWidget extends StatelessWidget { @@ -30,6 +31,18 @@ class CreditsWidget extends StatelessWidget { final String credits; + /* + * Callback function when a link is clicked in the markdown + */ + Future openLink(String url) async { + + final link = Uri.parse(url); + + if (await canLaunchUrl(link)) { + await launchUrl(link); + } + } + @override Widget build (BuildContext context) { return Scaffold( @@ -38,7 +51,13 @@ class CreditsWidget extends StatelessWidget { ), body: Markdown( selectable: false, - data: credits + data: credits, + onTapLink: (url, href, title) { + var link = href ?? ""; + if (link.isNotEmpty) { + openLink(link); + } + }, ) ); } From 10ae5e47ba988e5cae623e2a1e0b98d09bc1486c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Feb 2023 21:18:48 +1100 Subject: [PATCH 308/746] Update version number to 0.10.2 (#275) --- assets/release_notes.md | 1 - pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ac2747f..61a1b2b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,7 +6,6 @@ - Fix icon for supplier part detail widget - ### 0.10.1 - February 2023 --- diff --git a/pubspec.yaml b/pubspec.yaml index 01665da..ba97079 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.10.1+55 +version: 0.10.2+56 environment: sdk: ">=2.16.0 <3.0.0" From 221920cbbed6c4da7660d9b54bdc7e7232c2cd05 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 3 Mar 2023 18:57:52 +1100 Subject: [PATCH 309/746] New Crowdin updates (#276) * New translations app_en.arb (Czech) * New translations app_en.arb (Czech) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 384 +++++++++++++++++++++++++++++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 124 +++++++++-- 2 files changed, 494 insertions(+), 14 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index fc74a9d..77e2977 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -72,14 +72,26 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Naskenuj čárový kód InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanLocation": "Skenovat skladové místo", + "@barcodeScanLocation": {}, + "barcodeScanItem": "Skenovat skladovou položku", + "@barcodeScanItem": {}, "barcodeUnknown": "Čárkový kód nebyl rozpoznán", "@barcodeUnknown": {}, + "batchCode": "Kód šarže", + "@batchCode": {}, "billOfMaterials": "Kusovník", "@billOfMaterials": {}, "bom": "Kusovník", "@bom": {}, "bomEnable": "Zobrazit kusovník", "@bomEnable": {}, + "build": "Sestava", + "@build": {}, + "building": "Sestavení", + "@building": {}, "cancel": "Zrušit", "@cancel": { "description": "Cancel" @@ -88,12 +100,38 @@ "@category": {}, "categoryCreate": "Nová kategorie", "@categoryCreate": {}, + "categoryCreateDetail": "Vytvořit novou kategorii dílů", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategorie dílu byla aktualizována", + "@categoryUpdated": {}, + "company": "Společnost", + "@company": {}, + "companyEdit": "Editovat společnost", + "@companyEdit": {}, + "companyNoResults": "Žádné společnosti neodpovídají dotazu", + "@companyNoResults": {}, + "companyUpdated": "Údaje společnosti byly aktualizovány", + "@companyUpdated": {}, "companies": "Společnosti", "@companies": {}, + "configureServer": "Konfigurace nastavení serveru", + "@configureServer": {}, + "connectionRefused": "Spojení selhalo", + "@connectionRefused": {}, "count": "Počet", "@count": { "description": "Count" }, + "countStock": "Počet zásob", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Poděkování", + "@credits": {}, + "customers": "Zákazníci", + "@customers": {}, + "damaged": "Poškozeno", + "@damaged": {}, "delete": "Odstranit", "@delete": {}, "deleteFailed": "Odstranění se nezdařilo", @@ -102,6 +140,22 @@ "@deletePart": {}, "deletePartDetail": "Odstranit tento díl z databáze", "@deletePartDetail": {}, + "deleteSuccess": "Odstránění bylo úspěšné", + "@deleteSuccess": {}, + "description": "Popis", + "@description": {}, + "destroyed": "Zničeno", + "@destroyed": {}, + "details": "Detaily", + "@details": { + "description": "details" + }, + "documentation": "Dokumentace", + "@documentation": {}, + "downloading": "Stahování souboru", + "@downloading": {}, + "downloadError": "Chyba při stahování", + "@downloadError": {}, "edit": "Upravit", "@edit": { "description": "edit" @@ -116,6 +170,8 @@ "@editPart": { "description": "edit part" }, + "editItem": "Upravit skladovou položku", + "@editItem": {}, "enterPassword": "Zadejte heslo", "@enterPassword": {}, "enterUsername": "Zadejte uživatelské jméno", @@ -154,6 +210,8 @@ "@filterAssemblyDetail": {}, "filterComponent": "Součást", "@filterComponent": {}, + "filterComponentDetail": "Zobrazit díly komponentu", + "@filterComponentDetail": {}, "filterInStock": "Na skladě", "@filterInStock": {}, "filterInStockDetail": "Zobrazit díly, které jsou skladem", @@ -217,8 +275,124 @@ "@imageUploadSuccess": {}, "inactive": "Neaktivní", "@inactive": {}, + "inactiveDetail": "Tato část je označena jako neaktivní", + "@inactiveDetail": {}, + "includeSubcategories": "Zahrnout podkategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Zobrazit výsledky z podkategorie", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Zahrnout podumístění", + "@includeSublocations": {}, + "includeSublocationsDetail": "Zobrazit výsledky z podumístění", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Neúplné údaje o profilu", + "@incompleteDetails": {}, "internalPartNumber": "Interní číslo dílu", "@internalPartNumber": {}, + "info": "Informace", + "@info": {}, + "inProduction": "Ve výrobě", + "@inProduction": {}, + "inProductionDetail": "Tato skladová položka je ve výrobě", + "@inProductionDetail": {}, + "invalidHost": "Neplatný název hostitele", + "@invalidHost": {}, + "invalidHostDetails": "Zadaný název hostitele není platný", + "@invalidHostDetails": {}, + "invalidPart": "Neplatný díl", + "@invalidPart": {}, + "invalidPartCategory": "Neplatná kategorie dílu", + "@invalidPartCategory": {}, + "invalidStockLocation": "Neplatné skladové místo", + "@invalidStockLocation": {}, + "invalidStockItem": "Neplatná skladová položka", + "@invalidStockItem": {}, + "invalidSupplierPart": "Neplatný díl dodavatel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Neplatné uživatelské jméno nebo heslo.", + "@invalidUsernamePassword": {}, + "issueDate": "Datum nahlášení", + "@issueDate": {}, + "itemInLocation": "Položka je již umístěna", + "@itemInLocation": {}, + "keywords": "Klíčová slova", + "@keywords": {}, + "labelTemplate": "Šablona štítku", + "@labelTemplate": {}, + "language": "Jazyk", + "@language": {}, + "languageDefault": "Výchozí jazyk systému", + "@languageDefault": {}, + "languageSelect": "Vybrat jazyk", + "@languageSelect": {}, + "lastStocktake": "Poslední inventura", + "@lastStocktake": {}, + "lastUpdated": "Poslední aktualizace", + "@lastUpdated": {}, + "level": "Úroveň", + "@level": {}, + "lineItem": "Řádek položky", + "@lineItem": {}, + "locateItem": "Najít skladovou položku", + "@locateItem": {}, + "locateLocation": "Najít skladové umístění", + "@locateLocation": {}, + "locationCreate": "Nové umístění", + "@locationCreate": {}, + "locationCreateDetail": "Vytvořit nové skladové místo", + "@locationCreateDetail": {}, + "locationNotSet": "Není zadáno žádné umístění", + "@locationNotSet": {}, + "locationUpdated": "Skladové místo bylo aktualizováno", + "@locationUpdated": {}, + "link": "Odkaz", + "@link": {}, + "lost": "Ztraceno", + "@lost": {}, + "manufacturers": "Výrobci", + "@manufacturers": {}, + "missingData": "Chybějící data", + "@missingData": {}, + "name": "Jméno", + "@name": {}, + "notConnected": "Nepřipojeno", + "@notConnected": {}, + "notes": "Poznámky", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifikace", + "@notifications": {}, + "notificationsEmpty": "Žádná nepřečtená oznámení", + "@notificationsEmpty": {}, + "noResponse": "Žádná odpověď serveru", + "@noResponse": {}, + "noResults": "Žádné výsledky", + "@noResults": {}, + "noSubcategories": "Žádná podkategorie", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Žádné podkategorie nejsou k dispozici", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Neplatné číslo", + "@numberInvalid": {}, + "onOrder": "Na objednávku", + "@onOrder": {}, + "onOrderDetails": "Položky momentálně v objednávce", + "@onOrderDetails": {}, + "packaging": "Balení", + "@packaging": {}, + "packageName": "Název balíčku", + "@packageName": {}, + "parameters": "Paramtery", + "@parameters": {}, + "parametersSettingDetail": "Zobrazit parametry", + "@parametersSettingDetail": {}, + "parent": "Nadřazený", + "@parent": {}, + "parentCategory": "Nadřazená kategorie", + "@parentCategory": {}, + "parentLocation": "Nadřazená místo", + "@parentLocation": {}, "part": "Díl", "@part": { "description": "Part (single)" @@ -319,6 +493,96 @@ }, "quantityAvailable": "Dostupné množství", "@quantityAvailable": {}, + "quantityEmpty": "Množství je prázdné", + "@quantityEmpty": {}, + "quantityInvalid": "Množství je neplatné", + "@quantityInvalid": {}, + "quantityPositive": "Množství musí být kladné.", + "@quantityPositive": {}, + "quarantined": "V karanténě", + "@quarantined": {}, + "queryEmpty": "Zadejte hledaný dotaz", + "@queryEmpty": {}, + "queryNoResults": "Žádné výsledky dotazu", + "@queryNoResults": {}, + "received": "Přijato", + "@received": {}, + "receiveItem": "Přijaté položky", + "@receiveItem": {}, + "receivedItem": "Přijatá skladová položka", + "@receivedItem": {}, + "refresh": "Obnovit", + "@refresh": {}, + "refreshing": "Obnovuji…", + "@refreshing": {}, + "rejected": "Zamítnuto", + "@rejected": {}, + "releaseNotes": "Poznámky k vydání", + "@releaseNotes": {}, + "remove": "Odstranit", + "@remove": { + "description": "remove" + }, + "removeStock": "Odstranit sklad", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Nahlásit chybu", + "@reportBug": {}, + "reportBugDescription": "Odeslat hlášení o chybě (vyžaduje GitHub účet)", + "@reportBugDescription": {}, + "results": "Výsledky", + "@results": {}, + "request": "Požadavek", + "@request": {}, + "requestFailed": "Požadavek selhal", + "@requestFailed": {}, + "requestSuccessful": "Požadavek byl úspěšný", + "@requestSuccessful": {}, + "requestingData": "Požadavek na data", + "@requestingData": {}, + "required": "Povinné", + "@required": { + "description": "This field is required" + }, + "response400": "Chybný požadavek", + "@response400": {}, + "response401": "Neoprávněný", + "@response401": {}, + "response403": "Přístup odepřen", + "@response403": {}, + "response404": "Zdroj nebyl nalezen", + "@response404": {}, + "response405": "Metoda není povolena", + "@response405": {}, + "response429": "Příliš mnoho požadavků", + "@response429": {}, + "response500": "Interní chyba serveru", + "@response500": {}, + "response501": "Není implementováno", + "@response501": {}, + "response503": "Služba nedostupná", + "@response503": {}, + "response505": "HTTP verze není podporována", + "@response505": {}, + "responseUnknown": "Neznámá odpověď", + "@responseUnknown": {}, + "result": "Výsledek", + "@result": { + "description": "" + }, + "returned": "Vráceno", + "@returned": {}, + "salesOrders": "Prodejní objednávky", + "@salesOrders": {}, + "save": "Uložit", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skenovat čarový kód", + "@scanBarcode": {}, + "scanIntoLocation": "Skenovat umístění", + "@scanIntoLocation": {}, "search": "Hledat", "@search": { "description": "search" @@ -395,6 +659,126 @@ "@status": {}, "statusCode": "Stavový kód", "@statusCode": {}, + "stock": "Sklad", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktuální dostupné množství na skladě", + "@stockDetails": {}, + "stockItem": "Skladová položka", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Skladové položky", + "@stockItems": {}, + "stockItemCreate": "Nová skladová položka", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Vytvořit novou skladovou položku na tomto místě", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Odstranit skladovou položku", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Opravdu chcete odstranit tuto skladovou položku?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Nelze odstranit skladovou položku", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Skladová položka odstraněna", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Historie skladu", + "@stockItemHistory": {}, + "stockItemTransferred": "Skladová položka převedena", + "@stockItemTransferred": {}, + "stockItemUpdated": "Skladová položka upravena", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Žádné skladové položky k dispozici", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Poznámky skladové položky", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Skladová položka upravena", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Úprava skladové položky se nezdařila", + "@stockItemUpdateFailure": {}, + "stockLocation": "Skladové místo", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Skladová místa", + "@stockLocations": {}, + "subcategory": "Podkategorie", + "@subcategory": {}, + "subcategories": "Podkategorie", + "@subcategories": {}, + "sublocation": "Podumístění", + "@sublocation": {}, + "sublocations": "Podumístění", + "@sublocations": {}, + "sublocationNone": "Žádné podumístění", + "@sublocationNone": {}, + "sublocationNoneDetail": "Žádné podumístění k dispozici", + "@sublocationNoneDetail": {}, + "submitFeedback": "Odeslat zpětnou vazbu", + "@submitFeedback": {}, + "suppliedParts": "Dodané díly", + "@suppliedParts": {}, + "supplier": "Dodavatel", + "@supplier": {}, + "supplierPart": "Dodavatel dílu", + "@supplierPart": {}, + "supplierPartEdit": "Upravit dodavatele dílu", + "@supplierPartEdit": {}, + "supplierPartUpdated": "Dodavatel dílu upraven", + "@supplierPartUpdated": {}, + "supplierParts": "Dodavatel dílů", + "@supplierParts": {}, + "suppliers": "Dodavatelé", + "@suppliers": {}, + "supplierReference": "Kód dodavatele", + "@supplierReference": {}, + "takePicture": "Pořídit snímek", + "@takePicture": {}, + "targetDate": "Cílové datum", + "@targetDate": {}, + "testName": "Název testu", + "@testName": {}, + "testsRequired": "Požadované testy", + "@testsRequired": {}, + "testResults": "Výsledky testu", + "@testResults": { + "description": "" + }, + "testResultAdd": "Přidat výsledek testu", + "@testResultAdd": {}, + "testResultNone": "Žádné výsledky testu", + "@testResultNone": {}, + "testResultNoneDetail": "Žádné výsledky testu nejsou k dispozici", + "@testResultNoneDetail": {}, + "testResultUploadPass": "Výsledek testu nahrán", + "@testResultUploadPass": {}, + "timeout": "Časový limit", + "@timeout": { + "description": "" + }, + "tokenError": "Chyba tokenu", + "@tokenError": {}, + "tokenMissing": "Chybějící token", + "@tokenMissing": {}, + "transfer": "Převod", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Převod zásob", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Přenos položky na jiné místo", + "@transferStockDetail": {}, + "transferStockLocation": "Převod skladového místa", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Převod tohoto umístění skladu do jiného", + "@transferStockLocationDetail": {}, + "translate": "Přeložit", + "@translate": {}, + "translateHelp": "Pomozte přeložit aplikaci InvenTree", + "@translateHelp": {}, "units": "Jednotky", "@units": {}, "unknownResponse": "Neznámá odpověď", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 040b33c..5ebdf61 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -76,7 +76,7 @@ "@barcodeScanAssign": {}, "barcodeScanGeneral": "Scanear um Cod Bar InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Busca de itens de estoque para este local", + "barcodeScanInItems": "Digitalizar itens de estoque neste local", "@barcodeScanInItems": {}, "barcodeScanLocation": "Scanear localizacao do stock", "@barcodeScanLocation": {}, @@ -98,6 +98,8 @@ "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, + "bomEnable": "Mostrar Lista de Materiais", + "@bomEnable": {}, "build": "Construcao", "@build": {}, "building": "Construindo", @@ -116,7 +118,7 @@ "@categoryUpdated": {}, "company": "Companhia", "@company": {}, - "companyEdit": "Editar empresa", + "companyEdit": "Editar Empresa", "@companyEdit": {}, "companyNoResults": "Nenhuma empresa corresponde a essa consulta", "@companyNoResults": {}, @@ -144,10 +146,14 @@ "@damaged": {}, "delete": "Deletar", "@delete": {}, + "deleteFailed": "A operação de apagar falhou", + "@deleteFailed": {}, "deletePart": "Deletar Parte", "@deletePart": {}, "deletePartDetail": "Remova essa parte do banco de dados", "@deletePartDetail": {}, + "deleteSuccess": "Apagado com Sucesso", + "@deleteSuccess": {}, "description": "Descrição", "@description": {}, "destroyed": "Destruído", @@ -238,9 +244,9 @@ "@filterVirtual": {}, "filterVirtualDetail": "Mostrar peças virtuais", "@filterVirtualDetail": {}, - "filteringOptions": "Opções de filtragem", + "filteringOptions": "Opções de filtros", "@filteringOptions": {}, - "formatException": "Formatar exceção", + "formatException": "Exceção de Formato", "@formatException": {}, "formatExceptionJson": "Exceção de formato de dados JSON", "@formatExceptionJson": {}, @@ -285,11 +291,11 @@ "@inactiveDetail": {}, "includeSubcategories": "Incluir sub-categorias", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Mostrar resultados de subcategorias", + "includeSubcategoriesDetail": "Mostrar resultados das subcategorias", "@includeSubcategoriesDetail": {}, "includeSublocations": "Incuir Sub-Locacoes", "@includeSublocations": {}, - "includeSublocationsDetail": "Mostrar resultados de sublocais", + "includeSublocationsDetail": "Mostrar resultados dos sublocais", "@includeSublocationsDetail": {}, "incompleteDetails": "Detalhes incompletos", "@incompleteDetails": {}, @@ -313,6 +319,8 @@ "@invalidStockLocation": {}, "invalidStockItem": "Item de estoque invalido", "@invalidStockItem": {}, + "invalidSupplierPart": "Fornecedor de Peça Inválido", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Usuario ou senha invalidos", "@invalidUsernamePassword": {}, "issueDate": "Data de emissao", @@ -327,7 +335,7 @@ "@language": {}, "languageDefault": "Idioma padrão do sistema", "@languageDefault": {}, - "languageSelect": "Selecionar idioma", + "languageSelect": "Selecionar Idioma", "@languageSelect": {}, "lastStocktake": "Ultimo dado de estoque", "@lastStocktake": {}, @@ -383,7 +391,7 @@ "@numberInvalid": {}, "onOrder": "Pedido já colocado", "@onOrder": {}, - "onOrderDetails": "Itens atualmente em ordem", + "onOrderDetails": "Itens atualmente com pedidos feitos", "@onOrderDetails": {}, "packaging": "Embalagem", "@packaging": {}, @@ -391,11 +399,13 @@ "@packageName": {}, "parameters": "Parâmetros", "@parameters": {}, - "parent": "Pai", + "parametersSettingDetail": "Mostrar Parâmetros da Peça", + "@parametersSettingDetail": {}, + "parent": "Parental", "@parent": {}, - "parentCategory": "Categoria pai", + "parentCategory": "Categoria Parental", "@parentCategory": {}, - "parentLocation": "Localização pai", + "parentLocation": "Localização Parental", "@parentLocation": {}, "part": "Peça", "@part": { @@ -403,7 +413,7 @@ }, "partCreate": "Nova peça", "@partCreate": {}, - "partCreateDetail": "Criar uma nova peça nessa categoria", + "partCreateDetail": "Criar uma peça nesta categoria", "@partCreateDetail": {}, "partEdited": "Peça atualizada", "@partEdited": {}, @@ -413,8 +423,10 @@ }, "partsNone": "Sem peças", "@partsNone": {}, - "partNoResults": "Nenhuma peça corresponde a essa consulta", + "partNoResults": "Nenhuma peça corresponde a consulta", "@partNoResults": {}, + "partSettings": "Configurações de Peça", + "@partSettings": {}, "partsStarred": "Peças subscritas", "@partsStarred": {}, "partsStarredNone": "Nenhuma peça com estrela disponível", @@ -423,8 +435,18 @@ "@partSuppliers": {}, "partCategory": "Categoria da peça", "@partCategory": {}, - "partCategoryTopLevel": "Categoria de peça de nível superior", + "partCategoryTopLevel": "Categoria da peça superior", "@partCategoryTopLevel": {}, + "partCategories": "Categorias da Peça", + "@partCategories": {}, + "partDetails": "Detalhes da Peça", + "@partDetails": {}, + "partNotes": "Notas de Peça", + "@partNotes": {}, + "partStock": "Estoque da Peça", + "@partStock": { + "description": "part stock" + }, "password": "Senha", "@password": {}, "passwordEmpty": "A senha não pode estar em branco", @@ -433,8 +455,42 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permissão Necessária", "@permissionRequired": {}, + "printLabel": "Imprimir Etiqueta", + "@printLabel": {}, + "plugin": "Extensões", + "@plugin": {}, + "pluginPrinter": "Impressora", + "@pluginPrinter": {}, + "pluginSupport": "Suporte à Extensões Habilitado", + "@pluginSupport": {}, + "pluginSupportDetail": "O servidor suporta extensões personalizadas", + "@pluginSupportDetail": {}, + "printLabelFailure": "Impressão de Etiqueta Falhou", + "@printLabelFailure": {}, + "printLabelSuccess": "Etiqueta Enviado à Impressora", + "@printLabelSuccess": {}, "profile": "Perfil", "@profile": {}, + "profileAdd": "Adicionar Perfil do Servidor", + "@profileAdd": {}, + "profileConnect": "Conectar a um Servidor", + "@profileConnect": {}, + "profileEdit": "Editar perfil do Servidor", + "@profileEdit": {}, + "profileDelete": "Apagar perfil do Servidor", + "@profileDelete": {}, + "profileName": "Nome do Perfil", + "@profileName": {}, + "profileNone": "Nenhum perfil disponível", + "@profileNone": {}, + "profileNotSelected": "Nenhum perfil selecionado", + "@profileNotSelected": {}, + "profileSelect": "Selecione um servidor InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Selecione o servidor ou crie um perfil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Clique para criar ou selecionar o perfil", + "@profileTapToCreate": {}, "purchaseOrder": "Ordem de Compra", "@purchaseOrder": {}, "purchaseOrderEdit": "Editar ordem de compra", @@ -449,6 +505,8 @@ "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Quantidade Disponível", + "@quantityAvailable": {}, "quantityEmpty": "Quantidade esta em branco", "@quantityEmpty": {}, "quantityInvalid": "Quantidade invalida", @@ -493,6 +551,8 @@ "@results": {}, "request": "Pedido", "@request": {}, + "requestFailed": "Ops! Falha na solicitação", + "@requestFailed": {}, "requestSuccessful": "Pedido recebido com sucesso", "@requestSuccessful": {}, "requestingData": "Requisitando dados", @@ -547,12 +607,20 @@ "@scanBarcode": {}, "scanIntoLocation": "Scan para localizacao", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Digitalize este item no local", + "@scanIntoLocationDetail": {}, "search": "Buscar", "@search": { "description": "search" }, "searching": "Buscando", "@searching": {}, + "searchLocation": "Procurar um Local", + "@searchLocation": {}, + "searchParts": "Procurar uma Peça", + "@searchParts": {}, + "searchStock": "Procurar o Estoque", + "@searchStock": {}, "select": "Selecionar", "@select": {}, "selectFile": "Selecionar Arquivo", @@ -563,10 +631,30 @@ "@selectLocation": {}, "send": "Enviar", "@send": {}, + "serialNumber": "Número de Série", + "@serialNumber": {}, "server": "Servidor", "@server": {}, "serverAddress": "Endereço do servidor", "@serverAddress": {}, + "serverApiRequired": "Versão de API Necessária", + "@serverApiRequired": {}, + "serverApiVersion": "Versão API do Servidor", + "@serverApiVersion": {}, + "serverAuthenticationError": "Erro de Autenticação", + "@serverAuthenticationError": {}, + "serverCertificateError": "Erro de Certificação", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Certificado HTTPS do servidor é Inválido", + "@serverCertificateInvalid": {}, + "serverConnected": "Conectado ao servidor", + "@serverConnected": {}, + "serverConnecting": "Conectando ao servidor", + "@serverConnecting": {}, + "serverCouldNotConnect": "Não foi possível conectar ao servidor", + "@serverCouldNotConnect": {}, + "serverEmpty": "Servidor não pode estar vazio", + "@serverEmpty": {}, "serverError": "Erro de servidor", "@serverError": {}, "serverDetails": "Detalhes do servidor", @@ -667,6 +755,14 @@ "@suppliedParts": {}, "supplier": "Fornecedor", "@supplier": {}, + "supplierPart": "Fornecedor da Peça", + "@supplierPart": {}, + "supplierPartEdit": "Editar Fornecedor", + "@supplierPartEdit": {}, + "supplierPartUpdated": "Fornecedor da Peça Atualizado", + "@supplierPartUpdated": {}, + "supplierParts": "Peças dos Fornecedores", + "@supplierParts": {}, "suppliers": "Fornecedores", "@suppliers": {}, "supplierReference": "Referencia do fornecedor", From 347e80d8e247be6ffb9e0104948855f16cc681b3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 8 Mar 2023 23:42:26 +1100 Subject: [PATCH 310/746] Adds support for currency display (#277) * Adds a helper function for rendering currency data * Update helper functions for StockItem model * Render purchasePrice correctly for stockitem * Use currency_formatter library instead of money_formatter * Add total price display for purchase order * icon fix --- assets/release_notes.md | 1 + lib/helpers.dart | 21 ++ lib/inventree/purchase_order.dart | 12 + lib/inventree/stock.dart | 478 +++++++++++++------------- lib/l10n/app_en.arb | 3 + lib/widget/purchase_order_detail.dart | 10 +- lib/widget/stock_detail.dart | 5 +- pubspec.lock | 16 + pubspec.yaml | 1 + 9 files changed, 311 insertions(+), 236 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 61a1b2b..bfb2681 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ ### 0.10.2 - March 2023 --- +- Adds support for proper currency rendering - Fix icon for supplier part detail widget ### 0.10.1 - February 2023 diff --git a/lib/helpers.dart b/lib/helpers.dart index 085a051..ae1150c 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -8,6 +8,7 @@ */ import "dart:io"; +import "package:currency_formatter/currency_formatter.dart"; import "package:audioplayers/audioplayers.dart"; import "package:one_context/one_context.dart"; @@ -77,3 +78,23 @@ Future playAudioFile(String path) async { final player = AudioPlayer(); player.play(AssetSource(path)); } + + +/* + * Helper function for rendering a money / currency object as a String + */ +String renderCurrency(double? amount, String currency, {int decimals = 2}) { + + if (amount == null) return "-"; + if (amount.isInfinite || amount.isNaN) return "-"; + + CurrencyFormatterSettings backupSettings = CurrencyFormatterSettings( + symbol: "\$", + symbolSide: SymbolSide.left, + ); + + return CurrencyFormatter.format( + amount, + CurrencyFormatter.majors[currency.toLowerCase()] ?? backupSettings + ); +} \ No newline at end of file diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 59dff7e..2194328 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -89,6 +89,18 @@ class InvenTreePurchaseOrder extends InvenTreeModel { bool get isFailed => status == PO_STATUS_CANCELLED || status == PO_STATUS_LOST || status == PO_STATUS_RETURNED; + double? get totalPrice { + String price = (jsondata["total_price"] ?? "") as String; + + if (price.isEmpty) { + return null; + } else { + return double.tryParse(price); + } + } + + String get totalPriceCurrency => (jsondata["total_price_currency"] ?? "") as String; + Future> getLineItems() async { final results = await InvenTreePOLineItem().list( diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index be76ce7..f8a9a44 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -206,6 +206,8 @@ class InvenTreeStockItem extends InvenTreeModel { }, "status": {}, "batch": {}, + "purchase_price": {}, + "purchase_price_currency": {}, "packaging": {}, "link": {}, }; @@ -284,13 +286,21 @@ class InvenTreeStockItem extends InvenTreeModel { int get partId => (jsondata["part"] ?? -1) as int; - String get purchasePrice => (jsondata["purchase_price"] ?? "") as String; + double? get purchasePrice { + String pp = (jsondata["purchase_price"] ?? "") as String; + + if (pp.isEmpty) { + return null; + } else { + return double.tryParse(pp); + } + } + + String get purchasePriceCurrency => (jsondata["purchase_price_currency"] ?? "") as String; bool get hasPurchasePrice { - - String pp = purchasePrice; - - return pp.isNotEmpty && pp.trim() != "-"; + double? pp = purchasePrice; + return pp != null && pp > 0; } int get purchaseOrderId => (jsondata["purchase_order"] ?? -1) as int; @@ -299,321 +309,321 @@ class InvenTreeStockItem extends InvenTreeModel { bool get isBuilding => (jsondata["is_building"] ?? false) as bool; - // Date of last update - DateTime? get updatedDate { - if (jsondata.containsKey("updated")) { - return DateTime.tryParse((jsondata["updated"] ?? "") as String); - } else { - return null; - } - } - - String get updatedDateString { - var _updated = updatedDate; - - if (_updated == null) { - return ""; + // Date of last update + DateTime? get updatedDate { + if (jsondata.containsKey("updated")) { + return DateTime.tryParse((jsondata["updated"] ?? "") as String); + } else { + return null; + } } - final DateFormat _format = DateFormat("yyyy-MM-dd"); + String get updatedDateString { + var _updated = updatedDate; - return _format.format(_updated); - } + if (_updated == null) { + return ""; + } - DateTime? get stocktakeDate { - if (jsondata.containsKey("stocktake_date")) { - return DateTime.tryParse((jsondata["stocktake_date"] ?? "") as String); - } else { - return null; - } - } + final DateFormat _format = DateFormat("yyyy-MM-dd"); - String get stocktakeDateString { - var _stocktake = stocktakeDate; - - if (_stocktake == null) { - return ""; + return _format.format(_updated); } - final DateFormat _format = DateFormat("yyyy-MM-dd"); - - return _format.format(_stocktake); - } - - String get partName { - - String nm = ""; - - // Use the detailed part information as priority - if (jsondata.containsKey("part_detail")) { - nm = (jsondata["part_detail"]["full_name"] ?? "") as String; + DateTime? get stocktakeDate { + if (jsondata.containsKey("stocktake_date")) { + return DateTime.tryParse((jsondata["stocktake_date"] ?? "") as String); + } else { + return null; + } } - // Backup if first value fails - if (nm.isEmpty) { - nm = (jsondata["part__name"] ?? "") as String; + String get stocktakeDateString { + var _stocktake = stocktakeDate; + + if (_stocktake == null) { + return ""; + } + + final DateFormat _format = DateFormat("yyyy-MM-dd"); + + return _format.format(_stocktake); } - return nm; - } + String get partName { - String get partDescription { - String desc = ""; + String nm = ""; - // Use the detailed part description as priority - if (jsondata.containsKey("part_detail")) { - desc = (jsondata["part_detail"]["description"] ?? "") as String; + // Use the detailed part information as priority + if (jsondata.containsKey("part_detail")) { + nm = (jsondata["part_detail"]["full_name"] ?? "") as String; + } + + // Backup if first value fails + if (nm.isEmpty) { + nm = (jsondata["part__name"] ?? "") as String; + } + + return nm; } - if (desc.isEmpty) { - desc = (jsondata["part__description"] ?? "") as String; + String get partDescription { + String desc = ""; + + // Use the detailed part description as priority + if (jsondata.containsKey("part_detail")) { + desc = (jsondata["part_detail"]["description"] ?? "") as String; + } + + if (desc.isEmpty) { + desc = (jsondata["part__description"] ?? "") as String; + } + + return desc; } - return desc; - } + String get partImage { + String img = ""; - String get partImage { - String img = ""; + if (jsondata.containsKey("part_detail")) { + img = (jsondata["part_detail"]["thumbnail"] ?? "") as String; + } - if (jsondata.containsKey("part_detail")) { - img = (jsondata["part_detail"]["thumbnail"] ?? "") as String; + if (img.isEmpty) { + img = (jsondata["part__thumbnail"] ?? "") as String; + } + + return img; } - if (img.isEmpty) { - img = (jsondata["part__thumbnail"] ?? "") as String; - } - - return img; - } - - /* + /* * Return the Part thumbnail for this stock item. */ - String get partThumbnail { + String get partThumbnail { - String thumb = ""; + String thumb = ""; - thumb = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; + thumb = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; - // Use "image" as a backup - if (thumb.isEmpty) { - thumb = (jsondata["part_detail"]?["image"] ?? "") as String; + // Use "image" as a backup + if (thumb.isEmpty) { + thumb = (jsondata["part_detail"]?["image"] ?? "") as String; + } + + // Try a different approach + if (thumb.isEmpty) { + thumb = (jsondata["part__thumbnail"] ?? "") as String; + } + + // Still no thumbnail? Use the "no image" image + if (thumb.isEmpty) thumb = InvenTreeAPI.staticThumb; + + return thumb; } - // Try a different approach - if (thumb.isEmpty) { - thumb = (jsondata["part__thumbnail"] ?? "") as String; + int get supplierPartId => (jsondata["supplier_part"] ?? -1) as int; + + String get supplierImage { + String thumb = ""; + + if (jsondata.containsKey("supplier_part_detail")) { + thumb = (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") as String; + } else if (jsondata.containsKey("supplier_detail")) { + thumb = (jsondata["supplier_detail"]["image"] ?? "") as String; + } + + return thumb; } - // Still no thumbnail? Use the "no image" image - if (thumb.isEmpty) thumb = InvenTreeAPI.staticThumb; + String get supplierName { + String sname = ""; - return thumb; - } + if (jsondata.containsKey("supplier_detail")) { + sname = (jsondata["supplier_detail"]["supplier_name"] ?? "") as String; + } - int get supplierPartId => (jsondata["supplier_part"] ?? -1) as int; - - String get supplierImage { - String thumb = ""; - - if (jsondata.containsKey("supplier_part_detail")) { - thumb = (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") as String; - } else if (jsondata.containsKey("supplier_detail")) { - thumb = (jsondata["supplier_detail"]["image"] ?? "") as String; + return sname; } - return thumb; - } - - String get supplierName { - String sname = ""; - - if (jsondata.containsKey("supplier_detail")) { - sname = (jsondata["supplier_detail"]["supplier_name"] ?? "") as String; + String get units { + return (jsondata["part_detail"]?["units"] ?? "") as String; } - return sname; - } + String get supplierSKU { + String sku = ""; - String get units { - return (jsondata["part_detail"]?["units"] ?? "") as String; - } + if (jsondata.containsKey("supplier_part_detail")) { + sku = (jsondata["supplier_part_detail"]["SKU"] ?? "") as String; + } - String get supplierSKU { - String sku = ""; - - if (jsondata.containsKey("supplier_part_detail")) { - sku = (jsondata["supplier_part_detail"]["SKU"] ?? "") as String; + return sku; } - return sku; - } + String get serialNumber => (jsondata["serial"] ?? "") as String; - String get serialNumber => (jsondata["serial"] ?? "") as String; + double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; - double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; + String quantityString({bool includeUnits = false}){ - String quantityString({bool includeUnits = false}){ + String q = ""; - String q = ""; + if (allocated > 0) { + q += simpleNumberString(available); + q += " / "; + } - if (allocated > 0) { - q += simpleNumberString(available); - q += " / "; + q += simpleNumberString(quantity); + + if (includeUnits && units.isNotEmpty) { + q += " ${units}"; + } + + return q; } - q += simpleNumberString(quantity); + double get allocated => double.tryParse(jsondata["allocated"].toString()) ?? 0; - if (includeUnits && units.isNotEmpty) { - q += " ${units}"; + double get available => quantity - allocated; + + int get locationId => (jsondata["location"] ?? -1) as int; + + bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; + + String serialOrQuantityDisplay() { + if (isSerialized()) { + return "SN ${serialNumber}"; + } else if (allocated > 0) { + return "${available} / ${quantity}"; + } else { + return simpleNumberString(quantity); + } } - return q; - } + String get locationName { + String loc = ""; - double get allocated => double.tryParse(jsondata["allocated"].toString()) ?? 0; + if (locationId == -1 || !jsondata.containsKey("location_detail")) return "Unknown Location"; - double get available => quantity - allocated; + loc = (jsondata["location_detail"]["name"] ?? "") as String; - int get locationId => (jsondata["location"] ?? -1) as int; + // Old-style name + if (loc.isEmpty) { + loc = (jsondata["location__name"] ?? "") as String; + } - bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; - - String serialOrQuantityDisplay() { - if (isSerialized()) { - return "SN ${serialNumber}"; - } else if (allocated > 0) { - return "${available} / ${quantity}"; - } else { - return simpleNumberString(quantity); - } - } - - String get locationName { - String loc = ""; - - if (locationId == -1 || !jsondata.containsKey("location_detail")) return "Unknown Location"; - - loc = (jsondata["location_detail"]["name"] ?? "") as String; - - // Old-style name - if (loc.isEmpty) { - loc = (jsondata["location__name"] ?? "") as String; + return loc; } - return loc; - } + String get locationPathString { - String get locationPathString { + if (locationId == -1 || !jsondata.containsKey("location_detail")) return L10().locationNotSet; - if (locationId == -1 || !jsondata.containsKey("location_detail")) return L10().locationNotSet; + String _loc = (jsondata["location_detail"]["pathstring"] ?? "") as String; - String _loc = (jsondata["location_detail"]["pathstring"] ?? "") as String; - - if (_loc.isNotEmpty) { - return _loc; - } else { - return locationName; + if (_loc.isNotEmpty) { + return _loc; + } else { + return locationName; + } } - } - String get displayQuantity { - // Display either quantity or serial number! + String get displayQuantity { + // Display either quantity or serial number! - if (serialNumber.isNotEmpty) { - return "SN: $serialNumber"; - } else { - return simpleNumberString(quantity); + if (serialNumber.isNotEmpty) { + return "SN: $serialNumber"; + } else { + return simpleNumberString(quantity); + } } - } - @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeStockItem.fromJson(json); - } + @override + InvenTreeModel createFromJson(Map json) { + return InvenTreeStockItem.fromJson(json); + } - /* + /* * Perform stocktake action: * * - Add * - Remove * - Count */ - Future adjustStock(String endpoint, double q, {String? notes, int? location}) async { + Future adjustStock(String endpoint, double q, {String? notes, int? location}) async { - // Serialized stock cannot be adjusted (unless it is a "transfer") - if (isSerialized() && location == null) { - return false; + // Serialized stock cannot be adjusted (unless it is a "transfer") + if (isSerialized() && location == null) { + return false; + } + + // Cannot handle negative stock + if (q < 0) { + return false; + } + + Map data = {}; + + data = { + "items": [ + { + "pk": "${pk}", + "quantity": "${quantity}", + } + ], + "notes": notes ?? "", + }; + + if (location != null) { + data["location"] = location; + } + + var response = await api.post( + endpoint, + body: data, + ); + + return response.isValid() && (response.statusCode == 200 || response.statusCode == 201); } - // Cannot handle negative stock - if (q < 0) { - return false; + Future countStock(double q, {String? notes}) async { + + final bool result = await adjustStock("/stock/count/", q, notes: notes); + + return result; } - Map data = {}; + Future addStock(double q, {String? notes}) async { - data = { - "items": [ - { - "pk": "${pk}", - "quantity": "${quantity}", - } - ], - "notes": notes ?? "", - }; + final bool result = await adjustStock("/stock/add/", q, notes: notes); - if (location != null) { - data["location"] = location; + return result; } - var response = await api.post( - endpoint, - body: data, - ); + Future removeStock(double q, {String? notes}) async { - return response.isValid() && (response.statusCode == 200 || response.statusCode == 201); - } + final bool result = await adjustStock("/stock/remove/", q, notes: notes); - Future countStock(double q, {String? notes}) async { - - final bool result = await adjustStock("/stock/count/", q, notes: notes); - - return result; - } - - Future addStock(double q, {String? notes}) async { - - final bool result = await adjustStock("/stock/add/", q, notes: notes); - - return result; - } - - Future removeStock(double q, {String? notes}) async { - - final bool result = await adjustStock("/stock/remove/", q, notes: notes); - - return result; - } - - Future transferStock(int location, {double? quantity, String? notes}) async { - - double q = this.quantity; - - if (quantity != null) { - q = quantity; + return result; } - final bool result = await adjustStock( - "/stock/transfer/", - q, - notes: notes, - location: location, - ); + Future transferStock(int location, {double? quantity, String? notes}) async { - return result; + double q = this.quantity; + + if (quantity != null) { + q = quantity; + } + + final bool result = await adjustStock( + "/stock/transfer/", + q, + notes: notes, + location: location, + ); + + return result; + } } -} /* diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 879b714..f01d253 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1180,6 +1180,9 @@ "tokenMissingFromResponse": "Access token missing from response", "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", "@transfer": { "description": "transfer" diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index d81d176..87d6e6e 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -158,6 +158,14 @@ class _PurchaseOrderDetailState extends RefreshableState { ListTile( title: Text(L10().purchasePrice), leading: FaIcon(FontAwesomeIcons.dollarSign), - trailing: Text(widget.item.purchasePrice), + trailing: Text( + renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) + ) ) ); } diff --git a/pubspec.lock b/pubspec.lock index c31f34e..efea81b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -257,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + currency_formatter: + dependency: "direct main" + description: + name: currency_formatter + sha256: "24034a969f21a55071b1cf835655c1fb1fd94e3acd498a77283e945002591fb6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" datetime_picker_formfield: dependency: "direct main" description: @@ -1034,6 +1042,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" + url: "https://pub.dev" + source: hosted + version: "2.2.0" url_launcher: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ba97079..ac1c80b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: cached_network_image: ^3.2.0 # Download and cache remote images camera: ^0.10.3 # Camera cupertino_icons: ^1.0.3 + currency_formatter: ^2.0.0 datetime_picker_formfield: ^2.0.0 # Date / time picker device_info_plus: ^8.0.0 # Information about the device dropdown_search: ^5.0.5 # Dropdown autocomplete form fields From bb1c1cf3d9d5f46193c4408ac0eeac3e508cce09 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 9 Mar 2023 20:35:21 +1100 Subject: [PATCH 311/746] New translations app_en.arb (Portuguese, Brazilian) (#279) --- lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 5ebdf61..d820952 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -803,6 +803,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Token indisponivel na resposta", "@tokenMissingFromResponse": {}, + "totalPrice": "Preço Total", + "@totalPrice": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" From 878d9b46d2a10c30272f58c7523ac897704d9f95 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 14 Mar 2023 22:57:10 +1100 Subject: [PATCH 312/746] New Crowdin updates (#280) * New translations app_en.arb (German) * New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index f128d3d..49a0c4d 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -803,6 +803,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", "@tokenMissingFromResponse": {}, + "totalPrice": "Gesamtbetrag", + "@totalPrice": {}, "transfer": "Verschieben", "@transfer": { "description": "transfer" From 82f25dfc902c4d55bdc889fed887bbe325eb204a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 14 Mar 2023 23:02:59 +1100 Subject: [PATCH 313/746] Update docs link (#281) --- lib/settings/about.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 5ac468b..b398ed3 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -41,7 +41,7 @@ class InvenTreeAboutWidget extends StatelessWidget { var docsUrl = Uri( scheme: "https", - host: "inventree.readthedocs.io", + host: "docs.inventree.org", path: "en/latest/app/app/"); if (await canLaunchUrl(docsUrl)) { @@ -186,7 +186,7 @@ class InvenTreeAboutWidget extends StatelessWidget { tiles.add( ListTile( title: Text(L10().documentation), - subtitle: Text("https://inventree.readthedocs.io"), + subtitle: Text("https://docs.inventree.org"), leading: FaIcon(FontAwesomeIcons.book, color: COLOR_CLICK), onTap: () { _openDocs(); From b2d4522fb2d851e3406eb8fbf28ec4000443920f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 15 Mar 2023 07:56:27 +1100 Subject: [PATCH 314/746] Add currency suffix if currency cannot be determined (#282) --- lib/helpers.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/helpers.dart b/lib/helpers.dart index ae1150c..3cb905e 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -88,13 +88,24 @@ String renderCurrency(double? amount, String currency, {int decimals = 2}) { if (amount == null) return "-"; if (amount.isInfinite || amount.isNaN) return "-"; + currency = currency.trim(); + + if (currency.isEmpty) return "-"; + CurrencyFormatterSettings backupSettings = CurrencyFormatterSettings( symbol: "\$", symbolSide: SymbolSide.left, ); - return CurrencyFormatter.format( + String value = CurrencyFormatter.format( amount, CurrencyFormatter.majors[currency.toLowerCase()] ?? backupSettings ); + + // If we were not able to determine the currency + if (!CurrencyFormatter.majors.containsKey(currency.toLowerCase())) { + value += " ${currency}"; + } + + return value; } \ No newline at end of file From 73fd35d9a32aa2981df84a8c72a3fd6afb7c2e58 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 17 Mar 2023 19:36:44 +1100 Subject: [PATCH 315/746] New translations app_en.arb (Hungarian) (#283) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 0c97054..4d17b56 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -803,6 +803,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", "@tokenMissingFromResponse": {}, + "totalPrice": "Teljes ár", + "@totalPrice": {}, "transfer": "Áthelyezés", "@transfer": { "description": "transfer" From 9543490c21da8d5af7c40a9ea46dc61d63150c64 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Mar 2023 19:37:45 +1100 Subject: [PATCH 316/746] New Crowdin updates (#288) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/pt_BR/app_pt_BR.arb | 106 +++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index d820952..51e5cc3 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -1,6 +1,6 @@ { "@@locale": "en", - "appTitle": "CONTEXTO", + "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" }, @@ -8,37 +8,37 @@ "@ok": { "description": "OK" }, - "about": "&Sobre", + "about": "Sobre", "@about": {}, "accountDetails": "Detalhes da Conta", "@accountDetails": {}, - "actions": "Acoes", + "actions": "Ações", "@actions": { "description": "" }, - "actionsNone": "Nenhuma acao disponivel", + "actionsNone": "Nenhuma ação disponível", "@actionsNone": {}, "add": "Adicionar", "@add": { "description": "add" }, - "addStock": "Novo item", + "addStock": "Adicionar estoque", "@addStock": { "description": "add stock" }, - "address": "Endereco", + "address": "Endereço", "@address": {}, "appAbout": "Sobre InvenTree", "@appAbout": {}, - "appCredits": "Outros creditos do aplicativo", + "appCredits": "Outros créditos do aplicativo", "@appCredits": {}, "appDetails": "Detalhes do aplicativo", "@appDetails": {}, - "appReleaseNotes": "Mostrar detalhes do release", + "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, - "appSettings": "Configuracoes", + "appSettings": "Configurações do App", "@appSettings": {}, - "appSettingsDetails": "Configuracoes do InvenTree", + "appSettingsDetails": "Configurar os parâmetros do App do InvenTree", "@appSettingsDetails": {}, "attachments": "Anexos", "@attachments": {}, @@ -52,57 +52,57 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "Selecionar anexo", "@attachmentSelect": {}, - "attention": "Atencao", + "attention": "Atenção", "@attention": {}, - "availableStock": "Estoque disponivel", + "availableStock": "Estoque Disponível", "@availableStock": {}, - "barcodeAssign": "Adiconar codigo de barras", + "barcodeAssign": "Atribuir Código de Barras", "@barcodeAssign": {}, "barcodeAssignDetail": "Digitalize o código de barras personalizado para atribuir", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Cod Barras adicionado", + "barcodeAssigned": "Código de barras atribuído", "@barcodeAssigned": {}, - "barcodeError": "Erro ao scanear Cod Bar", + "barcodeError": "Erro ao escanear código de barras", "@barcodeError": {}, - "barcodeInUse": "Cod Bar ja adiciconado", + "barcodeInUse": "Código de barras já atribuído", "@barcodeInUse": {}, - "barcodeMissingHash": "Hash do cod bar nao encontrado", + "barcodeMissingHash": "Dados de hash de código de barras faltando na resposta", "@barcodeMissingHash": {}, - "barcodeNoMatch": "Cod Bar nao encontrado", + "barcodeNoMatch": "Nenhum código de barras correspondente", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Cod Bar inexistente", + "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, - "barcodeScanAssign": "Scanear para adicionar Cod Bar", + "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Scanear um Cod Bar InvenTree", + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Digitalizar itens de estoque neste local", + "barcodeScanInItems": "Busca de itens de estoque para este local", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scanear localizacao do stock", + "barcodeScanLocation": "Escanear Local do Estoque", "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Localizacao scaneada", + "barcodeScanIntoLocationSuccess": "Escaneado no local", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item nao scaneado", + "barcodeScanIntoLocationFailure": "O item não foi digitalizado no", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scanear item de estoque", + "barcodeScanItem": "Escanear item em estoque", "@barcodeScanItem": {}, - "barcodeTones": "Tom de Cod Bar", + "barcodeTones": "Tons de código de barras", "@barcodeTones": {}, - "barcodeUnassign": "Cod Bar nao selecionado", + "barcodeUnassign": "Desatribuir Código de Barras", "@barcodeUnassign": {}, - "barcodeUnknown": "Cod Bar nao reconhecido", + "barcodeUnknown": "Código de barras não reconhecido", "@barcodeUnknown": {}, - "batchCode": "Codigo batch", + "batchCode": "Código do lote", "@batchCode": {}, - "billOfMaterials": "Conta de materiais", + "billOfMaterials": "Lista de Materiais", "@billOfMaterials": {}, - "bom": "BOM", + "bom": "LDM", "@bom": {}, "bomEnable": "Mostrar Lista de Materiais", "@bomEnable": {}, - "build": "Construcao", + "build": "Produzir", "@build": {}, - "building": "Construindo", + "building": "Produzindo", "@building": {}, "cancel": "Cancelar", "@cancel": { @@ -130,7 +130,7 @@ "@configureServer": {}, "connectionRefused": "Conexão recusada", "@connectionRefused": {}, - "count": "Contador", + "count": "Contar", "@count": { "description": "Count" }, @@ -148,9 +148,9 @@ "@delete": {}, "deleteFailed": "A operação de apagar falhou", "@deleteFailed": {}, - "deletePart": "Deletar Parte", + "deletePart": "Deletar Peça", "@deletePart": {}, - "deletePartDetail": "Remova essa parte do banco de dados", + "deletePartDetail": "Remova essa peça do banco de dados", "@deletePartDetail": {}, "deleteSuccess": "Apagado com Sucesso", "@deleteSuccess": {}, @@ -174,7 +174,7 @@ }, "editCategory": "Editar categoria", "@editCategory": {}, - "editLocation": "Editar localização", + "editLocation": "Editar Local", "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, @@ -295,7 +295,7 @@ "@includeSubcategoriesDetail": {}, "includeSublocations": "Incuir Sub-Locacoes", "@includeSublocations": {}, - "includeSublocationsDetail": "Mostrar resultados dos sublocais", + "includeSublocationsDetail": "Mostrar resultados de sublocais", "@includeSublocationsDetail": {}, "incompleteDetails": "Detalhes incompletos", "@incompleteDetails": {}, @@ -319,7 +319,7 @@ "@invalidStockLocation": {}, "invalidStockItem": "Item de estoque invalido", "@invalidStockItem": {}, - "invalidSupplierPart": "Fornecedor de Peça Inválido", + "invalidSupplierPart": "Fornecedor da Peça Inválido", "@invalidSupplierPart": {}, "invalidUsernamePassword": "Usuario ou senha invalidos", "@invalidUsernamePassword": {}, @@ -389,7 +389,7 @@ "@noSubcategoriesAvailable": {}, "numberInvalid": "Número inválido", "@numberInvalid": {}, - "onOrder": "Pedido já colocado", + "onOrder": "No pedido", "@onOrder": {}, "onOrderDetails": "Itens atualmente com pedidos feitos", "@onOrderDetails": {}, @@ -411,7 +411,7 @@ "@part": { "description": "Part (single)" }, - "partCreate": "Nova peça", + "partCreate": "Nova Peça", "@partCreate": {}, "partCreateDetail": "Criar uma peça nesta categoria", "@partCreateDetail": {}, @@ -617,7 +617,7 @@ "@searching": {}, "searchLocation": "Procurar um Local", "@searchLocation": {}, - "searchParts": "Procurar uma Peça", + "searchParts": "Procurar Peças", "@searchParts": {}, "searchStock": "Procurar o Estoque", "@searchStock": {}, @@ -681,9 +681,9 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Tocar tom audível no erro do servidor", "@soundOnServerError": {}, - "status": "Status", + "status": "Estado", "@status": {}, - "statusCode": "Código do status", + "statusCode": "Código do Estado", "@statusCode": {}, "stock": "Estoque", "@stock": { @@ -699,15 +699,15 @@ "@stockItems": {}, "stockItemCreate": "Novo item de estoque", "@stockItemCreate": {}, - "stockItemCreateDetail": "Criar novo item de estoque nesta localização", + "stockItemCreateDetail": "Criar item de estoque neste local", "@stockItemCreateDetail": {}, "stockItemDelete": "Excluir Item de Estoque", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Você tem certeza que deseja excluir este \"item\" de estoque?", + "stockItemDeleteConfirm": "Você tem certeza que deseja excluir este item de estoque?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Não foi possível excluir o \"item\" de estoque", + "stockItemDeleteFailure": "Não foi possível excluir o item de estoque", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "\"Item\" de estoque excluído", + "stockItemDeleteSuccess": "Item de estoque excluído", "@stockItemDeleteSuccess": {}, "stockItemHistory": "Histórico de estoque", "@stockItemHistory": {}, @@ -719,7 +719,7 @@ "@stockItemUpdated": {}, "stockItemsNotAvailable": "Nenhum item de estoque disponível", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Notas de Item Estoque", + "stockItemNotes": "Notas de Item em Estoque", "@stockItemNotes": {}, "stockItemUpdateSuccess": "Item de estoque atualizado", "@stockItemUpdateSuccess": {}, @@ -757,11 +757,11 @@ "@supplier": {}, "supplierPart": "Fornecedor da Peça", "@supplierPart": {}, - "supplierPartEdit": "Editar Fornecedor", + "supplierPartEdit": "Editar Fornecedor da Peça", "@supplierPartEdit": {}, "supplierPartUpdated": "Fornecedor da Peça Atualizado", "@supplierPartUpdated": {}, - "supplierParts": "Peças dos Fornecedores", + "supplierParts": "Peças do Fornecedor", "@supplierParts": {}, "suppliers": "Fornecedores", "@suppliers": {}, @@ -813,7 +813,7 @@ "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transferir \"item\" para um local diferente", + "transferStockDetail": "Transferir item para um local diferente", "@transferStockDetail": {}, "transferStockLocation": "Transferir Localização do Estoque", "@transferStockLocation": {}, From d7f2c3939bfe5d24307a473aaa532940b99588fd Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Mar 2023 21:09:38 +1100 Subject: [PATCH 317/746] Consolidated search (#289) * Update search widget to support consolidated search API endpoint * Finer control over global search * Update release notes * remove unused variable --- assets/release_notes.md | 1 + lib/api.dart | 3 + lib/widget/search.dart | 155 ++++++++++++++++++++++++++++++++-------- 3 files changed, 129 insertions(+), 30 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index bfb2681..33d045c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Adds support for proper currency rendering - Fix icon for supplier part detail widget +- Support global search API endpoint ### 0.10.1 - February 2023 --- diff --git a/lib/api.dart b/lib/api.dart index d8b012d..1617dda 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -279,6 +279,9 @@ class InvenTreeAPI { // Company attachments require API v95 or newer bool get supportCompanyAttachments => isConnected() && apiVersion >= 95; + // Consolidated search request API v102 or newer + bool get supportsConsolidatedSearch => isConnected() && apiVersion >= 102; + // Are plugins enabled on the server? bool _pluginsEnabled = false; diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 59608c8..3974143 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -69,27 +69,34 @@ class _SearchDisplayState extends RefreshableState { Timer? debounceTimer; + /* + * Decrement the number of pending / outstanding search queries + */ + void decrementPendingSearches() { + if (nPendingSearches > 0) { + nPendingSearches--; + } + } + + /* + * Determine if the search is still running + */ bool isSearching() { if (searchController.text.isEmpty) { return false; } - return nSearchResults < 5; + return nPendingSearches > 0; } - int nSearchResults = 0; - + // Individual search result count (for legacy search API) + int nPendingSearches = 0; int nPartResults = 0; - int nCategoryResults = 0; - int nStockResults = 0; - int nLocationResults = 0; - int nSupplierResults = 0; - int nPurchaseOrderResults = 0; late FocusNode _focusNode; @@ -114,6 +121,32 @@ class _SearchDisplayState extends RefreshableState { } } + /* + * Return the 'result count' for a particular query from the results map + * e.g. + * { + * "part": { + * "count": 102, + * } + * } + */ + int getSearchResultCount(Map results, String key) { + + dynamic result = results[key]; + + if (result == null || result is! Map) { + return 0; + } + + dynamic count = result["count"]; + + if (count == null || count is! int) { + return 0; + } + + return count; + } + /* * Initiate multiple search requests to the server. * Each request returns at *some point* in the future, @@ -122,7 +155,6 @@ class _SearchDisplayState extends RefreshableState { * So, each request only causes an update *if* the search term is still the same when it completes */ Future search(String term) async { - var api = InvenTreeAPI(); if (!mounted) { @@ -138,21 +170,95 @@ class _SearchDisplayState extends RefreshableState { nSupplierResults = 0; nPurchaseOrderResults = 0; - nSearchResults = 0; + nPendingSearches = 0; }); if (term.isEmpty) { return; } + // Consolidated search allows us to perform *all* searches in a single query + if (api.supportsConsolidatedSearch) { + Map body = { + "limit": 1, + "search": term, + }; + + // Part search + if (api.checkPermission("part", "view")) { + body["part"] = {}; + } + + // PartCategory search + if (api.checkPermission("part_category", "view")) { + body["partcategory"] = {}; + } + + // StockItem search + if (api.checkPermission("stock", "view")) { + body["stockitem"] = { + "in_stock": true, + }; + } + + // StockLocation search + if (api.checkPermission("stock_location", "view")) { + body["stocklocation"] = {}; + } + + // PurchaseOrder search + if (api.checkPermission("purchase_order", "view")) { + body["purchaseorder"] = { + "outstanding": true + }; + } + + if (body.isNotEmpty) { + nPendingSearches++; + + api.post( + "search/", + body: body, + expectedStatusCode: 200).then((APIResponse response) { + decrementPendingSearches(); + + Map results = {}; + + if (response.data is Map) { + results = response.data as Map; + } + + if (mounted) { + setState(() { + nPartResults = getSearchResultCount(results, "part"); + nCategoryResults = getSearchResultCount(results, "partcategory"); + nStockResults = getSearchResultCount(results, "stockitem"); + nLocationResults = getSearchResultCount(results, "stocklocation"); + nSupplierResults = 0; //getSearchResultCount(results, "") + nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder"); + }); + } + }); + } + } else { + legacySearch(term); + } + } + + /* + * Perform "legacy" search (without consolidated search API endpoint + */ + Future legacySearch(String term) async { + // Search parts if (api.checkPermission("part", "view")) { + nPendingSearches++; InvenTreePart().count(searchQuery: term).then((int n) { if (term == searchController.text) { if (mounted) { + decrementPendingSearches(); setState(() { nPartResults = n; - nSearchResults++; }); } } @@ -161,12 +267,13 @@ class _SearchDisplayState extends RefreshableState { // Search part categories if (api.checkPermission("part_category", "view")) { + nPendingSearches++; InvenTreePartCategory().count(searchQuery: term,).then((int n) { if (term == searchController.text) { if (mounted) { + decrementPendingSearches(); setState(() { nCategoryResults = n; - nSearchResults++; }); } } @@ -175,12 +282,13 @@ class _SearchDisplayState extends RefreshableState { // Search stock items if (api.checkPermission("stock", "view")) { + nPendingSearches++; InvenTreeStockItem().count(searchQuery: term).then((int n) { if (term == searchController.text) { if (mounted) { + decrementPendingSearches(); setState(() { nStockResults = n; - nSearchResults++; }); } } @@ -189,35 +297,22 @@ class _SearchDisplayState extends RefreshableState { // Search stock locations if (api.checkPermission("stock_location", "view")) { + nPendingSearches++; InvenTreeStockLocation().count(searchQuery: term).then((int n) { if (term == searchController.text) { if (mounted) { + decrementPendingSearches(); setState(() { nLocationResults = n; - nSearchResults++; }); } } }); } - // TDOO: Re-implement this once display for companies has been fixed - /* - // Search suppliers - InvenTreeCompany().count(searchQuery: term, - filters: { - "is_supplier": "true", - }, - ).then((int n) { - setState(() { - nSupplierResults = n; - nSearchResults++; - }); - }); - */ - // Search purchase orders if (api.checkPermission("purchase_order", "view")) { + nPendingSearches++; InvenTreePurchaseOrder().count( searchQuery: term, filters: { @@ -226,9 +321,9 @@ class _SearchDisplayState extends RefreshableState { ).then((int n) { if (term == searchController.text) { if (mounted) { + decrementPendingSearches(); setState(() { nPurchaseOrderResults = n; - nSearchResults++; }); } } From 091f33eb10cae198d50eda9fe42e44e339eea036 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Mar 2023 21:19:26 +1100 Subject: [PATCH 318/746] Update version and build (#290) --- assets/release_notes.md | 1 + pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 33d045c..0389df0 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -7,6 +7,7 @@ - Adds support for proper currency rendering - Fix icon for supplier part detail widget - Support global search API endpoint +- Updated translations ### 0.10.1 - February 2023 --- diff --git a/pubspec.yaml b/pubspec.yaml index ac1c80b..b0fd2da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.10.2+56 +version: 0.10.2+57 environment: sdk: ">=2.16.0 <3.0.0" From 79026792e2cde1071e49e739d3bffe6f8bf246bf Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Apr 2023 22:34:06 +1000 Subject: [PATCH 319/746] remove legacy "reference_prefix" request (#295) --- lib/widget/purchase_order_detail.dart | 7 +------ lib/widget/purchase_order_list.dart | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 87d6e6e..fa1ecb1 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -40,8 +40,6 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; @@ -66,9 +64,6 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { - - _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); - await order.reload(); lines = await order.getLineItems(); @@ -106,7 +101,7 @@ class _PurchaseOrderDetailState extends RefreshableState { _PaginatedPurchaseOrderListState() : super(); - // Purchase order prefix - String _poPrefix = ""; @override String get prefix => "po_"; @@ -84,8 +82,6 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); - params["outstanding"] = "true"; final page = await InvenTreePurchaseOrder().listPaginated(limit, offset, filters: params); @@ -102,7 +98,7 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState Date: Wed, 5 Apr 2023 22:12:17 +1000 Subject: [PATCH 320/746] New Crowdin updates (#297) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Dutch) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 +- lib/l10n/da_DK/app_da_DK.arb | 2 +- lib/l10n/de_DE/app_de_DE.arb | 2 +- lib/l10n/el_GR/app_el_GR.arb | 2 +- lib/l10n/es_ES/app_es_ES.arb | 2 +- lib/l10n/es_MX/app_es_MX.arb | 2 +- lib/l10n/fa_IR/app_fa_IR.arb | 2 +- lib/l10n/fr_FR/app_fr_FR.arb | 2 +- lib/l10n/he_IL/app_he_IL.arb | 2 +- lib/l10n/hu_HU/app_hu_HU.arb | 2 +- lib/l10n/id_ID/app_id_ID.arb | 2 +- lib/l10n/it_IT/app_it_IT.arb | 2 +- lib/l10n/ja_JP/app_ja_JP.arb | 2 +- lib/l10n/ko_KR/app_ko_KR.arb | 2 +- lib/l10n/nl_NL/app_nl_NL.arb | 18 +++++++++++++++++- lib/l10n/no_NO/app_no_NO.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 2 +- lib/l10n/pt_BR/app_pt_BR.arb | 2 +- lib/l10n/pt_PT/app_pt_PT.arb | 2 +- lib/l10n/ru_RU/app_ru_RU.arb | 2 +- lib/l10n/sl_SI/app_sl_SI.arb | 2 +- lib/l10n/sv_SE/app_sv_SE.arb | 2 +- lib/l10n/th_TH/app_th_TH.arb | 2 +- lib/l10n/tr_TR/app_tr_TR.arb | 2 +- lib/l10n/vi_VN/app_vi_VN.arb | 2 +- lib/l10n/zh_CN/app_zh_CN.arb | 2 +- 26 files changed, 42 insertions(+), 26 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 77e2977..c26fa6d 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "cs", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index f2dff57..88c45d5 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "da", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 49a0c4d..a975d45 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "de", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 062eff6..0a07b12 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "el", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 5415b38..ce3bb38 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "es-ES", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index ef4c400..e2a5f9c 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "es-MX", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index f2dff57..fc4f529 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "fa", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 7941682..3db29ce 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "fr", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index f2dff57..9c4a221 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "he", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 4d17b56..f778239 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "hu", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index f2dff57..acc5be8 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "id", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 0efa0f8..6f57e55 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "it", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 4071b7c..0e2b7ce 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "ja", "about": "概要", "@about": {}, "accountDetails": "アカウントの詳細", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 8f17321..53bcc17 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "ko", "add": "추가", "@add": { "description": "add" diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 087dbb9..04478ec 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "nl", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" @@ -317,6 +317,8 @@ "@invalidStockLocation": {}, "invalidStockItem": "Ongeldig Voorraadartikel", "@invalidStockItem": {}, + "invalidSupplierPart": "Ongeldig Leveranciersonderdeel", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", "@invalidUsernamePassword": {}, "issueDate": "Uitgiftedatum", @@ -749,6 +751,14 @@ "@suppliedParts": {}, "supplier": "Leverancier", "@supplier": {}, + "supplierPart": "Leveranciersonderdeel", + "@supplierPart": {}, + "supplierPartEdit": "Bewerk Leveranciersonderdeel", + "@supplierPartEdit": {}, + "supplierPartUpdated": "Leveranciersonderdeel bijgewerkt", + "@supplierPartUpdated": {}, + "supplierParts": "Leveranciersonderdeel", + "@supplierParts": {}, "suppliers": "Leveranciers", "@suppliers": {}, "supplierReference": "Leveranciers Referentie", @@ -757,6 +767,8 @@ "@takePicture": {}, "targetDate": "Streefdatum", "@targetDate": {}, + "templatePart": "Bovenliggend sjabloon onderdeel", + "@templatePart": {}, "testName": "Test Naam", "@testName": {}, "testPassedOrFailed": "Test geslaagd of mislukt", @@ -785,6 +797,10 @@ "@tokenError": {}, "tokenMissing": "Ontbrekende Token", "@tokenMissing": {}, + "tokenMissingFromResponse": "Toegangstoken ontbreekt in antwoord", + "@tokenMissingFromResponse": {}, + "totalPrice": "Totaalprijs", + "@totalPrice": {}, "transfer": "Verplaats", "@transfer": { "description": "transfer" diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index f2dff57..f0ac65c 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "no", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index b28b3f6..4474772 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "pl", "about": "O nas", "@about": {}, "accountDetails": "Szczegóły konta", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 51e5cc3..b19e134 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "pt-BR", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 6752a01..8e60015 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "pt-PT", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 89a8551..c33b930 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "ru", "ok": "ОК", "@ok": { "description": "OK" diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index f2dff57..c51c253 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "sl", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index f2dff57..80e8669 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "sv-SE", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index f2dff57..6a6b92f 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "th", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index b29e729..b5d2a76 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "tr", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 1fc8bf2..c82145e 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "vi", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "parameters": "Thông số", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 630506c..db7dc46 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -1,5 +1,5 @@ { - "@@locale": "en", + "@@locale": "zh-CN", "appTitle": "InvenTree", "@appTitle": { "description": "InvenTree application title string" From f7d3315c9946f8a93d6c2d695ee4e574b6ce60f1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 5 Apr 2023 22:43:29 +1000 Subject: [PATCH 321/746] Support barcode scan for purchase order (#298) * Add functions for determining API support levels * Handle scanning of purchase orders --- lib/api.dart | 12 ++++++++++++ lib/barcode.dart | 30 ++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 1617dda..f0fdc83 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -282,6 +282,18 @@ class InvenTreeAPI { // Consolidated search request API v102 or newer bool get supportsConsolidatedSearch => isConnected() && apiVersion >= 102; + // ReturnOrder supports API v104 or newer + bool get supportsReturnOrders => isConnected() && apiVersion >= 104; + + // Status label endpoints API v105 or newer + bool get supportsStatusLabelEndpoints => isConnected() && apiVersion >= 105; + + // Regex search API v106 or newer + bool get supportsRegexSearch => isConnected() && apiVersion >= 106; + + // Order barcodes API v107 or newer + bool get supportsOrderBarcodes => isConnected() && apiVersion >= 107; + // Are plugins enabled on the server? bool _pluginsEnabled = false; diff --git a/lib/barcode.dart b/lib/barcode.dart index a030631..5c7d512 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -1,6 +1,8 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/purchase_order_detail.dart"; import "package:one_context/one_context.dart"; import "package:qr_code_scanner/qr_code_scanner.dart"; @@ -159,6 +161,7 @@ class BarcodeHandler { * - StockItem * - Part * - SupplierPart + * - PurchaseOrder */ class BarcodeScanHandler extends BarcodeHandler { @@ -232,6 +235,21 @@ class BarcodeScanHandler extends BarcodeHandler { } } + + /* + * Response when a "PurchaseOrder" instance is scanned + */ + Future handlePurchaseOrder(int pk) async { + var order = await InvenTreePurchaseOrder().get(pk); + + if (order is InvenTreePurchaseOrder) { + OneContext().pop(); + OneContext().push(MaterialPageRoute( + builder: (context) => PurchaseOrderDetailWidget(order))); + } + } + + @override Future onBarcodeMatched(Map data) async { int pk = -1; @@ -239,13 +257,18 @@ class BarcodeScanHandler extends BarcodeHandler { String model = ""; // The following model types can be matched with barcodes - final List validModels = [ + List validModels = [ "part", "stockitem", "stocklocation", - "supplierpart" + "supplierpart", ]; + + if (InvenTreeAPI().supportsOrderBarcodes) { + validModels.add("purchaseorder"); + } + for (var key in validModels) { if (data.containsKey(key)) { pk = (data[key]?["pk"] ?? -1) as int; @@ -276,6 +299,9 @@ class BarcodeScanHandler extends BarcodeHandler { case "supplierpart": await handleSupplierPart(pk); return; + case "purchaseorder": + await handlePurchaseOrder(pk); + return; default: // Fall through to failure state break; From 74176cdda8b597ae5f95e5ce00692a2d048b1690 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 5 Apr 2023 23:14:39 +1000 Subject: [PATCH 322/746] Bump release noes (#299) --- assets/release_notes.md | 5 +++++ lib/widget/drawer.dart | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 0389df0..e1e9f5b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.10.3 - April 2023 +--- + +- Support barcode scanning for purchase orders + ### 0.10.2 - March 2023 --- diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index c760ce2..64b6c3b 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -17,7 +17,7 @@ import "package:inventree/widget/search.dart"; * * - Provides a "home" button which completely unwinds the widget stack * - Global search - * - Barcoed scan + * - Barcode scan */ class InvenTreeDrawer extends StatelessWidget { @@ -90,7 +90,7 @@ class InvenTreeDrawer extends StatelessWidget { @override Widget build(BuildContext context) { - return Drawer( + return Drawer( child: ListView( children: ListTile.divideTiles( context: context, From a8f87e2f5a9277e96e214f09e1e875b73951e173 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 8 Apr 2023 23:59:11 +1000 Subject: [PATCH 323/746] UX Overhaul (#300) * Add "global actions" to title bar * Implement actions * Add "speed dial" action buttons * tweak global action icons * Refactor actions for "stock item" display * Refactor "part" detail * part category * SupplierPart * More updates * Add BottomAppBar * Add a global bottom app bar * Move "edit" buttons back to the app bar * tweaks * Updates to drawer navigation menu * home screen improvements * text tweaks * Fix appBarTitle for notifications widget * Update "tabs" for category display * Fix for attachment widget * Update tabs for purchaseorder view * Update part display * Cleanup * Add "BOM" tab to part detail widget * Paginated list search cleanup * Update release notes * Update old function * linting * linting * Tweaks to bottomappbar - Increase icon size slightly - Adjust "actions" icon --- assets/release_notes.md | 5 +- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 40 ++- ios/Runner/Info.plist | 4 + lib/barcode.dart | 37 +- lib/settings/settings.dart | 23 +- lib/widget/attachment_widget.dart | 46 +-- lib/widget/bom_list.dart | 4 +- lib/widget/category_display.dart | 157 +++------ lib/widget/category_list.dart | 4 +- lib/widget/company_detail.dart | 45 +-- lib/widget/company_list.dart | 2 +- lib/widget/drawer.dart | 168 +++++---- lib/widget/home.dart | 105 +----- lib/widget/location_display.dart | 443 ++++++++++-------------- lib/widget/location_list.dart | 4 +- lib/widget/notifications.dart | 5 +- lib/widget/paginator.dart | 10 +- lib/widget/part_detail.dart | 230 +++++------- lib/widget/part_image_widget.dart | 4 +- lib/widget/part_list.dart | 4 +- lib/widget/part_notes.dart | 4 +- lib/widget/part_parameter_widget.dart | 4 +- lib/widget/part_suppliers.dart | 4 +- lib/widget/purchase_order_detail.dart | 87 ++--- lib/widget/purchase_order_list.dart | 4 +- lib/widget/refreshable_state.dart | 201 +++++++++-- lib/widget/search.dart | 2 +- lib/widget/stock_detail.dart | 329 ++++++++---------- lib/widget/stock_item_history.dart | 2 +- lib/widget/stock_item_test_results.dart | 4 +- lib/widget/stock_list.dart | 4 +- lib/widget/stock_notes.dart | 4 +- lib/widget/supplier_part_detail.dart | 132 +++---- lib/widget/supplier_part_list.dart | 4 +- pubspec.lock | 8 + pubspec.yaml | 1 + 38 files changed, 979 insertions(+), 1159 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e1e9f5b..1eed3e4 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,9 +1,12 @@ ## InvenTree App Release Notes --- -### 0.10.3 - April 2023 +### 0.11.0 - April 2023 --- +- Adds globally accessible action button for "search" +- Adds globally accessible action button for "barcode scan" +- Implement context actions using floating actions buttons - Support barcode scanning for purchase orders ### 0.10.2 - March 2023 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..9625e10 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/ios/Podfile b/ios/Podfile index 0564dd3..74fd5d3 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -42,4 +42,4 @@ post_install do |installer| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' end end -end \ No newline at end of file +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 293e5b5..b35a1ca 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -236,6 +236,7 @@ }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -250,6 +251,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -276,17 +278,17 @@ "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", - "${BUILT_PRODUCTS_DIR}/audioplayers/audioplayers.framework", - "${BUILT_PRODUCTS_DIR}/camera/camera.framework", + "${BUILT_PRODUCTS_DIR}/audioplayers_darwin/audioplayers_darwin.framework", + "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", - "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", - "${BUILT_PRODUCTS_DIR}/open_file/open_file.framework", + "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", + "${BUILT_PRODUCTS_DIR}/open_filex/open_filex.framework", "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", - "${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework", + "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", "${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework", "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences_ios/shared_preferences_ios.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", ); @@ -299,17 +301,17 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers_darwin.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_file.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_filex.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", ); @@ -392,7 +394,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -415,7 +417,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -476,7 +478,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -523,7 +525,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -546,7 +548,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -577,7 +579,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 74a9f38..e3962ae 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -71,5 +71,9 @@ https + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/lib/barcode.dart b/lib/barcode.dart index 5c7d512..5487e3e 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -1,12 +1,12 @@ import "dart:io"; import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/purchase_order_detail.dart"; import "package:one_context/one_context.dart"; import "package:qr_code_scanner/qr_code_scanner.dart"; -import "package:inventree/app_colors.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -805,17 +805,12 @@ Future scanQrCode(BuildContext context) async { } -/* - * Construct a generic ListTile widget to link or un-link a custom barcode from a model. - */ -Widget customBarcodeActionTile(BuildContext context, RefreshableState state, String barcode, String model, int pk) { +SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, String barcode, String model, int pk) { if (barcode.isEmpty) { - return ListTile( - title: Text(L10().barcodeAssign), - subtitle: Text(L10().barcodeAssignDetail), - leading: Icon(Icons.qr_code, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code_scanner), + return SpeedDialChild( + label: L10().barcodeAssign, + child: Icon(Icons.barcode_reader), onTap: () { var handler = UniqueBarcodeHandler((String barcode) { InvenTreeAPI().linkBarcode({ @@ -823,8 +818,8 @@ Widget customBarcodeActionTile(BuildContext context, RefreshableState state, Str "barcode": barcode, }).then((bool result) { showSnackIcon( - result ? L10().barcodeAssigned : L10().barcodeNotAssigned, - success: result + result ? L10().barcodeAssigned : L10().barcodeNotAssigned, + success: result ); state.refresh(context); @@ -832,18 +827,18 @@ Widget customBarcodeActionTile(BuildContext context, RefreshableState state, Str }); Navigator.push( - context, - MaterialPageRoute( - builder: (context) => InvenTreeQRView(handler) - ) + context, + MaterialPageRoute( + builder: (context) => InvenTreeQRView(handler) + ) ); } ); } else { - return ListTile( - title: Text(L10().barcodeUnassign), - leading: Icon(Icons.qr_code, color: COLOR_CLICK), - onTap: () async { + return SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().barcodeUnassign, + onTap: () { InvenTreeAPI().unlinkBarcode({ model: pk.toString() }).then((bool result) { @@ -854,7 +849,7 @@ Widget customBarcodeActionTile(BuildContext context, RefreshableState state, Str state.refresh(context); }); - }, + } ); } } diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 4e8bf03..9c2c95c 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -1,8 +1,10 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; +import "package:inventree/settings/about.dart"; import "package:inventree/settings/app_settings.dart"; import "package:inventree/settings/home_settings.dart"; import "package:inventree/settings/login.dart"; @@ -22,6 +24,16 @@ class _InvenTreeSettingsState extends State { final _scaffoldKey = GlobalKey(); + /* + * Load "About" widget + */ + Future _about() async { + PackageInfo.fromPlatform().then((PackageInfo info) { + Navigator.push(context, + MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info))); + }); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -31,9 +43,7 @@ class _InvenTreeSettingsState extends State { ), body: Center( child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: [ + children: [ ListTile( title: Text(L10().server), subtitle: Text(L10().configureServer), @@ -65,9 +75,14 @@ class _InvenTreeSettingsState extends State { onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePartSettingsWidget())); } + ), + Divider(), + ListTile( + title: Text(L10().about), + leading: FaIcon(FontAwesomeIcons.circleInfo), + onTap: _about, ) ] - ).toList() ) ) ); diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 6ee694b..47bcc65 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -43,33 +43,35 @@ class _AttachmentWidgetState extends RefreshableState { List attachments = []; @override - String getAppBarTitle(BuildContext context) => L10().attachments; + String getAppBarTitle() => L10().attachments; @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { + if (!widget.hasUploadPermission) return []; - List actions = []; - - if (widget.hasUploadPermission) { - // File upload - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.circlePlus), - onPressed: () async { - FilePickerDialog.pickFile( - onPicked: (File file) async { - await upload(context, file); - } - ); - }, - ) - ); - } - - return actions; + return [ + IconButton( + icon: FaIcon(FontAwesomeIcons.camera), + onPressed: () async { + FilePickerDialog.pickImageFromCamera().then((File? file) { + upload(context, file); + }); + } + ), + IconButton( + icon: FaIcon(FontAwesomeIcons.fileArrowUp), + onPressed: () async { + FilePickerDialog.pickFileFromDevice().then((File? file) { + upload(context, file); + }); + } + ) + ]; } - Future upload(BuildContext context, File file) async { + Future upload(BuildContext context, File? file) async { + + if (file == null) return; showLoadingOverlay(context); final bool result = await widget.attachment.uploadAttachment(file, widget.referenceId); diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 022fc38..8504c75 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -37,7 +37,7 @@ class _BillOfMaterialsState extends RefreshableState { bool showFilterOptions = false; @override - String getAppBarTitle(BuildContext context) { + String getAppBarTitle() { if (widget.isParentComponent) { return L10().billOfMaterials; } else { @@ -46,7 +46,7 @@ class _BillOfMaterialsState extends RefreshableState { } @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index e72ec2a..2090687 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; @@ -33,27 +33,56 @@ class _CategoryDisplayState extends RefreshableState { bool showFilterOptions = false; @override - String getAppBarTitle(BuildContext context) => L10().partCategory; + String getAppBarTitle() => L10().partCategory; @override - List getAppBarActions(BuildContext context) { - + List appBarActions(BuildContext context) { List actions = []; - if ((widget.category != null) && InvenTreeAPI().checkPermission("part_category", "change")) { + if (widget.category != null) { + if (api.checkPermission("part_category", "change")) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().editCategory, + onPressed: () { + _editCategoryDialog(context); + }, + ) + ); + } + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("part", "add")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.shapes), + label: L10().partCreateDetail, + onTap: _newPart, + ) + ); + } + + if (api.checkPermission("part_category", "add")) { actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { - _editCategoryDialog(context); - }, + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.sitemap), + label: L10().categoryCreateDetail, + onTap: () { + _newCategory(context); + } ) ); } return actions; - } void _editCategoryDialog(BuildContext context) { @@ -154,25 +183,20 @@ class _CategoryDisplayState extends RefreshableState { } @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.sitemap), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.shapes), - label: L10().parts, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions - ), - ] - ); + List getTabIcons(BuildContext context) { + + return [ + Tab(text: L10().details), + Tab(text: L10().parts), + ]; + } + + @override + List getTabs(BuildContext context) { + return [ + Column(children: detailTiles()), + Column(children: partsTiles()), + ]; } // Construct the "details" panel @@ -216,7 +240,6 @@ class _CategoryDisplayState extends RefreshableState { }; return [ - getCategoryDescriptionCard(extra: false), ListTile( title: Text( L10().parts, @@ -298,74 +321,4 @@ class _CategoryDisplayState extends RefreshableState { } ); } - - List actionTiles(BuildContext context) { - - List tiles = [ - getCategoryDescriptionCard(extra: false), - ]; - - if (InvenTreeAPI().checkPermission("part", "add")) { - tiles.add( - ListTile( - title: Text(L10().categoryCreate), - subtitle: Text(L10().categoryCreateDetail), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - onTap: () async { - _newCategory(context); - }, - ) - ); - - if (widget.category != null) { - tiles.add( - ListTile( - title: Text(L10().partCreate), - subtitle: Text(L10().partCreateDetail), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_CLICK), - onTap: _newPart, - ) - ); - } - } - - if (tiles.isEmpty) { - tiles.add( - ListTile( - title: Text( - L10().actionsNone - ), - subtitle: Text( - L10().permissionAccountDenied, - ), - leading: FaIcon(FontAwesomeIcons.userXmark), - ) - ); - } - - return tiles; - } - - int partCount = 0; - - @override - Widget getBody(BuildContext context) { - - switch (tabIndex) { - case 0: - return Column( - children: detailTiles() - ); - case 1: - return Column( - children: partsTiles() - ); - case 2: - return ListView( - children: actionTiles(context) - ); - default: - return ListView(); - } - } } diff --git a/lib/widget/category_list.dart b/lib/widget/category_list.dart index 3e6f5be..0686faf 100644 --- a/lib/widget/category_list.dart +++ b/lib/widget/category_list.dart @@ -29,7 +29,7 @@ class _PartCategoryListState extends RefreshableState { bool showFilterOptions = false; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { @@ -41,7 +41,7 @@ class _PartCategoryListState extends RefreshableState { ]; @override - String getAppBarTitle(BuildContext context) => L10().partCategories; + String getAppBarTitle() => L10().partCategories; @override Widget getBody(BuildContext context) { diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index 7cc528f..be5167a 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/l10.dart"; @@ -40,34 +41,36 @@ class _CompanyDetailState extends RefreshableState { int attachmentCount = 0; @override - String getAppBarTitle(BuildContext context) => L10().company; + String getAppBarTitle() => L10().company; @override - List getAppBarActions(BuildContext context) { - + List appBarActions(BuildContext context) { List actions = []; - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: () async { - widget.company.goToInvenTreePage(); - }, - ) - ); + if (api.checkPermission("purchase_order", "change") || + api.checkPermission("sales_order", "change") || + api.checkPermission("return_order", "change")) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().companyEdit, + onPressed: () { + editCompany(context); + } + ) + ); + } + + return actions; + } - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { - editCompany(context); - } - ) - ); + @override + List actionButtons(BuildContext context) { + List actions = []; + + // TODO return actions; - } @override diff --git a/lib/widget/company_list.dart b/lib/widget/company_list.dart index 033423d..de9a539 100644 --- a/lib/widget/company_list.dart +++ b/lib/widget/company_list.dart @@ -32,7 +32,7 @@ class _CompanyListWidgetState extends RefreshableState { _CompanyListWidgetState(); @override - String getAppBarTitle(BuildContext context) => widget.title; + String getAppBarTitle() => widget.title; @override Widget getBody(BuildContext context) { diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 64b6c3b..4da5c50 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -1,23 +1,17 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/api.dart"; -import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; - -import "package:inventree/settings/about.dart"; import "package:inventree/settings/settings.dart"; - -import "package:inventree/widget/search.dart"; +import "package:inventree/widget/category_display.dart"; +import "package:inventree/widget/notifications.dart"; +import "package:inventree/widget/purchase_order_list.dart"; +import "package:inventree/widget/location_display.dart"; /* * Custom "drawer" widget for the InvenTree app. - * - * - Provides a "home" button which completely unwinds the widget stack - * - Global search - * - Barcode scan */ class InvenTreeDrawer extends StatelessWidget { @@ -42,90 +36,126 @@ class InvenTreeDrawer extends StatelessWidget { } } - void _search() { - - if (!InvenTreeAPI().checkConnection()) return; + // Load "parts" page + void _parts() { + _closeDrawer(); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)) + ); + } + // Load "stock" page + void _stock() { + _closeDrawer(); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)) + ); + } + + // Load "purchase orders" page + void _purchaseOrders() { _closeDrawer(); Navigator.push( context, MaterialPageRoute( - builder: (context) => SearchWidget(true) + builder: (context) => PurchaseOrderListWidget(filters: {}) ) ); } - /* - * Launch the camera to scan a QR code. - * Upon successful scan, data are passed off to be decoded. - */ - Future _scan() async { - if (!InvenTreeAPI().checkConnection()) return; - + // Load notifications screen + void _notifications() { _closeDrawer(); - scanQrCode(context); + Navigator.push(context, MaterialPageRoute(builder: (context) => NotificationWidget())); } - /* - * Load settings widget - */ + // Load settings widget void _settings() { _closeDrawer(); Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget())); } - /* - * Load "About" widget - */ - Future _about() async { - _closeDrawer(); + // Construct list of tiles to display in the "drawer" menu + List drawerTiles(BuildContext context) { + List tiles = []; - PackageInfo.fromPlatform().then((PackageInfo info) { - Navigator.push(context, - MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info))); - }); + // "Home" access + tiles.add(ListTile( + leading: FaIcon(FontAwesomeIcons.house), + title: Text( + L10().appTitle, + style: TextStyle(fontWeight: FontWeight.bold), + ), + onTap: _home, + )); + + tiles.add(Divider()); + + if (InvenTreeAPI().checkPermission("part_category", "view")) { + tiles.add( + ListTile( + title: Text(L10().parts), + leading: FaIcon(FontAwesomeIcons.shapes), + onTap: _parts, + ) + ); + } + + if (InvenTreeAPI().checkPermission("stock_location", "view")) { + tiles.add( + ListTile( + title: Text(L10().stock), + leading: FaIcon(FontAwesomeIcons.boxesStacked), + onTap: _stock, + ) + ); + } + + if (InvenTreeAPI().checkPermission("purchase_order", "view")) { + tiles.add( + ListTile( + title: Text(L10().purchaseOrders), + leading: FaIcon(FontAwesomeIcons.cartShopping), + onTap: _purchaseOrders, + ) + ); + } + + if (tiles.length > 2) { + tiles.add(Divider()); + } + + if (InvenTreeAPI().supportsNotifications) { + tiles.add( + ListTile( + leading: FaIcon(FontAwesomeIcons.bell), + title: Text(L10().notifications), + onTap: _notifications, + ) + ); + } + + tiles.add( + ListTile( + title: Text(L10().settings), + leading: Icon(Icons.settings), + onTap: _settings, + ) + ); + + return tiles; } @override Widget build(BuildContext context) { - return Drawer( + return Drawer( child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: [ - ListTile( - leading: FaIcon(FontAwesomeIcons.house), - title: Text( - L10().appTitle, - style: TextStyle(fontWeight: FontWeight.bold), - ), - onTap: _home, - ), - ListTile( - title: Text(L10().scanBarcode), - onTap: _scan, - leading: Icon(Icons.qr_code_scanner), - ), - ListTile( - title: Text(L10().search), - leading: FaIcon(FontAwesomeIcons.magnifyingGlass), - onTap: _search, - ), - ListTile( - title: Text(L10().settings), - leading: Icon(Icons.settings), - onTap: _settings, - ), - ListTile( - title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.circleInfo), - onTap: _about, - ) - ] - ).toList(), + children: drawerTiles(context), ) ); } -} \ No newline at end of file +} diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 8307f15..39c74a8 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -13,15 +13,12 @@ import "package:inventree/settings/login.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/user_profile.dart"; -import "package:inventree/inventree/notification.dart"; - import "package:inventree/widget/category_display.dart"; import "package:inventree/widget/drawer.dart"; import "package:inventree/widget/location_display.dart"; -import "package:inventree/widget/notifications.dart"; import "package:inventree/widget/part_list.dart"; import "package:inventree/widget/purchase_order_list.dart"; -import "package:inventree/widget/search.dart"; +import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/spinner.dart"; import "package:inventree/widget/company_list.dart"; @@ -35,7 +32,8 @@ class InvenTreeHomePage extends StatefulWidget { _InvenTreeHomePageState createState() => _InvenTreeHomePageState(); } -class _InvenTreeHomePageState extends State { + +class _InvenTreeHomePageState extends State with BaseWidgetProperties { _InvenTreeHomePageState() : super() { // Load display settings @@ -64,11 +62,7 @@ class _InvenTreeHomePageState extends State { }); } - // Index of bottom navigation bar - int _tabIndex = 0; - - // Number of outstanding notifications - int _notificationCounter = 0; + final homeKey = GlobalKey(); bool homeShowPo = false; bool homeShowSubscribed = false; @@ -76,8 +70,6 @@ class _InvenTreeHomePageState extends State { bool homeShowCustomers = false; bool homeShowSuppliers = false; - final GlobalKey<_InvenTreeHomePageState> _homeKey = GlobalKey<_InvenTreeHomePageState>(); - // Selected user profile UserProfile? _profile; @@ -202,10 +194,10 @@ class _InvenTreeHomePageState extends State { return; } - final notifications = await InvenTreeNotification().list(); + // final notifications = await InvenTreeNotification().list(); setState(() { - _notificationCounter = notifications.length; + // _notificationCounter = notifications.length; }); } @@ -416,78 +408,17 @@ class _InvenTreeHomePageState extends State { * Return the main body widget for display. * This depends on the current value of _tabIndex */ + @override Widget getBody(BuildContext context) { if (!InvenTreeAPI().isConnected()) { return _connectionStatusWidget(context); } - switch (_tabIndex) { - case 1: // Search widget - return SearchWidget(false); - case 2: // Notification widget - return NotificationWidget(); - case 0: // Home widget - default: - return ListView( - scrollDirection: Axis.vertical, - children: getListTiles(context), - ); - } - } - - /* - * Construct the bottom navigation bar - */ - List getNavBarItems(BuildContext context) { - - List items = [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.house), - label: L10().home, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.magnifyingGlass), - label: L10().search, - ), - ]; - - if (InvenTreeAPI().supportsNotifications) { - items.add( - BottomNavigationBarItem( - icon: _notificationCounter == 0 ? FaIcon(FontAwesomeIcons.bell) : Stack( - children: [ - FaIcon(FontAwesomeIcons.bell), - Positioned( - right: 0, - child: Container( - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(20), - ), - constraints: BoxConstraints( - minWidth: 12, - minHeight: 12, - ), - child: Text( - "${_notificationCounter}", - style: TextStyle( - color: Colors.white, - fontSize: 9, - ), - textAlign: TextAlign.center, - ), - ), - ) - ], - ), - label: L10().notifications, - ) - ); - } - - return items; + return ListView( + scrollDirection: Axis.vertical, + children: getListTiles(context), + ); } @override @@ -497,7 +428,7 @@ class _InvenTreeHomePageState extends State { var connecting = !connected && InvenTreeAPI().isConnecting(); return Scaffold( - key: _homeKey, + key: homeKey, appBar: AppBar( title: Text(L10().appTitle), actions: [ @@ -512,17 +443,7 @@ class _InvenTreeHomePageState extends State { ), drawer: InvenTreeDrawer(context), body: getBody(context), - bottomNavigationBar: connected ? BottomNavigationBar( - currentIndex: _tabIndex, - onTap: (int index) { - setState(() { - _tabIndex = index; - }); - - _refreshNotifications(); - }, - items: getNavBarItems(context), - ) : null, + bottomNavigationBar: InvenTreeAPI().isConnected() ? buildBottomAppBar(context, homeKey) : null, ); } } diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 7adcc45..f5518a3 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -40,35 +41,96 @@ class _LocationDisplayState extends RefreshableState { bool showFilterOptions = false; @override - String getAppBarTitle(BuildContext context) { return L10().stockLocation; } + String getAppBarTitle() { + return L10().stockLocation; + } @override - List getAppBarActions(BuildContext context) { - + List appBarActions(BuildContext context) { List actions = []; - if (location != null) { - - // Add "locate" button - if (api.supportsMixin("locate")) { - actions.add( + // Add "locate" button + if (location != null && api.supportsMixin("locate")) { + actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), - tooltip: L10().locateLocation, - onPressed: () async { - _locateStockLocation(context); - }, + icon: Icon(Icons.travel_explore), + tooltip: L10().locateLocation, + onPressed: () async { + api.locateItemOrLocation(context, location: location!.pk); + } ) + ); + } + + // Add "edit" button + if (location != null && api.checkPermission("stock_location", "change")) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().editLocation, + onPressed: () { + _editLocationDialog(context); + } + ) + ); + } + + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (location != null) { + // Scan items into this location + if (api.checkPermission("stock", "change")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.qrcode), + label: L10().barcodeScanItem, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => + InvenTreeQRView( + StockLocationScanInItemsHandler(location!))) + ).then((value) { + refresh(context); + }); + } + ) ); } - // Add "edit" button + // Scan this location into another one if (api.checkPermission("stock_location", "change")) { actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { _editLocationDialog(context); }, + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.qrcode), + label: L10().transferStockLocation, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => + InvenTreeQRView( + ScanParentLocationHandler(location!))) + ).then((value) { + refresh(context); + }); + } + ) + ); + } + + // Assign or un-assign barcodes + if (api.supportModernBarcodes) { + actions.add( + customBarcodeAction( + context, this, + location!.customBarcode, "stocklocation", + location!.pk ) ); } @@ -77,23 +139,43 @@ class _LocationDisplayState extends RefreshableState { return actions; } - /* - * Request identification of this location - */ - Future _locateStockLocation(BuildContext context) async { + @override + List actionButtons(BuildContext context) { + List actions = []; - final _loc = location; - - if (_loc != null) { - api.locateItemOrLocation(context, location: _loc.pk); + // Create new location + if (api.checkPermission("stock_location", "add")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.sitemap), + label: L10().locationCreate, + onTap: () async { + _newLocation(context); + } + ) + ); } + + // Create new item + if (location != null && api.checkPermission("stock", "add")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.boxesStacked), + label: L10().stockItemCreate, + onTap: () async { + _newStockItem(context); + } + ) + ); + } + + return actions; } /* * Launch a dialog form to edit this stock location */ void _editLocationDialog(BuildContext context) { - final _loc = location; if (_loc == null) { @@ -101,12 +183,12 @@ class _LocationDisplayState extends RefreshableState { } _loc.editForm( - context, - L10().editLocation, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().locationUpdated, success: true); - } + context, + L10().editLocation, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().locationUpdated, success: true); + } ); } @@ -117,7 +199,6 @@ class _LocationDisplayState extends RefreshableState { @override Future request(BuildContext context) async { - // Reload location information if (location != null) { final bool result = await location!.reload(); @@ -133,35 +214,32 @@ class _LocationDisplayState extends RefreshableState { } Future _newLocation(BuildContext context) async { - int pk = location?.pk ?? -1; InvenTreeStockLocation().createForm( - context, - L10().locationCreate, - data: { - "parent": (pk > 0) ? pk : null, - }, - onSuccess: (result) async { + context, + L10().locationCreate, + data: { + "parent": (pk > 0) ? pk : null, + }, + onSuccess: (result) async { + Map data = result as Map; - Map data = result as Map; + if (data.containsKey("pk")) { + var loc = InvenTreeStockLocation.fromJson(data); - if (data.containsKey("pk")) { - var loc = InvenTreeStockLocation.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc) - ) - ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationDisplayWidget(loc) + ) + ); + } } - } ); } Future _newStockItem(BuildContext context) async { - int pk = location?.pk ?? -1; if (location != null && pk <= 0) { @@ -169,48 +247,46 @@ class _LocationDisplayState extends RefreshableState { } InvenTreeStockItem().createForm( - context, - L10().stockItemCreate, - data: { - "location": location != null ? pk : null, - }, - onSuccess: (result) async { + context, + L10().stockItemCreate, + data: { + "location": location != null ? pk : null, + }, + onSuccess: (result) async { + Map data = result as Map; - Map data = result as Map; + if (data.containsKey("pk")) { + var item = InvenTreeStockItem.fromJson(data); - if (data.containsKey("pk")) { - var item = InvenTreeStockItem.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockDetailWidget(item) - ) - ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockDetailWidget(item) + ) + ); + } } - } ); - } Widget locationDescriptionCard({bool includeActions = true}) { if (location == null) { return Card( - child: ListTile( - title: Text( - L10().stockTopLevel, - style: TextStyle(fontStyle: FontStyle.italic) - ), - leading: FaIcon(FontAwesomeIcons.boxesStacked), - ) + child: ListTile( + title: Text( + L10().stockTopLevel, + style: TextStyle(fontStyle: FontStyle.italic) + ), + leading: FaIcon(FontAwesomeIcons.boxesStacked), + ) ); } else { - List children = [ ListTile( title: Text("${location!.name}"), subtitle: Text("${location!.description}"), - leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxesStacked), + leading: location!.customIcon ?? + FaIcon(FontAwesomeIcons.boxesStacked), ), ]; @@ -221,19 +297,19 @@ class _LocationDisplayState extends RefreshableState { subtitle: Text("${location!.parentPathString}"), leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_CLICK), onTap: () async { - int parentId = location?.parentId ?? -1; if (parentId < 0) { - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); + Navigator.push(context, MaterialPageRoute( + builder: (context) => LocationDisplayWidget(null))); } else { - showLoadingOverlay(context); var loc = await InvenTreeStockLocation().get(parentId); hideLoadingOverlay(); if (loc is InvenTreeStockLocation) { - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); + Navigator.push(context, MaterialPageRoute( + builder: (context) => LocationDisplayWidget(loc))); } } }, @@ -242,63 +318,27 @@ class _LocationDisplayState extends RefreshableState { } return Card( - child: Column( - children: children, - ) + child: Column( + children: children, + ) ); } } @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.sitemap), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxesStacked), - label: L10().stock, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions, - ) - ] - ); - } - - int stockItemCount = 0; - - Widget getSelectedWidget(int index) { - - switch (index) { - case 0: - return Column( - children: detailTiles(), - ); - case 1: - return Column( - children: stockTiles(), - ); - case 2: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: actionTiles() - ).toList() - ); - default: - return ListView(); - } + List getTabIcons(BuildContext context) { + return [ + Tab(text: L10().details), + Tab(text: L10().stockItems), + ]; } @override - Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); + List getTabs(BuildContext context) { + return [ + Column(children: detailTiles()), + Column(children: stockTiles()), + ]; } // Construct the "details" panel @@ -306,18 +346,18 @@ class _LocationDisplayState extends RefreshableState { List tiles = [ locationDescriptionCard(), ListTile( - title: Text( - L10().sublocations, - style: TextStyle(fontWeight: FontWeight.bold), - ), - trailing: GestureDetector( - child: FaIcon(FontAwesomeIcons.filter), - onTap: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) + title: Text( + L10().sublocations, + style: TextStyle(fontWeight: FontWeight.bold), + ), + trailing: GestureDetector( + child: FaIcon(FontAwesomeIcons.filter), + onTap: () async { + setState(() { + showFilterOptions = !showFilterOptions; + }); + }, + ) ), Expanded( child: PaginatedStockLocationList( @@ -335,13 +375,11 @@ class _LocationDisplayState extends RefreshableState { // Construct the "stock" panel List stockTiles() { - Map filters = { "location": location?.pk.toString() ?? "null", }; return [ - locationDescriptionCard(includeActions: false), ListTile( title: Text( L10().stock, @@ -365,115 +403,4 @@ class _LocationDisplayState extends RefreshableState { ) ]; } - - List actionTiles() { - List tiles = []; - - tiles.add(locationDescriptionCard(includeActions: false)); - - if (api.checkPermission("stock", "add")) { - - tiles.add( - ListTile( - title: Text(L10().locationCreate), - subtitle: Text(L10().locationCreateDetail), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), - onTap: () async { - _newLocation(context); - }, - ) - ); - - tiles.add( - ListTile( - title: Text(L10().stockItemCreate), - subtitle: Text(L10().stockItemCreateDetail), - leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), - onTap: () async { - _newStockItem(context); - }, - ) - ); - - } - - if (location != null) { - - // Scan stock item into location - if (api.checkPermission("stock", "change")) { - tiles.add( - ListTile( - title: Text(L10().barcodeScanItem), - subtitle: Text(L10().barcodeScanInItems), - leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code, color: COLOR_CLICK), - onTap: () { - - var _loc = location; - - if (_loc != null) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - InvenTreeQRView( - StockLocationScanInItemsHandler(_loc))) - ).then((value) { - refresh(context); - }); - } - }, - ) - ); - - // Scan this location into another one - if (api.checkPermission("stock_location", "change")) { - tiles.add( - ListTile( - title: Text(L10().transferStockLocation), - subtitle: Text(L10().transferStockLocationDetail), - leading: FaIcon(FontAwesomeIcons.rightToBracket, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code, color: COLOR_CLICK), - onTap: () { - var _loc = location; - - if (_loc != null) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - InvenTreeQRView( - ScanParentLocationHandler(_loc))) - ).then((value) { - refresh(context); - }); - } - } - ) - ); - } - - if (api.supportModernBarcodes) { - tiles.add( - customBarcodeActionTile(context, this, location!.customBarcode, "stocklocation", location!.pk) - ); - } - } - } - - if (tiles.length <= 1) { - tiles.add( - ListTile( - title: Text( - L10().actionsNone, - style: TextStyle( - fontStyle: FontStyle.italic - ), - ) - ) - ); - } - - return tiles; - } } diff --git a/lib/widget/location_list.dart b/lib/widget/location_list.dart index d2762fb..73c992e 100644 --- a/lib/widget/location_list.dart +++ b/lib/widget/location_list.dart @@ -30,7 +30,7 @@ class _StockLocationListState extends RefreshableState { bool showFilterOptions = false; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { @@ -42,7 +42,7 @@ class _StockLocationListState extends RefreshableState { ]; @override - String getAppBarTitle(BuildContext context) => L10().stockLocations; + String getAppBarTitle() => L10().stockLocations; @override Widget getBody(BuildContext context) { diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 23b8bd6..6b37d83 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -24,10 +24,7 @@ class _NotificationState extends RefreshableState { List notifications = []; @override - AppBar? buildAppBar(BuildContext context, GlobalKey key) { - // No app bar for the notification widget - return null; - } + String getAppBarTitle() => L10().notifications; @override Future request (BuildContext context) async { diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 86b76c1..77f70f5 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -409,19 +409,21 @@ abstract class PaginatedSearchState extends Sta */ Widget buildSearchInput(BuildContext context) { return ListTile( - leading: orderingOptions.isEmpty ? null : GestureDetector( + trailing: orderingOptions.isEmpty ? null : GestureDetector( child: FaIcon(FontAwesomeIcons.sort, color: COLOR_CLICK), onTap: () async { _saveOrderingOptions(context); }, ), - trailing: GestureDetector( + leading: GestureDetector( child: FaIcon( searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, - color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK, + color: searchController.text.isNotEmpty ? COLOR_DANGER : null, ), onTap: () { - searchController.clear(); + if (searchController.text.isEmpty) { + searchController.clear(); + } updateSearchTerm(); }, ), diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index b410a27..be397dc 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -65,39 +66,62 @@ class _PartDisplayState extends RefreshableState { int variantCount = 0; @override - String getAppBarTitle(BuildContext context) => L10().partDetails; + String getAppBarTitle() => L10().partDetails; @override - List getAppBarActions(BuildContext context) { - + List appBarActions(BuildContext context) { List actions = []; - if (api.checkPermission("part", "view")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: _openInvenTreePage, - ), - ); - } - if (api.checkPermission("part", "change")) { actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { - _editPartDialog(context); - }, - ) + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().editPart, + onPressed: () { + _editPartDialog(context); + } + ) ); } + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("part", "change")) { + if (api.supportModernBarcodes) { + actions.add( + customBarcodeAction( + context, this, + widget.part.customBarcode, "part", + widget.part.pk + ) + ); + } + } return actions; } - Future _openInvenTreePage() async { - part.goToInvenTreePage(); + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("stock", "add")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.box), + label: L10().stockItemCreate, + onTap: () { + _newStockItem(context); + } + ) + ); + } + + return actions; } @override @@ -144,20 +168,9 @@ class _PartDisplayState extends RefreshableState { // Request the number of parameters for this part if (api.supportsPartParameters) { - showParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; - - InvenTreePartParameter().count( - filters: { - "part": part.pk.toString(), - } - ).then((int value) { - if (mounted) { - setState(() { - parameterCount = value; - }); - } - }); + } else { + showParameters = false; } // Request the number of attachments @@ -394,18 +407,13 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), - leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.boxesStacked), trailing: Text( part.stockString(), style: TextStyle( fontWeight: FontWeight.bold, ), ), - onTap: () { - setState(() { - tabIndex = 1; - }); - }, ), ); @@ -436,14 +444,6 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().billOfMaterials), leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), trailing: Text(bomCount.toString()), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => BillOfMaterialsWidget(part) - ) - ); - } ) ); } @@ -543,24 +543,6 @@ class _PartDisplayState extends RefreshableState { } } - if (showParameters) { - tiles.add( - ListTile( - title: Text(L10().parameters), - leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), - trailing: parameterCount > 0 ? Text(parameterCount.toString()) : null, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartParameterWidget(part) - ) - ); - } - ) - ); - } - // Notes field tiles.add( ListTile( @@ -682,89 +664,49 @@ class _PartDisplayState extends RefreshableState { } } ); - - } - - List actionTiles(BuildContext context) { - List tiles = []; - - tiles.add(headerTile()); - - tiles.add( - ListTile( - title: Text(L10().stockItemCreate), - leading: FaIcon(FontAwesomeIcons.box), - onTap: () { - _newStockItem(context); - }, - ) - ); - - if (api.supportModernBarcodes) { - tiles.add( - customBarcodeActionTile(context, this, part.customBarcode, "part", part.pk) - ); - } - - return tiles; - } - - int stockItemCount = 0; - - Widget getSelectedWidget(int index) { - switch (index) { - case 0: - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: partTiles() - ).toList() - ), - ); - case 1: - return PaginatedStockItemList( - {"part": "${part.pk}"}, - true, - ); - case 2: - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: actionTiles(context) - ).toList() - ) - ); - default: - return Center(); - } } @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.circleInfo), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxesStacked), - label: L10().stock - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions, - ), - ] - ); + List getTabIcons(BuildContext context) { + List icons = [ + Tab(text: L10().details), + Tab(text: L10().stock) + ]; + + if (showBom && part.isAssembly) { + icons.add(Tab(text: L10().bom)); + } + + if (showParameters) { + icons.add(Tab(text: L10().parameters)); + } + + return icons; } @override - Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); + List getTabs(BuildContext context) { + List tabs = [ + Center( + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: partTiles() + ).toList() + ) + ), + PaginatedStockItemList({"part": part.pk.toString()}, true) + ]; + + if (showBom && part.isAssembly) { + tabs.add(PaginatedBomList({"part": part.pk.toString()}, showSearch: true, isParentPart: true)); + } + + if (showParameters) { + tabs.add(PaginatedParameterList({"part": part.pk.toString()}, true)); + } + + return tabs; } + } diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart index fc4d0b9..c548e8e 100644 --- a/lib/widget/part_image_widget.dart +++ b/lib/widget/part_image_widget.dart @@ -35,10 +35,10 @@ class _PartImageState extends RefreshableState { } @override - String getAppBarTitle(BuildContext context) => part.fullname; + String getAppBarTitle() => part.fullname; @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { List actions = []; diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 4e2646b..b6b7bc5 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -36,10 +36,10 @@ class _PartListState extends RefreshableState { bool showFilterOptions = false; @override - String getAppBarTitle(BuildContext context) => title.isNotEmpty ? title : L10().parts; + String getAppBarTitle() => title.isNotEmpty ? title : L10().parts; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { diff --git a/lib/widget/part_notes.dart b/lib/widget/part_notes.dart index 32bffe9..15b9ee7 100644 --- a/lib/widget/part_notes.dart +++ b/lib/widget/part_notes.dart @@ -30,10 +30,10 @@ class _PartNotesState extends RefreshableState { } @override - String getAppBarTitle(BuildContext context) => L10().partNotes; + String getAppBarTitle() => L10().partNotes; @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { List actions = []; diff --git a/lib/widget/part_parameter_widget.dart b/lib/widget/part_parameter_widget.dart index 50e8d8d..1adc523 100644 --- a/lib/widget/part_parameter_widget.dart +++ b/lib/widget/part_parameter_widget.dart @@ -24,12 +24,12 @@ class _ParameterWidgetState extends RefreshableState { _ParameterWidgetState(); @override - String getAppBarTitle(BuildContext context) { + String getAppBarTitle() { return L10().parameters; } @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { return []; } diff --git a/lib/widget/part_suppliers.dart b/lib/widget/part_suppliers.dart index 9b1a278..36b3900 100644 --- a/lib/widget/part_suppliers.dart +++ b/lib/widget/part_suppliers.dart @@ -38,10 +38,10 @@ class _PartSupplierState extends RefreshableState { } @override - String getAppBarTitle(BuildContext context) => L10().partSuppliers; + String getAppBarTitle() => L10().partSuppliers; @override - List getAppBarActions(BuildContext contexts) { + List appBarActions(BuildContext contexts) { // TODO return []; } diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index fa1ecb1..f70d09a 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; - import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:one_context/one_context.dart"; @@ -7,12 +6,13 @@ import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; + import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/company_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/l10.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_list.dart"; @@ -41,17 +41,17 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; + String getAppBarTitle() => L10().purchaseOrder; @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { List actions = []; if (InvenTreeAPI().checkPermission("purchase_order", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, + icon: Icon(Icons.edit_square), + tooltip: L10().purchaseOrderEdit, onPressed: () { editOrder(context); } @@ -145,12 +145,6 @@ class _PurchaseOrderDetailState extends RefreshableState getTabIcons(BuildContext context) { + return [ + Tab(text: L10().details), + Tab(text: L10().lineItems), + Tab(text: L10().received) + ]; } - - Widget getSelectedWidget(BuildContext context, int index) { - switch (index) { - case 0: - return ListView( - children: orderTiles(context) - ); - case 1: - return ListView( - children: lineTiles(context) - ); - case 2: - // Stock items received against this order - Map filters = { - "purchase_order": "${order.pk}" - }; - - return PaginatedStockItemList(filters, true); - - default: - return ListView(); - } - } - + @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.circleInfo), - label: L10().details - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.tableList), - label: L10().lineItems, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxesStacked), - label: L10().stockItems - ) - ], - ); + List getTabs(BuildContext context) { + return [ + ListView(children: orderTiles(context)), + ListView(children: lineTiles(context)), + PaginatedStockItemList({"purchase_order": order.pk.toString()}, true), + ]; } } \ No newline at end of file diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index 57309c9..5b9546a 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -33,10 +33,10 @@ class _PurchaseOrderListWidgetState extends RefreshableState L10().purchaseOrders; + String getAppBarTitle() => L10().purchaseOrders; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 184d8b5..1bd1fb3 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -1,9 +1,12 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:inventree/api.dart"; +import "package:inventree/barcode.dart"; import "package:inventree/widget/back.dart"; import "package:inventree/widget/drawer.dart"; +import "package:inventree/widget/search.dart"; /* @@ -11,17 +14,22 @@ import "package:inventree/widget/drawer.dart"; */ mixin BaseWidgetProperties { - // Return a list of appBar actions (default = None) - List getAppBarActions(BuildContext context) => []; + /* + * Return a list of appBar actions + * By default, no appBar actions are available + */ + List appBarActions(BuildContext context) => []; // Return a title for the appBar - String getAppBarTitle(BuildContext context) { return "--- app bar ---"; } + String getAppBarTitle() { return "--- app bar ---"; } // Function to construct a drawer (override if needed) Widget getDrawer(BuildContext context) { return InvenTreeDrawer(context); } + List getTabs(BuildContext context) => []; + // Function to construct a body (MUST BE PROVIDED) Widget getBody(BuildContext context) { @@ -29,18 +37,145 @@ mixin BaseWidgetProperties { return ListView(); } - Widget? getBottomNavBar(BuildContext context) { - return null; - } + /* + * Construct the top AppBar for this view + */ AppBar? buildAppBar(BuildContext context, GlobalKey key) { + + List tabs = getTabIcons(context); + return AppBar( - title: Text(getAppBarTitle(context)), - actions: getAppBarActions(context), + centerTitle: false, + bottom: tabs.isEmpty ? null : TabBar(tabs: tabs), + title: Text(getAppBarTitle()), + actions: appBarActions(context), leading: backButton(context, key), ); } + /* + * Construct a global navigation bar at the bottom of the screen + * - Button to access navigation menu + * - Button to access global search + * - Button to access barcode scan + */ + BottomAppBar? buildBottomAppBar(BuildContext context, GlobalKey key) { + + const double iconSize = 32; + const Color iconColor = Colors.blueGrey; + + List icons = [ + IconButton( + icon: Icon(Icons.menu, color: iconColor), + iconSize: iconSize, + onPressed: () { + if (key.currentState != null) { + key.currentState!.openDrawer(); + } + }, + ), + IconButton( + icon: Icon(Icons.search, color: iconColor), + iconSize: iconSize, + onPressed: () { + if (InvenTreeAPI().checkConnection()) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SearchWidget(true) + ) + ); + } + }, + ), + IconButton( + icon: Icon(Icons.qr_code_scanner, color: iconColor), + iconSize: iconSize, + onPressed: () { + if (InvenTreeAPI().checkConnection()) { + scanQrCode(context); + } + }, + ) + ]; + + return BottomAppBar( + shape: CircularNotchedRectangle(), + notchMargin: 20, + child: IconTheme( + data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: icons, + ) + ) + ); + } + + /* + * Build out a set of SpeedDialChild widgets, to serve as "actions" for this view + * Should be re-implemented by particular view with the required actions + * By default, returns an empty list, and thus nothing will be rendered + */ + List actionButtons(BuildContext context) => []; + + /* + * Build out a set of barcode actions available for this view + */ + List barcodeButtons(BuildContext context) => []; + + /* + * Build out action buttons for a given widget + */ + Widget? buildSpeedDial(BuildContext context) { + + final actions = actionButtons(context); + final barcodeActions = barcodeButtons(context); + + if (actions.isEmpty && barcodeActions.isEmpty) { + return null; + } + + List children = []; + + if (barcodeActions.isNotEmpty) { + children.add( + SpeedDial( + icon: Icons.qr_code_scanner, + activeIcon: Icons.close, + children: barcodeActions, + spacing: 14, + childPadding: const EdgeInsets.all(5), + spaceBetweenChildren: 15, + ) + ); + } + + if (actions.isNotEmpty) { + children.add( + SpeedDial( + icon: Icons.more_horiz, + activeIcon: Icons.close, + children: actions, + spacing: 14, + childPadding: const EdgeInsets.all(5), + spaceBetweenChildren: 15, + ) + ); + } + + return Wrap( + direction: Axis.horizontal, + children: children, + spacing: 15, + ); + } + + // Return list of "tabs" for this widget + List getTabIcons(BuildContext context) => []; + } @@ -57,9 +192,6 @@ abstract class RefreshableState extends State with // Storage for context once "Build" is called late BuildContext? _context; - // Current tab index (used for widgets which display bottom tabs) - int tabIndex = 0; - // Bool indicator bool loading = false; @@ -68,16 +200,6 @@ abstract class RefreshableState extends State with // Helper function to return API instance InvenTreeAPI get api => InvenTreeAPI(); - // Update current tab selection - void onTabSelectionChanged(int index) { - - if (mounted) { - setState(() { - tabIndex = index; - }); - } - } - @override void initState() { super.initState(); @@ -124,21 +246,38 @@ abstract class RefreshableState extends State with // Save the context for future use _context = context; - return Scaffold( + List tabs = getTabIcons(context); + + Widget body = tabs.isEmpty ? getBody(context) : TabBarView(children: getTabs(context)); + + Scaffold view = Scaffold( key: refreshableKey, appBar: buildAppBar(context, refreshableKey), drawer: getDrawer(context), + floatingActionButton: buildSpeedDial(context), + floatingActionButtonLocation: FloatingActionButtonLocation + .miniEndDocked, body: Builder( - builder: (BuildContext context) { - return RefreshIndicator( - onRefresh: () async { - refresh(context); - }, - child: getBody(context) - ); - } + builder: (BuildContext context) { + return RefreshIndicator( + onRefresh: () async { + refresh(context); + }, + child: body + ); + } ), - bottomNavigationBar: getBottomNavBar(context), + bottomNavigationBar: buildBottomAppBar(context, refreshableKey), ); + + // Default implementation is *not* tabbed + if (tabs.isNotEmpty) { + return DefaultTabController( + length: tabs.length, + child: view, + ); + } else { + return view; + } } } \ No newline at end of file diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 3974143..2f7ddb3 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -54,7 +54,7 @@ class _SearchDisplayState extends RefreshableState { } @override - String getAppBarTitle(BuildContext context) => L10().search; + String getAppBarTitle() => L10().search; @override AppBar? buildAppBar(BuildContext context, GlobalKey key) { diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 950867c..e274608 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -43,42 +44,34 @@ class _StockItemDisplayState extends RefreshableState { _StockItemDisplayState(); @override - String getAppBarTitle(BuildContext context) => L10().stockItem; + String getAppBarTitle() => L10().stockItem; bool stockShowHistory = false; @override - List getAppBarActions(BuildContext context) { - + List appBarActions(BuildContext context) { List actions = []; - if (InvenTreeAPI().checkPermission("stock", "view")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: _openInvenTreePage, - ) - ); - } - - if (InvenTreeAPI().supportsMixin("locate")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), - tooltip: L10().locateItem, - onPressed: () async { - InvenTreeAPI().locateItemOrLocation(context, item: widget.item.pk); - }, - ) - ); - } - - if (InvenTreeAPI().checkPermission("stock", "change")) { + if (api.supportsMixin("locate")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { _editStockItem(context); }, + icon: Icon(Icons.travel_explore), + tooltip: L10().locateItem, + onPressed: () async { + api.locateItemOrLocation(context, item: widget.item.pk); + } + ) + ); + } + + if (api.checkPermission("stock", "change")) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().editItem, + onPressed: () { + _editStockItem(context); + } ) ); } @@ -86,8 +79,115 @@ class _StockItemDisplayState extends RefreshableState { return actions; } - Future _openInvenTreePage() async { - widget.item.goToInvenTreePage(); + @override + List actionButtons(BuildContext context) { + + List actions = []; + + if (api.checkPermission("stock", "change")) { + + // Stock adjustment actions available if item is *not* serialized + if (!widget.item.isSerialized()) { + + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circleCheck, color: Colors.blue), + label: L10().countStock, + onTap: _countStockDialog, + ) + ); + + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circleMinus, color: Colors.red), + label: L10().removeStock, + onTap: _removeStockDialog, + ) + ); + + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus, color: Colors.green), + label: L10().addStock, + onTap: _addStockDialog, + ) + ); + } + + // Transfer item + actions.add( + SpeedDialChild( + child: Icon(Icons.trolley), + label: L10().transferStock, + onTap: () { + _transferStockDialog(context); + } + ) + ); + } + + if (labels.isNotEmpty) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.print), + label: L10().printLabel, + onTap: () { + _printLabel(context); + } + ) + ); + } + + if (api.checkPermission("stock", "delete")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), + label: L10().stockItemDelete, + onTap: () { + _deleteItem(context); + } + ) + ); + } + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("stock", "change")) { + // Scan item into location + actions.add( + SpeedDialChild( + child: Icon(Icons.qr_code_scanner), + label: L10().scanIntoLocation, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => + InvenTreeQRView( + StockItemScanIntoLocationHandler(widget.item))) + ).then((ctx) { + refresh(context); + }); + } + ) + ); + + if (api.supportModernBarcodes) { + actions.add( + customBarcodeAction( + context, this, + widget.item.customBarcode, + "stockitem", widget.item.pk + ) + ); + } + } + + return actions; } // Is label printing enabled for this StockItem? @@ -740,170 +840,13 @@ class _StockItemDisplayState extends RefreshableState { return tiles; } - List actionTiles(BuildContext context) { - List tiles = []; - - tiles.add(headerTile()); - - // First check that the user has the required permissions to adjust stock - if (!InvenTreeAPI().checkPermission("stock", "change")) { - tiles.add( - ListTile( - title: Text(L10().permissionRequired), - leading: FaIcon(FontAwesomeIcons.userXmark) - ) - ); - - tiles.add( - ListTile( - subtitle: Text(L10().permissionAccountDenied), - ) - ); - - return tiles; - } - - // "Count" is not available for serialized stock - if (!widget.item.isSerialized()) { - tiles.add( - ListTile( - title: Text(L10().countStock), - leading: FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_CLICK), - onTap: _countStockDialog, - trailing: Text(widget.item.quantityString(includeUnits: true)), - ) - ); - - tiles.add( - ListTile( - title: Text(L10().removeStock), - leading: FaIcon(FontAwesomeIcons.circleMinus, color: COLOR_CLICK), - onTap: _removeStockDialog, - ) - ); - - tiles.add( - ListTile( - title: Text(L10().addStock), - leading: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), - onTap: _addStockDialog, - ) - ); - } - - tiles.add( - ListTile( - title: Text(L10().transferStock), - subtitle: Text(L10().transferStockDetail), - leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), - onTap: () { _transferStockDialog(context); }, - ) - ); - - // Scan item into a location - tiles.add( - ListTile( - title: Text(L10().scanIntoLocation), - subtitle: Text(L10().scanIntoLocationDetail), - leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code_scanner), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(StockItemScanIntoLocationHandler(widget.item))) - ).then((ctx) { - refresh(context); - }); - }, - ) - ); - - if (InvenTreeAPI().supportModernBarcodes || widget.item.customBarcode.isEmpty) { - tiles.add(customBarcodeActionTile(context, this, widget.item.customBarcode, "stockitem", widget.item.pk)); - } else { - // Note: Custom legacy barcodes (only for StockItem model) are handled differently - tiles.add( - ListTile( - title: Text(L10().barcodeUnassign), - leading: Icon(Icons.qr_code, color: COLOR_CLICK), - onTap: () async { - await widget.item.update(values: {"uid": ""}); - refresh(context); - } - ) - ); - } - - - // Print label (if label printing plugins exist) - if (labels.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().printLabel), - leading: FaIcon(FontAwesomeIcons.print, color: COLOR_CLICK), - onTap: () { - _printLabel(context); - }, - ), - ); - } - - // If the user has permission to delete this stock item - if (InvenTreeAPI().checkPermission("stock", "delete")) { - tiles.add( - ListTile( - title: Text("Delete Stock Item"), - leading: FaIcon(FontAwesomeIcons.trashCan, color: COLOR_DANGER), - onTap: () { - _deleteItem(context); - }, - ) - ); - } - - return tiles; - } - - @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.circleInfo), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions, ), - ] - ); - } - - Widget getSelectedWidget(int index) { - switch (index) { - case 0: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: detailTiles() - ).toList(), - ); - case 1: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: actionTiles(context) - ).toList() - ); - default: - return ListView(); - } - } - @override Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); + return ListView( + children: ListTile.divideTiles( + context: context, + tiles: detailTiles() + ).toList() + ); } } \ No newline at end of file diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index c2284c0..b03263f 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -24,7 +24,7 @@ class _StockItemHistoryDisplayState extends RefreshableState L10().stockItemHistory; + String getAppBarTitle() => L10().stockItemHistory; List history = []; diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index 3d602a9..817e7c3 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -28,10 +28,10 @@ class _StockItemTestResultDisplayState extends RefreshableState L10().testResults; + String getAppBarTitle() => L10().testResults; @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { return [ IconButton( icon: FaIcon(FontAwesomeIcons.circlePlus), diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index 41c95f6..70c3928 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -30,10 +30,10 @@ class _StockListState extends RefreshableState { bool showFilterOptions = false; @override - String getAppBarTitle(BuildContext context) => L10().stockItems; + String getAppBarTitle() => L10().stockItems; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { diff --git a/lib/widget/stock_notes.dart b/lib/widget/stock_notes.dart index 82e5684..c990d0e 100644 --- a/lib/widget/stock_notes.dart +++ b/lib/widget/stock_notes.dart @@ -27,7 +27,7 @@ class _StockNotesState extends RefreshableState { final InvenTreeStockItem item; @override - String getAppBarTitle(BuildContext context) => L10().stockItemNotes; + String getAppBarTitle() => L10().stockItemNotes; @override Future request(BuildContext context) async { @@ -37,7 +37,7 @@ class _StockNotesState extends RefreshableState { } @override - List getAppBarActions(BuildContext context) { + List appBarActions(BuildContext context) { List actions = []; if (InvenTreeAPI().checkPermission("stock", "change")) { diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index a295658..9435e64 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; @@ -35,39 +36,64 @@ class _SupplierPartDisplayState extends RefreshableState L10().supplierPart; - - @override - List getAppBarActions(BuildContext context) { - List actions = []; - - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { - editSupplierPart(context); - }, - ) - ); - - return actions; - } + String getAppBarTitle() => L10().supplierPart; /* * Launch a form to edit the current SupplierPart instance */ Future editSupplierPart(BuildContext context) async { widget.supplierPart.editForm( - context, - L10().supplierPartEdit, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().supplierPartUpdated, success: true); - } + context, + L10().supplierPartEdit, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().supplierPartUpdated, success: true); + } ); } + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("purchase_order", "change") || + api.checkPermission("sales_order", "change") || + api.checkPermission("return_order", "change")) { + + actions.add( + customBarcodeAction( + context, this, + widget.supplierPart.customBarcode, + "supplierpart", + widget.supplierPart.pk + ) + ); + } + + return actions; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (api.checkPermission("purchase_order", "change") || + api.checkPermission("sales_order", "change") || + api.checkPermission("return_order", "change")) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().edit, + onPressed: () { + editSupplierPart(context); + } + ) + ); + } + + return actions; + } + @override Future request(BuildContext context) async { final bool result = widget.supplierPart.pk > 0 && await widget.supplierPart.reload(); @@ -179,60 +205,14 @@ class _SupplierPartDisplayState extends RefreshableState actionTiles(BuildContext context) { - List tiles = []; - - tiles.add( - customBarcodeActionTile(context, this, widget.supplierPart.customBarcode, "supplierpart", widget.supplierPart.pk) - ); - - return tiles; - } - - Widget getSelectedWidget(int index) { - switch (index) { - case 0: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: detailTiles(context), - ).toList() - ); - case 1: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: actionTiles(context) - ).toList() - ); - default: - return ListView(); - } - } - @override Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); - } - - @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.circleInfo), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions - ) - ] + return ListView( + children: ListTile.divideTiles( + context: context, + tiles: detailTiles(context), + ).toList() ); } + } \ No newline at end of file diff --git a/lib/widget/supplier_part_list.dart b/lib/widget/supplier_part_list.dart index 7a7ea8c..a35c8ec 100644 --- a/lib/widget/supplier_part_list.dart +++ b/lib/widget/supplier_part_list.dart @@ -29,12 +29,12 @@ class SupplierPartList extends StatefulWidget { class _SupplierPartListState extends RefreshableState { @override - String getAppBarTitle(BuildContext context) => L10().supplierParts; + String getAppBarTitle() => L10().supplierParts; bool showFilterOptions = false; @override - List getAppBarActions(BuildContext context) => [ + List appBarActions(BuildContext context) => [ IconButton( icon: FaIcon(FontAwesomeIcons.filter), onPressed: () async { diff --git a/pubspec.lock b/pubspec.lock index efea81b..336cbeb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -395,6 +395,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.7" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "41d7ad0bc224248637b3a5e0b9083e912a75445bdb450cf82b8ed06d7af7c61d" + url: "https://pub.dev" + source: hosted + version: "6.2.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index b0fd2da..634682a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,6 +24,7 @@ dependencies: flutter_localized_locales: ^2.0.4 flutter_markdown: ^0.6.13+1 # Rendering markdown flutter_overlay_loader: ^2.0.0 # Overlay screen support + flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation font_awesome_flutter: ^10.3.0 # FontAwesome icon set http: ^0.13.4 image_picker: ^0.8.6+1 # Select or take photos From bf8a65fadf1dc2f10781c8e97cf93973d4f401e3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 9 Apr 2023 00:14:09 +1000 Subject: [PATCH 324/746] Update release notes (#302) --- assets/release_notes.md | 1 + lib/settings/release.dart | 20 +++++++++++++++++--- pubspec.yaml | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 1eed3e4..6a858f7 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ ### 0.11.0 - April 2023 --- +- Major UI updates - [see the documentation](https://docs.inventree.org/en/latest/app/app/) - Adds globally accessible action button for "search" - Adds globally accessible action button for "barcode scan" - Implement context actions using floating actions buttons diff --git a/lib/settings/release.dart b/lib/settings/release.dart index 728a762..6502a90 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -10,6 +10,16 @@ class ReleaseNotesWidget extends StatelessWidget { final String releaseNotes; + // Callback function when a link is clicked in the markdown + Future openLink(String url) async { + + final link = Uri.parse(url); + + if (await canLaunchUrl(link)) { + await launchUrl(link); + } + } + @override Widget build (BuildContext context) { return Scaffold( @@ -19,6 +29,12 @@ class ReleaseNotesWidget extends StatelessWidget { body: Markdown( selectable: false, data: releaseNotes, + onTapLink: (url, href, title) { + var link = href ?? ""; + if (link.isNotEmpty) { + openLink(link); + } + }, ) ); } @@ -31,9 +47,7 @@ class CreditsWidget extends StatelessWidget { final String credits; - /* - * Callback function when a link is clicked in the markdown - */ + // Callback function when a link is clicked in the markdown Future openLink(String url) async { final link = Uri.parse(url); diff --git a/pubspec.yaml b/pubspec.yaml index 634682a..7f8eae9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.10.2+57 +version: 0.11.0+58 environment: sdk: ">=2.16.0 <3.0.0" From 8631fedbfb57b02eaae6c52ac13821d7ca59afb9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 10 Apr 2023 16:23:22 +1000 Subject: [PATCH 325/746] New translations app_en.arb (French) (#304) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 3db29ce..6888679 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -803,6 +803,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", "@tokenMissingFromResponse": {}, + "totalPrice": "Prix total", + "@totalPrice": {}, "transfer": "Transfert", "@transfer": { "description": "transfer" From 020cc4497c1f450304682346c940dab85d6e3682 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 10 Apr 2023 16:59:45 +1000 Subject: [PATCH 326/746] PO Contact (#305) * Bug fix in API forms - Allow form fields to specify custom filters at runtime * Add "contact" model to purchase order edit form * Add action to create new purchase order from list widget * widget updates for purchase order --- lib/api.dart | 3 ++ lib/api_form.dart | 20 ++++++++---- lib/inventree/purchase_order.dart | 10 ++++++ lib/l10n/app_en.arb | 3 ++ lib/widget/purchase_order_detail.dart | 23 ++++++-------- lib/widget/purchase_order_list.dart | 46 +++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index f0fdc83..3e14777 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -285,6 +285,9 @@ class InvenTreeAPI { // ReturnOrder supports API v104 or newer bool get supportsReturnOrders => isConnected() && apiVersion >= 104; + // "Contact" model exposed to API + bool get supportsContactModel => isConnected() && apiVersion >= 104; + // Status label endpoints API v105 or newer bool get supportsStatusLabelEndpoints => isConnected() && apiVersion >= 105; diff --git a/lib/api_form.dart b/lib/api_form.dart index 360617a..341d740 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -523,18 +523,17 @@ class APIFormField { ), selectedItem: initial_data, asyncItems: (String filter) async { - Map filters = {}; + Map _filters = {}; filters.forEach((key, value) { - filters[key] = value; + _filters[key] = value; }); - filters["search"] = filter; - filters["offset"] = "0"; - filters["limit"] = "25"; + _filters["search"] = filter; + _filters["offset"] = "0"; + _filters["limit"] = "25"; - final APIResponse response = - await InvenTreeAPI().get(api_url, params: filters); + final APIResponse response = await InvenTreeAPI().get(api_url, params: _filters); if (response.isValid()) { List results = []; @@ -650,6 +649,13 @@ class APIFormField { title: Text(name), leading: FaIcon(isGroup ? FontAwesomeIcons.users : FontAwesomeIcons.user), ); + case "contact": + String name = (data["name"] ?? "") as String; + String role = (data["role"] ?? "") as String; + return ListTile( + title: Text(name), + subtitle: Text(role), + ); case "company": var company = InvenTreeCompany.fromJson(data); return ListTile( diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 2194328..23f5819 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -26,11 +26,21 @@ class InvenTreePurchaseOrder extends InvenTreeModel { Map formFields() { return { "reference": {}, + "supplier": { + "filters": { + "is_supplier": true, + }, + }, "supplier_reference": {}, "description": {}, "target_date": {}, "link": {}, "responsible": {}, + "contact": { + "filters": { + "company": supplierId, + } + }, }; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f01d253..b189554 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -726,6 +726,9 @@ "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index f70d09a..77337ef 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -83,11 +83,19 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { + var fields = order.formFields(); + fields.remove("supplier"); + + if (!api.supportsContactModel) { + fields.remove("contact"); + } order.editForm( context, L10().purchaseOrderEdit, + fields: fields, onSuccess: (data) async { refresh(context); showSnackIcon(L10().purchaseOrderUpdated, success: true); @@ -143,8 +151,8 @@ class _PurchaseOrderDetailState extends RefreshableState tiles = []; - tiles.add(headerTile(context)); - for (var line in lines) { InvenTreeSupplierPart? supplierPart = line.supplierPart; @@ -347,9 +347,6 @@ class _PurchaseOrderDetailState extends RefreshableState actionButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("purchase_order", "add")) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus), + label: L10().purchaseOrderCreate, + onTap: () { + createPurchaseOrder(context); + } + ) + ); + } + + return actions; + } + + Future createPurchaseOrder(BuildContext context) async { + var fields = InvenTreePurchaseOrder().formFields(); + + fields.remove("contact"); + + InvenTreePurchaseOrder().createForm( + context, + L10().purchaseOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var order = InvenTreePurchaseOrder.fromJson(data); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderDetailWidget(order) + ) + ); + } + } + ); + } + @override Widget getBody(BuildContext context) { return PaginatedPurchaseOrderList(filters, showFilterOptions); From efb7ff4170a0a3915746357cb0fccc7b08756d85 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 10 Apr 2023 17:07:06 +1000 Subject: [PATCH 327/746] Keyboard fix (#306) * Remove focusNode in search widget - Was causing some issues in iOS in particular * Improve search UX by cancelling previous query - Prevent successive search queries from being displayed * Update release notes * Add "type" for cancelable operation --- assets/release_notes.md | 7 +++ lib/widget/search.dart | 94 +++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 6a858f7..5b638d9 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,13 @@ ## InvenTree App Release Notes --- +### 0.11.1 - April 2023 +--- + +- Fixes keyboard bug in search widget +- Adds ability to create new purchase orders directly from the app +- Adds support for the "contact" field to purchase orders + ### 0.11.0 - April 2023 --- diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 2f7ddb3..07860db 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -1,5 +1,5 @@ import "dart:async"; - +import "package:async/async.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; @@ -40,16 +40,10 @@ class _SearchDisplayState extends RefreshableState { final bool hasAppBar; - @override - void initState() { - super.initState(); - - _focusNode = FocusNode(); - } + CancelableOperation? _search_query; @override void dispose() { - _focusNode.dispose(); super.dispose(); } @@ -99,8 +93,6 @@ class _SearchDisplayState extends RefreshableState { int nSupplierResults = 0; int nPurchaseOrderResults = 0; - late FocusNode _focusNode; - // Callback when the text is being edited // Incorporates a debounce timer to restrict search frequency void onSearchTextChanged(String text, {bool immediate = false}) { @@ -114,9 +106,6 @@ class _SearchDisplayState extends RefreshableState { } else { debounceTimer = Timer(Duration(milliseconds: 250), () { search(text); - if (!_focusNode.hasFocus) { - _focusNode.requestFocus(); - } }); } } @@ -147,12 +136,36 @@ class _SearchDisplayState extends RefreshableState { return count; } + // Actually perform the search query + Future _perform_search(Map body) async { + InvenTreeAPI().post( + "search/", + body: body, + expectedStatusCode: 200).then((APIResponse response) { + decrementPendingSearches(); + + + Map results = {}; + + if (response.data is Map) { + results = response.data as Map; + } + + if (mounted) { + setState(() { + nPartResults = getSearchResultCount(results, "part"); + nCategoryResults = getSearchResultCount(results, "partcategory"); + nStockResults = getSearchResultCount(results, "stockitem"); + nLocationResults = getSearchResultCount(results, "stocklocation"); + nSupplierResults = 0; //getSearchResultCount(results, "") + nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder"); + }); + } + }); + } + /* - * Initiate multiple search requests to the server. - * Each request returns at *some point* in the future, - * by which time the search input may have changed, giving unexpected results. - * - * So, each request only causes an update *if* the search term is still the same when it completes + * Callback when the search input is changed */ Future search(String term) async { var api = InvenTreeAPI(); @@ -173,6 +186,15 @@ class _SearchDisplayState extends RefreshableState { nPendingSearches = 0; }); + // Cancel the previous search query (if in progress) + if (_search_query != null) { + if (!_search_query!.isCanceled) { + _search_query!.cancel(); + } + } + + _search_query = null; + if (term.isEmpty) { return; } @@ -216,29 +238,9 @@ class _SearchDisplayState extends RefreshableState { if (body.isNotEmpty) { nPendingSearches++; - api.post( - "search/", - body: body, - expectedStatusCode: 200).then((APIResponse response) { - decrementPendingSearches(); - - Map results = {}; - - if (response.data is Map) { - results = response.data as Map; - } - - if (mounted) { - setState(() { - nPartResults = getSearchResultCount(results, "part"); - nCategoryResults = getSearchResultCount(results, "partcategory"); - nStockResults = getSearchResultCount(results, "stockitem"); - nLocationResults = getSearchResultCount(results, "stocklocation"); - nSupplierResults = 0; //getSearchResultCount(results, "") - nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder"); - }); - } - }); + _search_query = CancelableOperation.fromFuture( + _perform_search(body), + ); } } else { legacySearch(term); @@ -344,16 +346,13 @@ class _SearchDisplayState extends RefreshableState { ), key: _formKey, readOnly: false, - autofocus: false, + autofocus: true, autocorrect: false, - focusNode: _focusNode, controller: searchController, onChanged: (String text) { onSearchTextChanged(text); - _focusNode.requestFocus(); }, onFieldSubmitted: (String text) { - _focusNode.requestFocus(); }, ), trailing: GestureDetector( @@ -363,7 +362,6 @@ class _SearchDisplayState extends RefreshableState { ), onTap: () { searchController.clear(); - _focusNode.requestFocus(); onSearchTextChanged("", immediate: true); }, ), @@ -541,10 +539,6 @@ class _SearchDisplayState extends RefreshableState { } } - if (!_focusNode.hasFocus) { - _focusNode.requestFocus(); - } - return tiles; } From 26b86a21944a9337595a41e327e7a1e98ae78e41 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 10 Apr 2023 23:12:30 +1000 Subject: [PATCH 328/746] Update status codes (#307) * Extra error info when connecting to server * Adds accessors for various types of status codes * Cleanup / refactor stock status codes - No longer need to duplicate these on the app * improvements to purchase order list - Add option to show closed orders - Render order status * Add purchase order status to order detail widget * Update release notes * Cleanup for imports * linting fixes --- assets/release_notes.md | 2 + lib/api.dart | 71 ++++++++++++---- lib/inventree/status_codes.dart | 112 ++++++++++++++++++++++++++ lib/inventree/stock.dart | 57 ------------- lib/l10n/app_en.arb | 12 +++ lib/widget/purchase_order_detail.dart | 8 ++ lib/widget/purchase_order_list.dart | 19 ++++- lib/widget/stock_detail.dart | 6 +- lib/widget/stock_item_history.dart | 2 +- lib/widget/stock_list.dart | 5 +- 10 files changed, 214 insertions(+), 80 deletions(-) create mode 100644 lib/inventree/status_codes.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 5b638d9..939abf6 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -7,6 +7,8 @@ - Fixes keyboard bug in search widget - Adds ability to create new purchase orders directly from the app - Adds support for the "contact" field to purchase orders +- Improved rendering of status codes for stock items +- Added rendering of status codes for purchase orders ### 0.11.0 - April 2023 --- diff --git a/lib/api.dart b/lib/api.dart index 3e14777..68a4a4e 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -6,6 +6,7 @@ import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; import "package:intl/intl.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/status_codes.dart"; import "package:inventree/preferences.dart"; import "package:open_filex/open_filex.dart"; @@ -148,6 +149,9 @@ class InvenTreeAPI { InvenTreeAPI._internal(); + // Ensure we only ever create a single instance of the API class + static final InvenTreeAPI _api = InvenTreeAPI._internal(); + // List of callback functions to trigger when the connection status changes List _statusCallbacks = []; @@ -346,9 +350,6 @@ class InvenTreeAPI { return !isConnected() && _connecting; } - // Ensure we only ever create a single instance of the API class - static final InvenTreeAPI _api = InvenTreeAPI._internal(); - /* * Connect to the remote InvenTree server: * @@ -490,11 +491,33 @@ class InvenTreeAPI { debug("Received token from server"); + bool result = false; + // Request user role information (async) - getUserRoles(); + result = await getUserRoles(); + + if (!result) { + showServerError( + apiUrl, + L10().serverError, + L10().errorUserRoles, + ); + + return false; + } // Request plugin information (async) - getPluginInformation(); + result = await getPluginInformation(); + + if (!result) { + showServerError( + apiUrl, + L10().serverError, + L10().errorPluginInfo + ); + + return false; + } // Ok, probably pretty good... return true; @@ -516,9 +539,7 @@ class InvenTreeAPI { _connectionStatusChanged(); } - /* - * Public facing connection function - */ + // Public facing connection function Future connectToServer() async { // Ensure server is first disconnected @@ -590,12 +611,12 @@ class InvenTreeAPI { } // Request plugin information from the server - Future getPluginInformation() async { + Future getPluginInformation() async { // The server does not support plugins, or they are not enabled if (!pluginsEnabled()) { _plugins.clear(); - return; + return true; } debug("API: getPluginInformation()"); @@ -611,15 +632,15 @@ class InvenTreeAPI { } } } + + return true; } + /* + * Check if the user has the given role.permission assigned + * e.g. "part", "change" + */ bool checkPermission(String role, String permission) { - /* - * Check if the user has the given role.permission assigned - *e - * e.g. "part", "change" - */ - // If we do not have enough information, assume permission is allowed if (roles.isEmpty) { return true; @@ -1422,4 +1443,22 @@ class InvenTreeAPI { } }); } + + // Keep an internal map of status codes + Map _status_codes = {}; + + // Return a status class based on provided URL + InvenTreeStatusCode _get_status_class(String url) { + if (!_status_codes.containsKey(url)) { + _status_codes[url] = InvenTreeStatusCode(url); + } + + return _status_codes[url]!; + } + + // Accessors methods for various status code classes + InvenTreeStatusCode get StockHistoryStatus => _get_status_class("stock/track/status/"); + InvenTreeStatusCode get StockStatus => _get_status_class("stock/status/"); + InvenTreeStatusCode get PurchaseOrderStatus => _get_status_class("order/po/status/"); + } diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart new file mode 100644 index 0000000..1a563a2 --- /dev/null +++ b/lib/inventree/status_codes.dart @@ -0,0 +1,112 @@ +/* + * Code for querying the server for various status code data, + * so that we do not have to duplicate those codes in the app. + * + * Ref: https://github.com/inventree/InvenTree/blob/master/InvenTree/InvenTree/status_codes.py + */ + +import "package:flutter/material.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; + + +/* + * Base class definition for a "status code" definition. + */ +class InvenTreeStatusCode { + + InvenTreeStatusCode(this.URL); + + final String URL; + + // Internal status code data loaded from server + Map data = {}; + + // Load status code information from the server + Future load({bool forceReload = false}) async { + + // Return internally cached data + if (data.isNotEmpty && !forceReload) { + return; + } + + // The server must support this feature! + if (!InvenTreeAPI().supportsStatusLabelEndpoints) { + return; + } + + debug("Loading status codes from ${URL}"); + + APIResponse response = await InvenTreeAPI().get(URL); + + if (response.statusCode == 200) { + Map results = response.data as Map; + + if (results.containsKey("values")) { + data = results["values"] as Map; + } + } + } + + // Return the entry associated with the provided integer status + Map entry(int status) { + for (String key in data.keys) { + dynamic _entry = data[key]; + + if (_entry is Map) { + dynamic _status = _entry["key"]; + + if (_status is int) { + if (status == _status) { + return _entry; + } + } + } + } + + // No match - return an empty map + return {}; + } + + // Return the 'label' associated with a given status code + String label(int status) { + Map _entry = entry(status); + + String _label = (_entry["label"] ?? "") as String; + + if (_label.isEmpty) { + // If no match found, return the status code + debug("No match for status code ${status} at '${URL}'"); + return status.toString(); + } else { + return _label; + } + } + + // Return the 'color' associated with a given status code + Color color(int status) { + Map _entry = entry(status); + + String color_name = (_entry["color"] ?? "") as String; + + switch (color_name.toLowerCase()) { + case "success": + return Colors.green; + case "primary": + return Colors.blue; + case "secondary": + return Colors.grey; + case "dark": + return Colors.black; + case "danger": + return Colors.red; + case "warning": + return Colors.orange; + case "info": + return Colors.lightBlue; + default: + return Colors.black; + } + } +} diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index f8a9a44..f6e8f3b 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -1,6 +1,5 @@ import "dart:async"; -import "package:flutter/material.dart"; import "package:intl/intl.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/part.dart"; @@ -122,66 +121,10 @@ class InvenTreeStockItem extends InvenTreeModel { InvenTreeStockItem.fromJson(Map json) : super.fromJson(json); - // Stock status codes - static const int OK = 10; - static const int ATTENTION = 50; - static const int DAMAGED = 55; - static const int DESTROYED = 60; - static const int REJECTED = 65; - static const int LOST = 70; - static const int QUARANTINED = 75; - static const int RETURNED = 85; - - String statusLabel() { - - // TODO: Delete me - The translated status values should be provided by the API! - - switch (status) { - case OK: - return L10().ok; - case ATTENTION: - return L10().attention; - case DAMAGED: - return L10().damaged; - case DESTROYED: - return L10().destroyed; - case REJECTED: - return L10().rejected; - case LOST: - return L10().lost; - case QUARANTINED: - return L10().quarantined; - case RETURNED: - return L10().returned; - default: - return status.toString(); - } - } - - // Return color associated with stock status - Color get statusColor { - switch (status) { - case OK: - return Colors.black; - case ATTENTION: - return Color(0xFFfdc82a); - case DAMAGED: - case DESTROYED: - case REJECTED: - return Color(0xFFe35a57); - case QUARANTINED: - return Color(0xFF0DCAF0); - case LOST: - default: - return Color(0xFFAAAAAA); - } - } - @override String get URL => "stock/"; // URLs for performing stock actions - static String transferStockUrl() => "stock/transfer/"; static String countStockUrl() => "stock/count/"; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b189554..bd30602 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -288,6 +288,12 @@ "errorFetch": "Error fetching data from server", "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", "@errorReporting": {}, @@ -579,6 +585,12 @@ "onOrderDetails": "Items currently on order", "@onOrderDetails": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "packaging": "Packaging", "@packaging": {}, diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 77337ef..220596d 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -66,6 +66,8 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { await order.reload(); + await api.PurchaseOrderStatus.load(); + lines = await order.getLineItems(); completedLines = 0; @@ -112,6 +114,12 @@ class _PurchaseOrderDetailState extends RefreshableState> get filterOptions => { + "outstanding": { + "label": L10().outstanding, + "help_text": L10().outstandingOrderDetail, + "tristate": true, + } + }; + @override Future requestPage(int limit, int offset, Map params) async { - params["outstanding"] = "true"; - + await InvenTreeAPI().PurchaseOrderStatus.load(); final page = await InvenTreePurchaseOrder().listPaginated(limit, offset, filters: params); return page; @@ -151,7 +159,12 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState { @override Future request(BuildContext context) async { + await api.StockStatus.load(); + stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; final bool result = widget.item.pk > 0 && await widget.item.reload(); @@ -565,9 +567,9 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text("${widget.item.partDescription}"), leading: InvenTreeAPI().getImage(widget.item.partImage), trailing: Text( - widget.item.statusLabel(), + api.StockStatus.label(widget.item.status), style: TextStyle( - color: widget.item.statusColor + color: api.StockStatus.color(widget.item.status), ) ), onTap: () async { diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index b03263f..15ecf83 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -33,7 +33,7 @@ class _StockItemHistoryDisplayState extends RefreshableState results) { + await InvenTreeStockItemHistory().list(filters: {"item": "${item.pk}"}).then((List results) { for (var result in results) { if (result is InvenTreeStockItemHistory) { history.add(result); diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index 70c3928..0d16bc1 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -95,6 +95,9 @@ class _PaginatedStockItemListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { + // Ensure StockStatus codes are loaded + await InvenTreeAPI().StockStatus.load(); + final page = await InvenTreeStockItem().listPaginated( limit, offset, @@ -120,7 +123,7 @@ class _PaginatedStockItemListState extends PaginatedSearchState Date: Mon, 10 Apr 2023 23:28:02 +1000 Subject: [PATCH 329/746] Dialog improvements (#308) --- lib/settings/login.dart | 16 +++++++++------- lib/widget/dialogs.dart | 7 ++++--- lib/widget/stock_detail.dart | 2 ++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/settings/login.dart b/lib/settings/login.dart index e4606e6..aa9a9d4 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -175,16 +175,18 @@ class _InvenTreeLoginSettingsState extends State { Navigator.of(context).pop(); // Navigator.of(context, rootNavigator: true).pop(); confirmationDialog( - L10().delete, - L10().profileDelete + "?", - onAccept: () { - _deleteProfile(profile); - } + L10().delete, + L10().profileDelete + "?", + color: Colors.red, + icon: FontAwesomeIcons.trashCan, + onAccept: () { + _deleteProfile(profile); + } ); }, child: ListTile( - title: Text(L10().profileDelete), - leading: FaIcon(FontAwesomeIcons.trashCan), + title: Text(L10().profileDelete, style: TextStyle(color: Colors.red)), + leading: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), ) ) ], diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index ba09b30..a14a13f 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -13,7 +13,7 @@ import "package:inventree/widget/snacks.dart"; /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ -Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { +Future confirmationDialog(String title, String text, {Color? color, IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; @@ -21,9 +21,10 @@ Future confirmationDialog(String title, String text, {IconData icon = Font OneContext().showDialog( builder: (BuildContext context) { return AlertDialog( + iconColor: color, title: ListTile( - title: Text(title), - leading: FaIcon(icon), + title: Text(title, style: TextStyle(color: color)), + leading: FaIcon(icon, color: color), ), content: Text(text), actions: [ diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 6de1924..5dced70 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -293,6 +293,8 @@ class _StockItemDisplayState extends RefreshableState { L10().stockItemDelete, L10().stockItemDeleteConfirm, icon: FontAwesomeIcons.trashCan, + color: Colors.red, + acceptText: L10().delete, onAccept: () async { final bool result = await widget.item.delete(); From 2fdff022991cd9e9d3563766cfa39f417b554cd5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 10 Apr 2023 23:29:29 +1000 Subject: [PATCH 330/746] Update version number (#309) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 7f8eae9..f69a420 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.0+58 +version: 0.11.1+59 environment: sdk: ">=2.16.0 <3.0.0" From 0156329fb6c30fc83af9dad092137b0b78f6ab4c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 11 Apr 2023 00:00:43 +1000 Subject: [PATCH 331/746] Bump release number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f69a420..dcb67cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.1+59 +version: 0.11.1+60 environment: sdk: ">=2.16.0 <3.0.0" From 946abb60a0dd09e7051bbdc79049c4c0face3f72 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Apr 2023 21:25:39 +1000 Subject: [PATCH 332/746] Update notifications periodically (#311) - Call periodically from API class --- lib/api.dart | 53 ++++++++++++++++++++++++++++++++---------- lib/widget/drawer.dart | 3 +++ lib/widget/home.dart | 32 ------------------------- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 68a4a4e..fb883fa 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -5,26 +5,25 @@ import "dart:io"; import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; import "package:intl/intl.dart"; -import "package:inventree/app_colors.dart"; -import "package:inventree/inventree/status_codes.dart"; -import "package:inventree/preferences.dart"; - import "package:open_filex/open_filex.dart"; import "package:cached_network_image/cached_network_image.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter_cache_manager/flutter_cache_manager.dart"; - -import "package:inventree/widget/dialogs.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/helpers.dart"; -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/inventree/model.dart"; -import "package:inventree/user_profile.dart"; -import "package:inventree/widget/snacks.dart"; import "package:path_provider/path_provider.dart"; import "package:inventree/api_form.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/preferences.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/notification.dart"; +import "package:inventree/inventree/status_codes.dart"; +import "package:inventree/inventree/sentry.dart"; +import "package:inventree/user_profile.dart"; +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/snacks.dart"; /* @@ -520,6 +519,16 @@ class InvenTreeAPI { } // Ok, probably pretty good... + + if (_notification_timer == null) { + debug("starting notification timer"); + _notification_timer = Timer.periodic( + Duration(seconds: 5), + (timer) { + _refreshNotifications(); + }); + } + return true; } @@ -1461,4 +1470,24 @@ class InvenTreeAPI { InvenTreeStatusCode get StockStatus => _get_status_class("stock/status/"); InvenTreeStatusCode get PurchaseOrderStatus => _get_status_class("order/po/status/"); + int notification_counter = 0; + + Timer? _notification_timer; + + /* + * Update notification counter (called periodically) + */ + Future _refreshNotifications() async { + if (!isConnected()) { + return; + } + + if (!supportsNotifications) { + return; + } + + InvenTreeNotification().count(filters: {"read": "false"}).then((int n) { + notification_counter = n; + }); + } } diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 4da5c50..6f438ec 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -129,9 +129,12 @@ class InvenTreeDrawer extends StatelessWidget { } if (InvenTreeAPI().supportsNotifications) { + int notification_count = InvenTreeAPI().notification_counter; + tiles.add( ListTile( leading: FaIcon(FontAwesomeIcons.bell), + trailing: notification_count > 0 ? Text(notification_count.toString()) : null, title: Text(L10().notifications), onTap: _notifications, ) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 39c74a8..c525c0d 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -42,16 +42,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr // Initially load the profile and attempt server connection _loadProfile(); - _refreshNotifications(); - - // Refresh notifications every ~30 seconds - Timer.periodic( - Duration( - milliseconds: 30000, - ), (timer) { - _refreshNotifications(); - }); - InvenTreeAPI().registerCallback(() { if (mounted) { @@ -180,28 +170,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr setState(() {}); } - /* - * Refresh the number of active notifications for this user - */ - Future _refreshNotifications() async { - - if (!InvenTreeAPI().isConnected()) { - return; - } - - // Ignore if the widget is no longer active - if (!mounted) { - return; - } - - // final notifications = await InvenTreeNotification().list(); - - setState(() { - // _notificationCounter = notifications.length; - }); - } - - Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = "", Widget? trailing}) { bool connected = InvenTreeAPI().isConnected(); From 164295c3e2183426bb6c7c77a421e6ff75f17faf Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Apr 2023 22:38:57 +1000 Subject: [PATCH 333/746] Code Cleanup (#312) * Open email and telephone links for company * Cleanup imports --- ios/Runner/Info.plist | 42 ++++++++++++++++++++----------- lib/helpers.dart | 21 ++++++++++++++-- lib/inventree/bom.dart | 1 - lib/inventree/model.dart | 7 +++--- lib/inventree/part.dart | 7 +++--- lib/inventree/purchase_order.dart | 2 -- lib/inventree/sentry.dart | 2 +- lib/inventree/stock.dart | 11 ++++---- lib/settings/release.dart | 14 +++-------- lib/widget/company_detail.dart | 23 ++++++++--------- 10 files changed, 74 insertions(+), 56 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e3962ae..edb4d15 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -12,22 +12,31 @@ 6.0 CFBundleLocalizations - de - el + cs-CZ + da-DK + de-DE + el-GR en - es - fr - he - it - ja - ko - nl - no - pl - ru - sv - tr - vi + es-ES + es-MX + fa-IR + fr-FR + he-IL + hu-HU + id-ID + it-IT + ja-JP + ko-KR + nl-NL + no-NO + pl-PL + pt-BR + pt-PT + ru-RU + sv-SE + th-TH + tr-TR + vi-VN zh-CN CFBundleName @@ -69,7 +78,10 @@ LSApplicationQueriesSchemes + http https + mailto + tel CADisableMinimumFrameDurationOnPhone diff --git a/lib/helpers.dart b/lib/helpers.dart index 3cb905e..404e6ea 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -9,9 +9,13 @@ import "dart:io"; import "package:currency_formatter/currency_formatter.dart"; - -import "package:audioplayers/audioplayers.dart"; import "package:one_context/one_context.dart"; +import "package:url_launcher/url_launcher.dart"; +import "package:audioplayers/audioplayers.dart"; + +import "package:inventree/l10.dart"; +import "package:inventree/widget/snacks.dart"; + List debug_messages = []; @@ -80,6 +84,19 @@ Future playAudioFile(String path) async { } +// Open an external URL +Future openLink(String url) async { + + final link = Uri.parse(url); + + try { + await launchUrl(link); + } catch (e) { + showSnackIcon(L10().error, success: false); + } +} + + /* * Helper function for rendering a money / currency object as a String */ diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart index 5521786..ec326fe 100644 --- a/lib/inventree/bom.dart +++ b/lib/inventree/bom.dart @@ -1,5 +1,4 @@ - import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 33d5e47..8427b58 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -2,17 +2,16 @@ import "dart:async"; import "dart:io"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; import "package:flutter/material.dart"; -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/widget/dialogs.dart"; import "package:url_launcher/url_launcher.dart"; - import "package:path/path.dart" as path; +import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; import "package:inventree/fa_icon_mapping.dart"; import "package:inventree/l10.dart"; +import "package:inventree/inventree/sentry.dart"; +import "package:inventree/widget/dialogs.dart"; // Paginated response object diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 762ba9d..339382b 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -1,12 +1,13 @@ import "dart:io"; +import "package:flutter/material.dart"; + import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; -import "package:inventree/inventree/stock.dart"; -import "package:inventree/inventree/company.dart"; -import "package:flutter/material.dart"; import "package:inventree/l10.dart"; +import "package:inventree/inventree/stock.dart"; +import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 23f5819..2ee1489 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,9 +1,7 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; - import "package:inventree/inventree/model.dart"; -// TODO: In the future, status codes should be retrieved from the server const int PO_STATUS_PENDING = 10; const int PO_STATUS_PLACED = 20; const int PO_STATUS_COMPLETE = 30; diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index de24733..d8becd8 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,11 +1,11 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; -import "package:inventree/preferences.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/preferences.dart"; Future> getDeviceInfo() async { diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index f6e8f3b..a52cc9b 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -1,13 +1,14 @@ import "dart:async"; import "package:intl/intl.dart"; -import "package:inventree/helpers.dart"; -import "package:inventree/inventree/part.dart"; - -import "package:inventree/inventree/model.dart"; -import "package:inventree/l10.dart"; import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/model.dart"; + class InvenTreeStockItemTestResult extends InvenTreeModel { diff --git a/lib/settings/release.dart b/lib/settings/release.dart index 6502a90..4358a47 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -1,8 +1,10 @@ import "package:flutter/material.dart"; import "package:flutter_markdown/flutter_markdown.dart"; -import "package:inventree/l10.dart"; import "package:url_launcher/url_launcher.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; + class ReleaseNotesWidget extends StatelessWidget { @@ -10,16 +12,6 @@ class ReleaseNotesWidget extends StatelessWidget { final String releaseNotes; - // Callback function when a link is clicked in the markdown - Future openLink(String url) async { - - final link = Uri.parse(url); - - if (await canLaunchUrl(link)) { - await launchUrl(link); - } - } - @override Widget build (BuildContext context) { return Scaffold( diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index be5167a..f5cc36b 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -5,6 +5,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; @@ -15,6 +16,7 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/supplier_part_list.dart"; + /* * Widget for displaying detail view of a single Company instance */ @@ -68,7 +70,7 @@ class _CompanyDetailState extends RefreshableState { List actionButtons(BuildContext context) { List actions = []; - // TODO + // TODO - Actions for this company return actions; } @@ -147,9 +149,9 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.website.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.website}"), - leading: FaIcon(FontAwesomeIcons.globe), - onTap: () { - // TODO - Open website + leading: FaIcon(FontAwesomeIcons.globe, color: COLOR_CLICK), + onTap: () async { + openLink(widget.company.website); }, )); @@ -159,9 +161,9 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.email.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.email}"), - leading: FaIcon(FontAwesomeIcons.at), - onTap: () { - // TODO - Open email + leading: FaIcon(FontAwesomeIcons.at, color: COLOR_CLICK), + onTap: () async { + openLink("mailto:${widget.company.email}"); }, )); @@ -171,9 +173,9 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.phone.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.phone}"), - leading: FaIcon(FontAwesomeIcons.phone), + leading: FaIcon(FontAwesomeIcons.phone, color: COLOR_CLICK), onTap: () { - // TODO - Call phone number + openLink("tel:${widget.company.phone}"); }, )); @@ -256,10 +258,7 @@ class _CompanyDetailState extends RefreshableState { } if (widget.company.isCustomer) { - // TODO - Add list of sales orders - - tiles.add(Divider()); } if (widget.company.notes.isNotEmpty) { From 943104f20cd2808196108fe1d07e0b954a856cf8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Apr 2023 22:52:27 +1000 Subject: [PATCH 334/746] Add actions to issue or cancel purchase orders (#313) --- lib/inventree/purchase_order.dart | 21 +++++++++ lib/l10n/app_en.arb | 9 ++++ lib/widget/dialogs.dart | 2 +- lib/widget/purchase_order_detail.dart | 68 +++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 2ee1489..abfd0ba 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -93,6 +93,8 @@ class InvenTreePurchaseOrder extends InvenTreeModel { bool get isOpen => status == PO_STATUS_PENDING || status == PO_STATUS_PLACED; + bool get isPending => status == PO_STATUS_PENDING; + bool get isPlaced => status == PO_STATUS_PLACED; bool get isFailed => status == PO_STATUS_CANCELLED || status == PO_STATUS_LOST || status == PO_STATUS_RETURNED; @@ -132,6 +134,25 @@ class InvenTreePurchaseOrder extends InvenTreeModel { InvenTreeModel createFromJson(Map json) { return InvenTreePurchaseOrder.fromJson(json); } + + /// Mark this order as "placed" / "issued" + Future issueOrder() async { + // Order can only be placed when the order is 'pending' + if (!isPending) { + return; + } + + await api.post("${url}issue/", expectedStatusCode: 201); + } + + /// Mark this order as "cancelled" + Future cancelOrder() async { + if (!isOpen) { + return; + } + + await api.post("${url}cancel/", expectedStatusCode: 201); + } } class InvenTreePOLineItem extends InvenTreeModel { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bd30602..e9d81e9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -156,6 +156,9 @@ "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", "@category": {}, @@ -479,9 +482,15 @@ "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", "@itemInLocation": {}, diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index a14a13f..398dea6 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -26,7 +26,7 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa title: Text(title, style: TextStyle(color: color)), leading: FaIcon(icon, color: color), ), - content: Text(text), + content: text.isEmpty ? Text(text) : null, actions: [ TextButton( child: Text(_reject), diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 220596d..3b7d1ee 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -1,5 +1,7 @@ import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/widget/dialogs.dart"; import "package:one_context/one_context.dart"; import "package:inventree/api.dart"; @@ -62,6 +64,72 @@ class _PurchaseOrderDetailState extends RefreshableState actionButtons(BuildContext context) { + List actions = []; + + if (api.checkPermission("purchase_order", "add")) { + if (order.isPending) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.paperPlane, color: Colors.blue), + label: L10().issueOrder, + onTap: () async { + _issueOrder(context); + } + ) + ); + } + + if (order.isOpen) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circleXmark, color: Colors.red), + label: L10().cancelOrder, + onTap: () async { + _cancelOrder(context); + } + ) + ); + } + } + + return actions; + } + + /// Issue this order + Future _issueOrder(BuildContext context) async { + + confirmationDialog( + L10().issueOrder, "", + icon: FontAwesomeIcons.paperPlane, + color: Colors.blue, + acceptText: L10().issue, + onAccept: () async { + await order.issueOrder().then((dynamic) { + refresh(context); + }); + } + ); + } + + /// Cancel this order + Future _cancelOrder(BuildContext context) async { + + confirmationDialog( + L10().cancelOrder, "", + icon: FontAwesomeIcons.circleXmark, + color: Colors.red, + acceptText: L10().cancel, + onAccept: () async { + await order.cancelOrder().then((dynamic) { + print("callback"); + refresh(context); + }); + } + ); + } + @override Future request(BuildContext context) async { await order.reload(); From 1d913084a682e3ef72f8a5f126f5e25be85c995a Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 12 Apr 2023 22:58:13 +1000 Subject: [PATCH 335/746] Update release notes (#314) --- assets/release_notes.md | 7 +++++++ pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 939abf6..385d307 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,13 @@ ## InvenTree App Release Notes --- +### 0.11.2 - April 2023 +--- + +- Add action to issue a purchase order +- Add action to cancel a purchase order +- Reimplement periodic checks for notifications + ### 0.11.1 - April 2023 --- diff --git a/pubspec.yaml b/pubspec.yaml index dcb67cf..3f157d6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.1+60 +version: 0.11.2+61 environment: sdk: ">=2.16.0 <3.0.0" From e7f5141aa9b07156b141d93aabf8abc041bdc3a4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 15 Apr 2023 22:11:55 +1000 Subject: [PATCH 336/746] New translations app_en.arb (Hungarian) (#315) --- lib/l10n/hu_HU/app_hu_HU.arb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index f778239..3a51552 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -108,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Rendelés törlése", + "@cancelOrder": {}, "category": "Kategória", "@category": {}, "categoryCreate": "Új kategória", @@ -200,6 +202,10 @@ "@errorDetails": {}, "errorFetch": "Hiba a kiszolgálótól való adatlekérés közben", "@errorFetch": {}, + "errorUserRoles": "Felhasználói szerepkörök lekérése a szervertől sikertelen", + "@errorUserRoles": {}, + "errorPluginInfo": "Plugin adatok lekérése a szervertől sikertelen", + "@errorPluginInfo": {}, "errorReporting": "Hibajelentés", "@errorReporting": {}, "errorReportUpload": "Hibajelentések feltöltése", @@ -323,8 +329,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", "@invalidUsernamePassword": {}, + "issue": "Kiküldés", + "@issue": {}, "issueDate": "Kiállítás dátuma", "@issueDate": {}, + "issueOrder": "Rendelés kiküldése", + "@issueOrder": {}, "itemInLocation": "A tétel már a megadott helyen van", "@itemInLocation": {}, "keywords": "Kulcsszavak", @@ -393,6 +403,10 @@ "@onOrder": {}, "onOrderDetails": "Alaktrészek beszállítás alatt", "@onOrderDetails": {}, + "outstanding": "Kintlévő", + "@outstanding": {}, + "outstandingOrderDetail": "Kintlévő rendelések megjelenítése", + "@outstandingOrderDetail": {}, "packaging": "Csomagolás", "@packaging": {}, "packageName": "Csomag neve", @@ -493,6 +507,8 @@ "@profileTapToCreate": {}, "purchaseOrder": "Beszerzési rendelés", "@purchaseOrder": {}, + "purchaseOrderCreate": "Új beszerzési rendelés", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", "@purchaseOrderEdit": {}, "purchaseOrders": "Beszerzési rendelések", From a3d712d11ddc637d6aa5d6a62d3febd3ef1f90b3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 16 Apr 2023 21:10:57 +1000 Subject: [PATCH 337/746] Adds "dark mode" support (#317) * Adds "dark mode" support - Uses adaptive_theme package * CI fixes * More fixes * Update release notes --- assets/release_notes.md | 2 ++ lib/l10n/app_en.arb | 6 ++++ lib/main.dart | 58 +++++++++++++++++++++++----------- lib/settings/app_settings.dart | 37 ++++++++++++++++++++-- lib/settings/settings.dart | 16 +++++----- pubspec.lock | 8 +++++ pubspec.yaml | 1 + 7 files changed, 99 insertions(+), 29 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 385d307..e3018f1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,10 +4,12 @@ ### 0.11.2 - April 2023 --- +- Adds "dark mode" display option - Add action to issue a purchase order - Add action to cancel a purchase order - Reimplement periodic checks for notifications + ### 0.11.1 - April 2023 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e9d81e9..661e300 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -211,6 +211,12 @@ "damaged": "Damaged", "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", "@delete": {}, diff --git a/lib/main.dart b/lib/main.dart index ef9b49f..f41357a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:flutter/services.dart"; +import "package:adaptive_theme/adaptive_theme.dart"; import "package:flutter_gen/gen_l10n/app_localizations.dart"; import "package:flutter_localizations/flutter_localizations.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; @@ -22,6 +23,8 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); + final savedThemeMode = await AdaptiveTheme.getThemeMode(); + await runZonedGuarded>(() async { PackageInfo info = await PackageInfo.fromPlatform(); @@ -53,7 +56,7 @@ Future main() async { }; runApp( - InvenTreeApp() + InvenTreeApp(savedThemeMode) ); }, (Object error, StackTrace stackTrace) async { @@ -65,8 +68,12 @@ Future main() async { class InvenTreeApp extends StatefulWidget { // This widget is the root of your application. + const InvenTreeApp(this.savedThemeMode); + + final AdaptiveThemeMode? savedThemeMode; + @override - InvenTreeAppState createState() => InvenTreeAppState(); + InvenTreeAppState createState() => InvenTreeAppState(savedThemeMode); static InvenTreeAppState? of(BuildContext context) => context.findAncestorStateOfType(); @@ -75,9 +82,13 @@ class InvenTreeApp extends StatefulWidget { class InvenTreeAppState extends State { + InvenTreeAppState(this.savedThemeMode) : super(); + // Custom _locale (default = null; use system default) Locale? _locale; + final AdaptiveThemeMode? savedThemeMode; + @override void initState() { super.initState(); @@ -122,25 +133,36 @@ class InvenTreeAppState extends State { @override Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - builder: OneContext().builder, - navigatorKey: OneContext().key, - onGenerateTitle: (BuildContext context) => "InvenTree", - theme: ThemeData( + return AdaptiveTheme( + light: ThemeData( + brightness: Brightness.light, + primarySwatch: Colors.lightBlue, + secondaryHeaderColor: Colors.blueGrey + ), + dark: ThemeData( + brightness: Brightness.dark, primarySwatch: Colors.lightBlue, secondaryHeaderColor: Colors.blueGrey, ), - home: InvenTreeHomePage(), - localizationsDelegates: [ - I18N.delegate, - LocaleNamesLocalizationsDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: supported_locales, - locale: _locale, + initial: savedThemeMode ?? AdaptiveThemeMode.light, + builder: (light, dark) => MaterialApp( + theme: light, + darkTheme: dark, + debugShowCheckedModeBanner: false, + builder: OneContext().builder, + navigatorKey: OneContext().key, + onGenerateTitle: (BuildContext context) => "InvenTree", + home: InvenTreeHomePage(), + localizationsDelegates: [ + I18N.delegate, + LocaleNamesLocalizationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: supported_locales, + locale: _locale, + ) ); } } diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index ad7e58d..42c94a0 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -1,7 +1,9 @@ - import "package:flutter/material.dart"; + +import "package:adaptive_theme/adaptive_theme.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; +import "package:one_context/one_context.dart"; import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; @@ -9,6 +11,8 @@ import "package:inventree/l10n/supported_locales.dart"; import "package:inventree/main.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/progress.dart"; + class InvenTreeAppSettingsWidget extends StatefulWidget { @override @@ -28,23 +32,32 @@ class _InvenTreeAppSettingsState extends State { bool reportErrors = true; bool strictHttps = false; + bool darkMode = false; + Locale? locale; @override void initState() { super.initState(); - loadSettings(); + loadSettings(OneContext().context!); } - Future loadSettings() async { + Future loadSettings(BuildContext context) async { + + showLoadingOverlay(context); + barcodeSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; serverSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + darkMode = AdaptiveTheme.of(context).mode.isDark; + locale = await InvenTreeSettingsManager().getSelectedLocale(); + hideLoadingOverlay(); + if (mounted) { setState(() {}); } @@ -168,6 +181,24 @@ class _InvenTreeAppSettingsState extends State { ), leading: FaIcon(FontAwesomeIcons.mobile), ), + ListTile( + title: Text(L10().darkMode), + subtitle: Text(L10().darkModeEnable), + leading: FaIcon(FontAwesomeIcons.moon), + trailing: Switch( + value: darkMode, + onChanged: (bool value) { + if (value) { + AdaptiveTheme.of(context).setDark(); + } else { + AdaptiveTheme.of(context).setLight(); + } + setState(() { + darkMode = value; + }); + } + ) + ), ListTile( title: Text(L10().strictHttps), subtitle: Text(L10().strictHttpsDetails), diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 9c2c95c..ed589e1 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -52,6 +52,14 @@ class _InvenTreeSettingsState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget())); }, ), + ListTile( + title: Text(L10().appSettings), + subtitle: Text(L10().appSettingsDetails), + leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); + } + ), ListTile( title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), @@ -60,14 +68,6 @@ class _InvenTreeSettingsState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } ), - ListTile( - title: Text(L10().appSettings), - subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); - } - ), ListTile( title: Text(L10().part), subtitle: Text(L10().partSettings), diff --git a/pubspec.lock b/pubspec.lock index 336cbeb..ac1db99 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "52.0.0" + adaptive_theme: + dependency: "direct main" + description: + name: adaptive_theme + sha256: "61bde10390e937d11d05c6cf0d5cf378a73d49f9a442262e43613dae60ed0b3f" + url: "https://pub.dev" + source: hosted + version: "3.2.0" analyzer: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3f157d6..91dc1d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,6 +7,7 @@ environment: sdk: ">=2.16.0 <3.0.0" dependencies: + adaptive_theme: ^3.2.0 # Theme management (e.g. dark mode) audioplayers: ^3.0.1 # Play audio files cached_network_image: ^3.2.0 # Download and cache remote images camera: ^0.10.3 # Camera From b54565d1c314aa258ac4f14473eb54f5a43d5a27 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 16 Apr 2023 22:07:01 +1000 Subject: [PATCH 338/746] Dark mode color fix (#318) * Fix custom colors in API forms * update release notes * update build version --- assets/release_notes.md | 5 +++++ lib/api_form.dart | 4 ++-- lib/app_colors.dart | 1 - pubspec.yaml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e3018f1..10b280b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.11.3 - April 2023 +--- + +- Fixes text color in dark mode + ### 0.11.2 - April 2023 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index 341d740..1b72360 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -743,7 +743,7 @@ class APIFormField { fontWeight: FontWeight.bold, fontSize: 18, fontFamily: "arial", - color: hasErrors() ? COLOR_DANGER : COLOR_GRAY, + color: hasErrors() ? COLOR_DANGER : null, fontStyle: FontStyle.normal, ); } @@ -751,7 +751,7 @@ class APIFormField { TextStyle _helperStyle() { return TextStyle( fontStyle: FontStyle.italic, - color: hasErrors() ? COLOR_DANGER : COLOR_GRAY, + color: hasErrors() ? COLOR_DANGER : null, ); } diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 2f0395f..065a86f 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -1,6 +1,5 @@ import "dart:ui"; -const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1); const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 1); const Color COLOR_CLICK = Color.fromRGBO(150, 120, 100, 0.9); diff --git a/pubspec.yaml b/pubspec.yaml index 91dc1d8..33a6094 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.2+61 +version: 0.11.3+62 environment: sdk: ">=2.16.0 <3.0.0" From b5c4bda80f4cdcc3d6f1bdd3be7565d99f9a80f0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 18 Apr 2023 18:43:52 +1000 Subject: [PATCH 339/746] New translations app_en.arb (French) (#319) --- lib/l10n/fr_FR/app_fr_FR.arb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 6888679..e2b6eb7 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -108,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Annuler la commande", + "@cancelOrder": {}, "category": "Catégorie", "@category": {}, "categoryCreate": "Nouvelle catégorie", @@ -144,6 +146,10 @@ "@customers": {}, "damaged": "Endommagé", "@damaged": {}, + "darkMode": "Mode Sombre", + "@darkMode": {}, + "darkModeEnable": "Activer le mode sombre", + "@darkModeEnable": {}, "delete": "Supprimer", "@delete": {}, "deleteFailed": "L'opération de suppression a échoué", @@ -200,6 +206,10 @@ "@errorDetails": {}, "errorFetch": "Erreur de récupération des données du serveur", "@errorFetch": {}, + "errorUserRoles": "Erreur lors de la demande des rôles d'utilisateurs au serveur", + "@errorUserRoles": {}, + "errorPluginInfo": "Erreur lors de la demande des données des modules d'extension au serveur", + "@errorPluginInfo": {}, "errorReporting": "Rapport d'erreur", "@errorReporting": {}, "errorReportUpload": "Envoyer le rapport d 'erreur", @@ -323,8 +333,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", "@invalidUsernamePassword": {}, + "issue": "Problème", + "@issue": {}, "issueDate": "Date d'émission", "@issueDate": {}, + "issueOrder": "Émettre la commande", + "@issueOrder": {}, "itemInLocation": "Article déjà dans l'emplacement", "@itemInLocation": {}, "keywords": "Mots clés", @@ -393,6 +407,8 @@ "@onOrder": {}, "onOrderDetails": "Articles en cours de commande", "@onOrderDetails": {}, + "outstandingOrderDetail": "Afficher les commandes en cours", + "@outstandingOrderDetail": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -493,6 +509,8 @@ "@profileTapToCreate": {}, "purchaseOrder": "Commande d’achat", "@purchaseOrder": {}, + "purchaseOrderCreate": "Nouveau Bon de Commande", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifier la commande d'achat", "@purchaseOrderEdit": {}, "purchaseOrders": "Commandes d'achat", @@ -803,7 +821,7 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", "@tokenMissingFromResponse": {}, - "totalPrice": "Prix total", + "totalPrice": "Prix Total", "@totalPrice": {}, "transfer": "Transfert", "@transfer": { @@ -815,7 +833,7 @@ }, "transferStockDetail": "Transférer un élément vers un autre emplacement", "@transferStockDetail": {}, - "transferStockLocation": "Transférer l'emplacement du stock", + "transferStockLocation": "Transférer l'Emplacement du Stock", "@transferStockLocation": {}, "transferStockLocationDetail": "Transférer cet emplacement de stock vers un autre", "@transferStockLocationDetail": {}, From 01a45568a0c3d8e47b2ffda3a035dca886f76fea Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 18 Apr 2023 22:39:32 +1000 Subject: [PATCH 340/746] Bump version to 0.11.4 (#321) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 33a6094..811d293 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.3+62 +version: 0.11.4+63 environment: sdk: ">=2.16.0 <3.0.0" From d926686a895ae06a28544a6d3f391abd73cb247a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 18 Apr 2023 22:46:08 +1000 Subject: [PATCH 341/746] Stock history fix (#320) * Improves quantity parsing from * Add paginated history widget * Refactor stock history widget as a paginated widget * Allow paginated result list to handle results returned as list - Some API endpoints (older ones most likely) don't paginate results correctly * Fix code layout * Render user information in "history" widget (not quantity) * Hide filter button * Update release notes * remove unused import --- android/gradle.properties | 4 ++ assets/release_notes.md | 6 ++ lib/inventree/model.dart | 29 ++++++-- lib/inventree/stock.dart | 31 +++++--- lib/widget/stock_item_history.dart | 109 +++++++++++++++++------------ 5 files changed, 116 insertions(+), 63 deletions(-) diff --git a/android/gradle.properties b/android/gradle.properties index 615b166..ce4fa01 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,7 @@ +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.configureondemand=true +org.gradle.caching=true org.gradle.jvmargs=-Xmx1536M android.enableD8=true android.enableJetifier=true diff --git a/assets/release_notes.md b/assets/release_notes.md index 10b280b..07a3df3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,12 @@ ## InvenTree App Release Notes --- +### 0.11.4 - April 2023 +--- + +- Bug fix for stock history widget +- Improved display of stock history widget + ### 0.11.3 - April 2023 --- diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 8427b58..7c75129 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -575,10 +575,12 @@ class InvenTreeModel { // Construct the response InvenTreePageResponse page = InvenTreePageResponse(); - var data = response.asMap(); + var dataMap = response.asMap(); - if (data.containsKey("count") && data.containsKey("results")) { - page.count = (data["count"] ?? 0) as int; + // First attempt is to look for paginated data, returned as a map + + if (dataMap.isNotEmpty && dataMap.containsKey("count") && dataMap.containsKey("results")) { + page.count = (dataMap["count"] ?? 0) as int; page.results = []; @@ -587,15 +589,28 @@ class InvenTreeModel { } return page; - - } else { - return null; } + + // Second attempt is to look for a list of data (not paginated) + var dataList = response.asList(); + + if (dataList.isNotEmpty) { + page.count = dataList.length; + page.results = []; + + for (var result in dataList) { + page.addResult(createFromJson(result as Map)); + } + + return page; + } + + // Finally, no results available + return null; } // Return list of objects from the database, with optional filters Future> list({Map filters = const {}}) async { - var params = defaultListFilters(); for (String key in filters.keys) { diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index a52cc9b..ab6cc14 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -23,9 +23,7 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { @override Map formFields() { return { - "stock_item": { - "hidden": true - }, + "stock_item": {"hidden": true}, "test": {}, "result": {}, "value": {}, @@ -75,6 +73,7 @@ class InvenTreeStockItemHistory extends InvenTreeModel { // By default, order by decreasing date return { "ordering": "-date", + "user_detail": "true", }; } @@ -98,21 +97,31 @@ class InvenTreeStockItemHistory extends InvenTreeModel { String get label => (jsondata["label"] ?? "") as String; - String get quantityString { - Map deltas = (jsondata["deltas"] ?? {}) as Map; + // Return the "deltas" associated with this historical object + Map get deltas { + if (jsondata.containsKey("deltas")) { + return jsondata["deltas"] as Map; + } else { + return {}; + } + } - // Serial number takes priority here - if (deltas.containsKey("serial")) { - var serial = (deltas["serial"] ?? "").toString(); - return "# ${serial}"; - } else if (deltas.containsKey("quantity")) { - double q = (deltas["quantity"] ?? 0) as double; + // Return the quantity string for this historical object + String get quantityString { + var _deltas = deltas; + + if (_deltas.containsKey("quantity")) { + double q = double.tryParse(_deltas["quantity"].toString()) ?? 0; return simpleNumberString(q); } else { return ""; } } + + String get userString { + return (jsondata["user_detail"]?["username"] ?? "") as String; + } } diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index 15ecf83..3c3771e 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -1,13 +1,14 @@ import "package:flutter/material.dart"; -import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/api.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/model.dart"; +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/refreshable_state.dart"; class StockItemHistoryWidget extends StatefulWidget { - const StockItemHistoryWidget(this.item, {Key? key}) : super(key: key); final InvenTreeStockItem item; @@ -16,60 +17,78 @@ class StockItemHistoryWidget extends StatefulWidget { _StockItemHistoryDisplayState createState() => _StockItemHistoryDisplayState(item); } - class _StockItemHistoryDisplayState extends RefreshableState { - _StockItemHistoryDisplayState(this.item); final InvenTreeStockItem item; + bool showFilterOptions = false; + @override String getAppBarTitle() => L10().stockItemHistory; - List history = []; - @override - Future request(BuildContext refresh) async { - - history.clear(); - - await InvenTreeStockItemHistory().list(filters: {"item": "${item.pk}"}).then((List results) { - for (var result in results) { - if (result is InvenTreeStockItemHistory) { - history.add(result); - } - } - - // Refresh - setState(() { - }); - }); - } + List appBarActions(BuildContext context) => []; @override Widget getBody(BuildContext context) { - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: historyList(), - ).toList() + Map filters = { + "item": widget.item.pk.toString(), + }; + + return PaginatedStockHistoryList(filters, showFilterOptions); + } + +} + +/* + * Widget which displays a paginated stock history list + */ +class PaginatedStockHistoryList extends PaginatedSearchWidget { + const PaginatedStockHistoryList(Map filters, bool showSearch) + : super(filters: filters, showSearch: showSearch); + + @override + _PaginatedStockHistoryState createState() => _PaginatedStockHistoryState(); +} + +/* + * State class for the paginated stock history list + */ +class _PaginatedStockHistoryState + extends PaginatedSearchState { + _PaginatedStockHistoryState() : super(); + + @override + String get prefix => "stock_history"; + + @override + Map get orderingOptions => {}; + + @override + Map> get filterOptions => { + // TODO: Add filter options + }; + + @override + Future requestPage( + int limit, int offset, Map params) async { + await InvenTreeAPI().StockHistoryStatus.load(); + + final page = await InvenTreeStockItemHistory().listPaginated(limit, offset, filters: params); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeStockItemHistory entry = model as InvenTreeStockItemHistory; + + return ListTile( + leading: Text(entry.dateString), + trailing: entry.userString.isNotEmpty ? Text(entry.userString) : null, + title: Text(entry.label), + subtitle: entry.notes.isNotEmpty ? Text(entry.notes) : null, ); } - - List historyList() { - List tiles = []; - - for (var entry in history) { - tiles.add( - ListTile( - leading: Text(entry.dateString), - trailing: entry.quantityString.isNotEmpty ? Text(entry.quantityString) : null, - title: Text(entry.label), - subtitle: entry.notes.isNotEmpty ? Text(entry.notes) : null, - ) - ); - } - - return tiles; - } -} \ No newline at end of file +} From 612db9f1949c3cf941e1a4e1bc9a8fdd826632de Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 18 Apr 2023 23:07:24 +1000 Subject: [PATCH 342/746] Improvements for dark mode (#322) * Action colors are now determined based on theme * Fix unused import * Update some more colors based on theme * Updated release notes * Better color choice * Update for home screen * Updates for app drawer * remove unused import --- assets/release_notes.md | 1 + lib/app_colors.dart | 19 +++++++----- lib/settings/about.dart | 10 +++---- lib/settings/login.dart | 2 +- lib/settings/settings.dart | 10 +++---- lib/widget/attachment_widget.dart | 4 +-- lib/widget/category_display.dart | 2 +- lib/widget/company_detail.dart | 14 ++++----- lib/widget/drawer.dart | 13 ++++---- lib/widget/home.dart | 40 ++++--------------------- lib/widget/location_display.dart | 2 +- lib/widget/paginator.dart | 2 +- lib/widget/part_detail.dart | 20 ++++++------- lib/widget/purchase_order_detail.dart | 4 +-- lib/widget/search.dart | 2 +- lib/widget/stock_detail.dart | 14 ++++----- lib/widget/stock_item_test_results.dart | 2 +- 17 files changed, 69 insertions(+), 92 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 07a3df3..f35de38 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Bug fix for stock history widget - Improved display of stock history widget +- Theme improvements for dark mode ### 0.11.3 - April 2023 --- diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 065a86f..a5556a0 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -1,16 +1,21 @@ -import "dart:ui"; +import "package:flutter/material.dart"; +import "package:one_context/one_context.dart"; const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 1); -const Color COLOR_CLICK = Color.fromRGBO(150, 120, 100, 0.9); +// Return an "action" color based on the current theme +Color get COLOR_ACTION { -const Color COLOR_BLUE = Color.fromRGBO(0, 0, 250, 1); + BuildContext? context = OneContext().context; -const Color COLOR_STAR = Color.fromRGBO(250, 250, 100, 1); + if (context != null) { + return Theme.of(context).indicatorColor; + } else { + return Colors.lightBlue; + } +} const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); const Color COLOR_DANGER = Color.fromRGBO(250, 50, 50, 1); const Color COLOR_SUCCESS = Color.fromRGBO(50, 250, 50, 1); -const Color COLOR_PROGRESS = Color.fromRGBO(50, 50, 250, 1); - -const Color COLOR_SELECTED = Color.fromRGBO(0, 0, 0, 0.05); \ No newline at end of file +const Color COLOR_PROGRESS = Color.fromRGBO(50, 50, 250, 1); \ No newline at end of file diff --git a/lib/settings/about.dart b/lib/settings/about.dart index b398ed3..84578e0 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -165,7 +165,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), onTap: () { _releaseNotes(context); }, @@ -176,7 +176,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().credits), subtitle: Text(L10().appCredits), - leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_ACTION), onTap: () { _credits(context); } @@ -187,7 +187,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().documentation), subtitle: Text("https://docs.inventree.org"), - leading: FaIcon(FontAwesomeIcons.book, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.book, color: COLOR_ACTION), onTap: () { _openDocs(); }, @@ -198,7 +198,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().translate), subtitle: Text(L10().translateHelp), - leading: FaIcon(FontAwesomeIcons.language, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.language, color: COLOR_ACTION), onTap: () { _translate(); } @@ -209,7 +209,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().reportBug), subtitle: Text(L10().reportBugDescription), - leading: FaIcon(FontAwesomeIcons.bug, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.bug, color: COLOR_ACTION), onTap: () { _reportBug(context); }, diff --git a/lib/settings/login.dart b/lib/settings/login.dart index aa9a9d4..185a779 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -137,7 +137,7 @@ class _InvenTreeLoginSettingsState extends State { title: Text( profile.name, ), - tileColor: profile.selected ? COLOR_SELECTED : null, + tileColor: profile.selected ? Theme.of(context).secondaryHeaderColor : null, subtitle: Text("${profile.server}"), trailing: _getProfileIcon(profile), onTap: () { diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index ed589e1..b202e6d 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -47,7 +47,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().server), subtitle: Text(L10().configureServer), - leading: FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.server, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget())); }, @@ -55,7 +55,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); } @@ -63,7 +63,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), - leading: FaIcon(FontAwesomeIcons.house, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.house, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } @@ -71,7 +71,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().part), subtitle: Text(L10().partSettings), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePartSettingsWidget())); } @@ -79,7 +79,7 @@ class _InvenTreeSettingsState extends State { Divider(), ListTile( title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.circleInfo), + leading: FaIcon(FontAwesomeIcons.circleInfo, color: COLOR_ACTION), onTap: _about, ) ] diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 47bcc65..bdfb415 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -170,7 +170,7 @@ class _AttachmentWidgetState extends RefreshableState { tiles.add(ListTile( title: Text(attachment.filename), subtitle: Text(attachment.comment), - leading: FaIcon(attachment.icon, color: COLOR_CLICK), + leading: FaIcon(attachment.icon, color: COLOR_ACTION), onTap: () async { showLoadingOverlay(context); await attachment.downloadAttachment(); @@ -186,7 +186,7 @@ class _AttachmentWidgetState extends RefreshableState { tiles.add(ListTile( title: Text(attachment.link), subtitle: Text(attachment.comment), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), onTap: () async { var uri = Uri.tryParse(attachment.link.trimLeft()); if (uri != null && await canLaunchUrl(uri)) { diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 2090687..404150d 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -151,7 +151,7 @@ class _CategoryDisplayState extends RefreshableState { subtitle: Text("${widget.category?.parentPathString}"), leading: FaIcon( FontAwesomeIcons.turnUp, - color: COLOR_CLICK, + color: COLOR_ACTION, ), onTap: () async { diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index f5cc36b..ff62fd4 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -149,7 +149,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.website.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.website}"), - leading: FaIcon(FontAwesomeIcons.globe, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.globe, color: COLOR_ACTION), onTap: () async { openLink(widget.company.website); }, @@ -161,7 +161,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.email.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.email}"), - leading: FaIcon(FontAwesomeIcons.at, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.at, color: COLOR_ACTION), onTap: () async { openLink("mailto:${widget.company.email}"); }, @@ -173,7 +173,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.phone.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.phone}"), - leading: FaIcon(FontAwesomeIcons.phone, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.phone, color: COLOR_ACTION), onTap: () { openLink("tel:${widget.company.phone}"); }, @@ -186,7 +186,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.link.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), onTap: () { widget.company.openLink(); }, @@ -205,7 +205,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().supplierParts), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), trailing: Text(supplierPartCount.toString()), onTap: () { Navigator.push( @@ -224,7 +224,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_ACTION), trailing: Text("${outstandingOrders.length}"), onTap: () { Navigator.push( @@ -272,7 +272,7 @@ class _CompanyDetailState extends RefreshableState { if (api.supportCompanyAttachments) { tiles.add(ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 6f438ec..a745d2b 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/widget/category_display.dart"; @@ -84,7 +85,7 @@ class InvenTreeDrawer extends StatelessWidget { // "Home" access tiles.add(ListTile( - leading: FaIcon(FontAwesomeIcons.house), + leading: FaIcon(FontAwesomeIcons.house, color: COLOR_ACTION), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -98,7 +99,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().parts), - leading: FaIcon(FontAwesomeIcons.shapes), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), onTap: _parts, ) ); @@ -108,7 +109,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().stock), - leading: FaIcon(FontAwesomeIcons.boxesStacked), + leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_ACTION), onTap: _stock, ) ); @@ -118,7 +119,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.cartShopping), + leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_ACTION), onTap: _purchaseOrders, ) ); @@ -133,7 +134,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( - leading: FaIcon(FontAwesomeIcons.bell), + leading: FaIcon(FontAwesomeIcons.bell, color: COLOR_ACTION), trailing: notification_count > 0 ? Text(notification_count.toString()) : null, title: Text(L10().notifications), onTap: _notifications, @@ -144,7 +145,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().settings), - leading: Icon(Icons.settings), + leading: Icon(Icons.settings, color: COLOR_ACTION), onTap: _settings, ) ); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index c525c0d..30c3db8 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -7,10 +7,8 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; -import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/login.dart"; -import "package:inventree/settings/settings.dart"; import "package:inventree/user_profile.dart"; import "package:inventree/widget/category_display.dart"; @@ -63,22 +61,12 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr // Selected user profile UserProfile? _profile; - void _scan(BuildContext context) { - if (!InvenTreeAPI().checkConnection()) return; - - scanQrCode(context); - } - void _showParts(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } - void _showSettings(BuildContext context) { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget())); - } - void _showStarredParts(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; @@ -187,7 +175,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr horizontal: 12 ), child: ListTile( - leading: FaIcon(icon, color: connected && allowed ? COLOR_CLICK : Colors.grey), + leading: FaIcon(icon, color: connected && allowed ? COLOR_ACTION : Colors.grey), title: Text(label), trailing: trailing, ), @@ -217,17 +205,9 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr */ List getListTiles(BuildContext context) { - List tiles = []; - - // Barcode scanner - tiles.add(_listTile( - context, - L10().scanBarcode, - Icons.qr_code_scanner, - callback: () { - _scan(context); - } - )); + List tiles = [ + Divider(height: 5) + ]; // Parts tiles.add(_listTile( @@ -314,16 +294,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } */ - // Settings - tiles.add(_listTile( - context, - L10().settings, - FontAwesomeIcons.gears, - callback: () { - _showSettings(context); - } - )); - return tiles; } @@ -338,7 +308,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); Widget leading = FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER); - Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK); + Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_ACTION); String title = L10().serverNotConnected; String subtitle = L10().profileSelectOrCreate; diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index f5518a3..dec7be6 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -295,7 +295,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().parentLocation), subtitle: Text("${location!.parentPathString}"), - leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_ACTION), onTap: () async { int parentId = location?.parentId ?? -1; diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 77f70f5..e9cc4cf 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -410,7 +410,7 @@ abstract class PaginatedSearchState extends Sta Widget buildSearchInput(BuildContext context) { return ListTile( trailing: orderingOptions.isEmpty ? null : GestureDetector( - child: FaIcon(FontAwesomeIcons.sort, color: COLOR_CLICK), + child: FaIcon(FontAwesomeIcons.sort, color: COLOR_ACTION), onTap: () async { _saveOrderingOptions(context); }, diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index be397dc..7f3b645 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -261,7 +261,7 @@ class _PartDisplayState extends RefreshableState { subtitle: Text("${part.description}"), trailing: IconButton( icon: FaIcon(part.starred ? FontAwesomeIcons.solidStar : FontAwesomeIcons.star, - color: part.starred ? COLOR_STAR : null, + color: part.starred ? Colors.yellowAccent : null, ), onPressed: () { _toggleStar(context); @@ -349,7 +349,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().partCategory), subtitle: Text("${part.categoryName}"), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_ACTION), onTap: () async { if (part.categoryId > 0) { @@ -370,7 +370,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().partCategory), subtitle: Text(L10().partCategoryTopLevel), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute( builder: (context) => CategoryDisplayWidget(null))); @@ -384,7 +384,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().variants), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), trailing: Text(variantCount.toString()), onTap: () { Navigator.push( @@ -442,7 +442,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_ACTION), trailing: Text(bomCount.toString()), ) ); @@ -468,7 +468,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().usedIn), subtitle: Text(L10().usedInDetails), - leading: FaIcon(FontAwesomeIcons.layerGroup, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.layerGroup, color: COLOR_ACTION), trailing: Text(usedInCount.toString()), onTap: () { Navigator.push( @@ -498,7 +498,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("${part.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), onTap: () { part.openLink(); }, @@ -528,7 +528,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.industry, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.industry, color: COLOR_ACTION), trailing: Text("${part.supplierCount}"), onTap: () { Navigator.push( @@ -547,7 +547,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), trailing: Text(""), onTap: () { Navigator.push( @@ -561,7 +561,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 3b7d1ee..06dd8a6 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -205,7 +205,7 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 07860db..750717e 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -358,7 +358,7 @@ class _SearchDisplayState extends RefreshableState { trailing: GestureDetector( child: FaIcon( searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, - color: searchController.text.isEmpty ? COLOR_CLICK : COLOR_DANGER, + color: searchController.text.isEmpty ? COLOR_ACTION : COLOR_DANGER, ), onTap: () { searchController.clear(); diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 5dced70..0149e09 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -633,7 +633,7 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text("${widget.item.locationPathString}"), leading: FaIcon( FontAwesomeIcons.locationDot, - color: COLOR_CLICK, + color: COLOR_ACTION, ), onTap: () async { if (widget.item.locationId > 0) { @@ -666,7 +666,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), trailing: InvenTreeAPI().getImage( widget.item.supplierImage, width: 40, @@ -748,7 +748,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("${widget.item.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), onTap: () { widget.item.openLink(); }, @@ -760,7 +760,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().testResults), - leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_ACTION), trailing: Text("${widget.item.testResultCount}"), onTap: () { Navigator.push( @@ -793,7 +793,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_ACTION), trailing: Text("${widget.item.trackingItemCount}"), onTap: () { Navigator.push( @@ -812,7 +812,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), onTap: () { Navigator.push( context, @@ -825,7 +825,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index 817e7c3..fc0ef4b 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -158,7 +158,7 @@ class _StockItemTestResultDisplayState extends RefreshableState Date: Wed, 19 Apr 2023 20:54:52 +1000 Subject: [PATCH 343/746] Add transparent background image (#323) - Fixes display of background image in dark mode --- assets/image/logo_transparent.png | Bin 0 -> 111607 bytes assets/release_notes.md | 5 ++++- lib/widget/home.dart | 2 +- pubspec.yaml | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 assets/image/logo_transparent.png diff --git a/assets/image/logo_transparent.png b/assets/image/logo_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..f5045cf0a340a0f77e05c06766ec9a012363e87b GIT binary patch literal 111607 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 JZ>Rm~{{!<0p&S4J literal 0 HcmV?d00001 diff --git a/assets/release_notes.md b/assets/release_notes.md index f35de38..b9220c5 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,9 @@ -## InvenTree App Release Notes +### 0.11.5 - April 2023 --- +- Fix background image transparency for dark mode + + ### 0.11.4 - April 2023 --- diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 30c3db8..bd5701c 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -324,7 +324,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr child: Column( children: [ Image.asset( - "assets/image/icon.png", + "assets/image/logo_transparent.png", color: Colors.white.withOpacity(0.2), colorBlendMode: BlendMode.modulate, scale: 0.5, diff --git a/pubspec.yaml b/pubspec.yaml index 811d293..e5415a7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -64,6 +64,7 @@ flutter: assets: - assets/image/icon.png + - assets/image/logo_transparent.png - assets/release_notes.md - assets/credits.md - assets/sounds/barcode_scan.mp3 From ba1df2e8174a2be5f747ffd3ff012905edd626f1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 19 Apr 2023 20:57:40 +1000 Subject: [PATCH 344/746] Adds invoke script for automating release tasks (#324) --- tasks.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tasks.py diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..c1629db --- /dev/null +++ b/tasks.py @@ -0,0 +1,27 @@ +"""Invoke tasks for building the app""" + +from invoke import task + + +@task +def clean(c): + """Clean flutter build""" + c.run("flutter clean") + + +@task +def translate(c): + """Update translation files""" + c.run("cd lib/l10n && python collect_translations.py") + + +@task(pre=[clean, translate]) +def ios(c): + """Build iOS app""" + c.run("flutter build ipa --release --no-tree-shake-icons") + + +@task(pre=[clean, translate]) +def android(c): + """Build Android app""" + c.run("flutter build appbundle --release --no-tree-shake-icons") From 87994a491295f5e27321e8f1e12972590356ca8c Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 19 Apr 2023 21:07:56 +1000 Subject: [PATCH 345/746] Re-implement BOM link from part view (#325) --- assets/release_notes.md | 1 + lib/widget/part_detail.dart | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index b9220c5..9afdab8 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Fix background image transparency for dark mode +- Fix link to Bill of Materials from Part screen ### 0.11.4 - April 2023 diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 7f3b645..485b35b 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -444,6 +444,11 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().billOfMaterials), leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_ACTION), trailing: Text(bomCount.toString()), + onTap: () { + Navigator.push(context, MaterialPageRoute( + builder: (context) => BillOfMaterialsWidget(part, isParentComponent: true) + )); + }, ) ); } From 28ed1ed54586c2e821651311c5687d7a5ad46936 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 19 Apr 2023 21:17:24 +1000 Subject: [PATCH 346/746] Improve supplier part detail screen (#326) * Improve supplier part detail screen * Update release notes --- assets/release_notes.md | 1 + lib/inventree/company.dart | 2 ++ lib/l10n/app_en.arb | 12 +++++++ lib/widget/supplier_part_detail.dart | 48 ++++++++++++++++++++++------ 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 9afdab8..7ada37f 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Fix background image transparency for dark mode - Fix link to Bill of Materials from Part screen +- Improvements to supplier part detail screen ### 0.11.4 - April 2023 diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index a0d37a0..ae711b7 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -148,6 +148,8 @@ class InvenTreeSupplierPart extends InvenTreeModel { return _filters(); } + int get manufacturerId => (jsondata["manufacturer_detail"]["pk"] ?? -1) as int; + String get manufacturerName => (jsondata["manufacturer_detail"]?["name"] ?? "") as String; String get MPN => (jsondata["manufacturer_part_detail"]?["MPN"] ?? "") as String; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 661e300..2d353b7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -464,6 +464,9 @@ "inProductionDetail": "This stock item is in production", "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", "@invalidHost": {}, @@ -555,6 +558,12 @@ "lost": "Lost", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", "@manufacturers": {}, @@ -1146,6 +1155,9 @@ "supplierPartEdit": "Edit Supplier Part", "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", "@supplierPartUpdated": {}, diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index 9435e64..85661d4 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -3,6 +3,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/l10.dart"; @@ -117,9 +118,10 @@ class _SupplierPartDisplayState extends RefreshableState 0) { tiles.add( ListTile( + title: Text(L10().manufacturer), subtitle: Text(widget.supplierPart.manufacturerName), - title: Text(widget.supplierPart.MPN), - leading: FaIcon(FontAwesomeIcons.industry), + leading: FaIcon(FontAwesomeIcons.industry, color: COLOR_ACTION), trailing: InvenTreeAPI().getImage( widget.supplierPart.manufacturerImage, width: 40, height: 40, - ) + ), + onTap: () async { + showLoadingOverlay(context); + var supplier = await InvenTreeCompany().get(widget.supplierPart.manufacturerId); + hideLoadingOverlay(); + + if (supplier is InvenTreeCompany) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => CompanyDetailWidget(supplier) + )); + } + } + ) + ); + + tiles.add( + ListTile( + title: Text(L10().manufacturerPartNumber), + subtitle: Text(widget.supplierPart.MPN), + leading: FaIcon(FontAwesomeIcons.barcode), ) ); } @@ -182,7 +212,7 @@ class _SupplierPartDisplayState extends RefreshableState Date: Wed, 19 Apr 2023 21:57:28 +1000 Subject: [PATCH 347/746] Make notes widget "generic" (#327) * Make notes widget "generic" - No longer tied to the "part" model - Will allow us to use it elsewhere * Update release notes * Add helper methods for checking model permissions * Refactoring of permissions checks * Add notes to the "purchase order" widget * Fix typos * remove bom tab from part view * linting fixes --- assets/release_notes.md | 1 + lib/api.dart | 4 + lib/inventree/company.dart | 6 ++ lib/inventree/model.dart | 57 ++++++++++++++ lib/inventree/part.dart | 6 ++ lib/inventree/purchase_order.dart | 3 + lib/inventree/stock.dart | 9 +++ lib/widget/category_display.dart | 6 +- lib/widget/company_detail.dart | 20 +++-- lib/widget/drawer.dart | 9 ++- lib/widget/location_display.dart | 10 +-- .../{part_notes.dart => notes_widget.dart} | 37 +++++---- lib/widget/part_detail.dart | 23 ++---- lib/widget/part_image_widget.dart | 2 +- lib/widget/purchase_order_detail.dart | 34 ++++++-- lib/widget/purchase_order_list.dart | 2 +- lib/widget/search.dart | 20 ++--- lib/widget/stock_detail.dart | 25 +++--- lib/widget/stock_notes.dart | 77 ------------------- lib/widget/supplier_part_detail.dart | 9 +-- 20 files changed, 192 insertions(+), 168 deletions(-) rename lib/widget/{part_notes.dart => notes_widget.dart} (59%) delete mode 100644 lib/widget/stock_notes.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 7ada37f..a298327 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ - Fix background image transparency for dark mode - Fix link to Bill of Materials from Part screen - Improvements to supplier part detail screen +- Add "notes" field to more models ### 0.11.4 - April 2023 diff --git a/lib/api.dart b/lib/api.dart index fb883fa..0950eeb 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -650,16 +650,20 @@ class InvenTreeAPI { * e.g. "part", "change" */ bool checkPermission(String role, String permission) { + // If we do not have enough information, assume permission is allowed if (roles.isEmpty) { + debug("checkPermission - no roles defined!"); return true; } if (!roles.containsKey(role)) { + debug("checkPermission - role '$role' not found!"); return true; } if (roles[role] == null) { + debug("checkPermission - role '$role' is null!"); return true; } diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index ae711b7..7af1229 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -18,6 +18,9 @@ class InvenTreeCompany extends InvenTreeModel { @override String get URL => "company/"; + @override + List get rolesRequired => ["purchase_order", "sales_order", "return_order"]; + @override Map formFields() { return { @@ -118,6 +121,9 @@ class InvenTreeSupplierPart extends InvenTreeModel { @override String get URL => "company/part/"; + @override + List get rolesRequired => ["part", "purchase_order"]; + @override Map formFields() { return { diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 7c75129..576329f 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -10,6 +10,7 @@ import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; import "package:inventree/fa_icon_mapping.dart"; import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/widget/dialogs.dart"; @@ -78,7 +79,63 @@ class InvenTreeModel { } else { return ""; } + } + /* Return a list of roles which may be required for this model + * If multiple roles are required, *any* role which passes the check is sufficient + */ + List get rolesRequired { + // Default implementation should not be called + debug("rolesRequired() not implemented for model ${URL} - returning empty list"); + return []; + } + + // Test if the user can "edit" this model + bool get canEdit { + for (String role in rolesRequired) { + if (InvenTreeAPI().checkPermission(role, "change")) { + return true; + } + } + + // Fallback + return false; + } + + // Test if the user can "create" this model + bool get canCreate { + for (String role in rolesRequired) { + if (InvenTreeAPI().checkPermission(role, "add")) { + return true; + } + } + + // Fallback + return false; + } + + // Test if the user can "delete" this model + bool get canDelete { + for (String role in rolesRequired) { + if (InvenTreeAPI().checkPermission(role, "delete")) { + return true; + } + } + + // Fallback + return false; + } + + // Test if the user can "view" this model + bool get canView { + for (String role in rolesRequired) { + if (InvenTreeAPI().checkPermission(role, "view")) { + return true; + } + } + + // Fallback + return false; } // Fields for editing / creating this model diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 339382b..e2ef2d9 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -23,6 +23,9 @@ class InvenTreePartCategory extends InvenTreeModel { @override String get URL => "part/category/"; + @override + List get rolesRequired => ["part_category"]; + @override Map formFields() { @@ -182,6 +185,9 @@ class InvenTreePart extends InvenTreeModel { @override String get URL => "part/"; + @override + List get rolesRequired => ["part"]; + @override Map formFields() { return { diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index abfd0ba..53a297a 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -18,6 +18,9 @@ class InvenTreePurchaseOrder extends InvenTreeModel { @override String get URL => "order/po/"; + @override + List get rolesRequired => ["purchase_order"]; + String get receive_url => "${url}receive/"; @override diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index ab6cc14..cd22e3f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -20,6 +20,9 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { @override String get URL => "stock/test/"; + @override + List get rolesRequired => ["stock"]; + @override Map formFields() { return { @@ -134,6 +137,9 @@ class InvenTreeStockItem extends InvenTreeModel { @override String get URL => "stock/"; + @override + List get rolesRequired => ["stock"]; + // URLs for performing stock actions static String transferStockUrl() => "stock/transfer/"; @@ -611,6 +617,9 @@ class InvenTreeStockLocation extends InvenTreeModel { @override String get URL => "stock/location/"; + @override + List get rolesRequired => ["stock_location"]; + String get pathstring => (jsondata["pathstring"] ?? "") as String; @override diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 404150d..31ead03 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -40,7 +40,7 @@ class _CategoryDisplayState extends RefreshableState { List actions = []; if (widget.category != null) { - if (api.checkPermission("part_category", "change")) { + if (InvenTreePartCategory().canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -60,7 +60,7 @@ class _CategoryDisplayState extends RefreshableState { List actionButtons(BuildContext context) { List actions = []; - if (api.checkPermission("part", "add")) { + if (InvenTreePart().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.shapes), @@ -70,7 +70,7 @@ class _CategoryDisplayState extends RefreshableState { ); } - if (api.checkPermission("part_category", "add")) { + if (InvenTreePartCategory().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.sitemap), diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index ff62fd4..c1d98a5 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -49,17 +49,15 @@ class _CompanyDetailState extends RefreshableState { List appBarActions(BuildContext context) { List actions = []; - if (api.checkPermission("purchase_order", "change") || - api.checkPermission("sales_order", "change") || - api.checkPermission("return_order", "change")) { + if (InvenTreeCompany().canEdit) { actions.add( - IconButton( - icon: Icon(Icons.edit_square), - tooltip: L10().companyEdit, - onPressed: () { - editCompany(context); - } - ) + IconButton( + icon: Icon(Icons.edit_square), + tooltip: L10().companyEdit, + onPressed: () { + editCompany(context); + } + ) ); } @@ -281,7 +279,7 @@ class _CompanyDetailState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreeCompanyAttachment(), widget.company.pk, - api.checkPermission("purchase_order", "change") || api.checkPermission("sales_order", "change") + InvenTreeCompany().canEdit ) ) ); diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index a745d2b..2ca8d88 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -3,6 +3,9 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/stock.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/settings.dart"; import "package:inventree/widget/category_display.dart"; @@ -95,7 +98,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add(Divider()); - if (InvenTreeAPI().checkPermission("part_category", "view")) { + if (InvenTreeCompany().canView) { tiles.add( ListTile( title: Text(L10().parts), @@ -105,7 +108,7 @@ class InvenTreeDrawer extends StatelessWidget { ); } - if (InvenTreeAPI().checkPermission("stock_location", "view")) { + if (InvenTreeStockLocation().canView) { tiles.add( ListTile( title: Text(L10().stock), @@ -115,7 +118,7 @@ class InvenTreeDrawer extends StatelessWidget { ); } - if (InvenTreeAPI().checkPermission("purchase_order", "view")) { + if (InvenTreePurchaseOrder().canView) { tiles.add( ListTile( title: Text(L10().purchaseOrders), diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index dec7be6..38cc63d 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -63,7 +63,7 @@ class _LocationDisplayState extends RefreshableState { } // Add "edit" button - if (location != null && api.checkPermission("stock_location", "change")) { + if (location != null && InvenTreeStockLocation().canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -85,7 +85,7 @@ class _LocationDisplayState extends RefreshableState { if (location != null) { // Scan items into this location - if (api.checkPermission("stock", "change")) { + if (InvenTreeStockItem().canEdit) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.qrcode), @@ -105,7 +105,7 @@ class _LocationDisplayState extends RefreshableState { } // Scan this location into another one - if (api.checkPermission("stock_location", "change")) { + if (InvenTreeStockLocation().canEdit) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.qrcode), @@ -144,7 +144,7 @@ class _LocationDisplayState extends RefreshableState { List actions = []; // Create new location - if (api.checkPermission("stock_location", "add")) { + if (InvenTreeStockLocation().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.sitemap), @@ -157,7 +157,7 @@ class _LocationDisplayState extends RefreshableState { } // Create new item - if (location != null && api.checkPermission("stock", "add")) { + if (location != null && InvenTreeStockItem().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.boxesStacked), diff --git a/lib/widget/part_notes.dart b/lib/widget/notes_widget.dart similarity index 59% rename from lib/widget/part_notes.dart rename to lib/widget/notes_widget.dart index 15b9ee7..a5c1146 100644 --- a/lib/widget/part_notes.dart +++ b/lib/widget/notes_widget.dart @@ -1,49 +1,56 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; -import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/model.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:flutter_markdown/flutter_markdown.dart"; import "package:inventree/l10.dart"; -class PartNotesWidget extends StatefulWidget { +/* + * A widget for displaying the notes associated with a given model. + * We need to pass in the following parameters: + * + * - Model instance + * - Title for the app bar + */ +class NotesWidget extends StatefulWidget { - const PartNotesWidget(this.part, {Key? key}) : super(key: key); + const NotesWidget(this.model, {Key? key}) : super(key: key); - final InvenTreePart part; + final InvenTreeModel model; @override - _PartNotesState createState() => _PartNotesState(part); + _NotesState createState() => _NotesState(); } -class _PartNotesState extends RefreshableState { +/* + * Class representing the state of the NotesWidget + */ +class _NotesState extends RefreshableState { - _PartNotesState(this.part); - - final InvenTreePart part; + _NotesState(); @override Future request(BuildContext context) async { - await part.reload(); + await widget.model.reload(); } @override - String getAppBarTitle() => L10().partNotes; + String getAppBarTitle() => L10().editNotes; @override List appBarActions(BuildContext context) { List actions = []; - if (InvenTreeAPI().checkPermission("part", "change")) { + if (widget.model.canEdit) { actions.add( IconButton( icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { - part.editForm( + widget.model.editForm( context, L10().editNotes, fields: { @@ -67,7 +74,7 @@ class _PartNotesState extends RefreshableState { Widget getBody(BuildContext context) { return Markdown( selectable: false, - data: part.notes, + data: widget.model.notes, ); } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 485b35b..bcfb733 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -16,7 +16,7 @@ import "package:inventree/preferences.dart"; import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/bom_list.dart"; import "package:inventree/widget/part_list.dart"; -import "package:inventree/widget/part_notes.dart"; +import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/part_parameter_widget.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/category_display.dart"; @@ -72,7 +72,7 @@ class _PartDisplayState extends RefreshableState { List appBarActions(BuildContext context) { List actions = []; - if (api.checkPermission("part", "change")) { + if (InvenTreePart().canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -90,7 +90,7 @@ class _PartDisplayState extends RefreshableState { List barcodeButtons(BuildContext context) { List actions = []; - if (api.checkPermission("part", "change")) { + if (InvenTreePart().canEdit) { if (api.supportModernBarcodes) { actions.add( customBarcodeAction( @@ -109,7 +109,7 @@ class _PartDisplayState extends RefreshableState { List actionButtons(BuildContext context) { List actions = []; - if (api.checkPermission("stock", "add")) { + if (InvenTreeStockItem().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.box), @@ -234,7 +234,7 @@ class _PartDisplayState extends RefreshableState { */ Future _toggleStar(BuildContext context) async { - if (api.checkPermission("part", "view")) { + if (InvenTreePart().canView) { showLoadingOverlay(context); await part.update(values: {"starred": "${!part.starred}"}); hideLoadingOverlay(); @@ -557,7 +557,7 @@ class _PartDisplayState extends RefreshableState { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => PartNotesWidget(part)) + MaterialPageRoute(builder: (context) => NotesWidget(part)) ); }, ) @@ -575,7 +575,8 @@ class _PartDisplayState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreePartAttachment(), part.pk, - api.checkPermission("part", "change")) + part.canEdit + ) ) ); }, @@ -678,10 +679,6 @@ class _PartDisplayState extends RefreshableState { Tab(text: L10().stock) ]; - if (showBom && part.isAssembly) { - icons.add(Tab(text: L10().bom)); - } - if (showParameters) { icons.add(Tab(text: L10().parameters)); } @@ -703,10 +700,6 @@ class _PartDisplayState extends RefreshableState { PaginatedStockItemList({"part": part.pk.toString()}, true) ]; - if (showBom && part.isAssembly) { - tabs.add(PaginatedBomList({"part": part.pk.toString()}, showSearch: true, isParentPart: true)); - } - if (showParameters) { tabs.add(PaginatedParameterList({"part": part.pk.toString()}, true)); } diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart index c548e8e..68b12bd 100644 --- a/lib/widget/part_image_widget.dart +++ b/lib/widget/part_image_widget.dart @@ -42,7 +42,7 @@ class _PartImageState extends RefreshableState { List actions = []; - if (InvenTreeAPI().checkPermission("part", "change")) { + if (part.canEdit) { // File upload actions.add( diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 06dd8a6..1e405f0 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -14,6 +14,7 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/company_detail.dart"; +import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_list.dart"; @@ -49,7 +50,7 @@ class _PurchaseOrderDetailState extends RefreshableState appBarActions(BuildContext context) { List actions = []; - if (InvenTreeAPI().checkPermission("purchase_order", "change")) { + if (order.canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -68,7 +69,7 @@ class _PurchaseOrderDetailState extends RefreshableState actionButtons(BuildContext context) { List actions = []; - if (api.checkPermission("purchase_order", "add")) { + if (order.canCreate) { if (order.isPending) { actions.add( SpeedDialChild( @@ -255,6 +256,22 @@ class _PurchaseOrderDetailState extends RefreshableState NotesWidget(order) + ) + ); + }, + ) + ); + // Attachments tiles.add( ListTile( @@ -263,13 +280,14 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreePurchaseOrderAttachment(), - order.pk, - InvenTreeAPI().checkPermission("purchase_order", "change")) + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreePurchaseOrderAttachment(), + order.pk, + order.canEdit ) + ) ); }, ) diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index f2e5141..a228198 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -52,7 +52,7 @@ class _PurchaseOrderListWidgetState extends RefreshableState actionButtons(BuildContext context) { List actions = []; - if (api.checkPermission("purchase_order", "add")) { + if (InvenTreePurchaseOrder().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.circlePlus), diff --git a/lib/widget/search.dart b/lib/widget/search.dart index 750717e..fd8fcab 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -207,29 +207,29 @@ class _SearchDisplayState extends RefreshableState { }; // Part search - if (api.checkPermission("part", "view")) { + if (InvenTreePart().canView) { body["part"] = {}; } // PartCategory search - if (api.checkPermission("part_category", "view")) { + if (InvenTreePartCategory().canView) { body["partcategory"] = {}; } // StockItem search - if (api.checkPermission("stock", "view")) { + if (InvenTreeStockItem().canView) { body["stockitem"] = { "in_stock": true, }; } // StockLocation search - if (api.checkPermission("stock_location", "view")) { + if (InvenTreeStockLocation().canView) { body["stocklocation"] = {}; } // PurchaseOrder search - if (api.checkPermission("purchase_order", "view")) { + if (InvenTreePurchaseOrder().canView) { body["purchaseorder"] = { "outstanding": true }; @@ -253,7 +253,7 @@ class _SearchDisplayState extends RefreshableState { Future legacySearch(String term) async { // Search parts - if (api.checkPermission("part", "view")) { + if (InvenTreePart().canView) { nPendingSearches++; InvenTreePart().count(searchQuery: term).then((int n) { if (term == searchController.text) { @@ -268,7 +268,7 @@ class _SearchDisplayState extends RefreshableState { } // Search part categories - if (api.checkPermission("part_category", "view")) { + if (InvenTreePartCategory().canView) { nPendingSearches++; InvenTreePartCategory().count(searchQuery: term,).then((int n) { if (term == searchController.text) { @@ -283,7 +283,7 @@ class _SearchDisplayState extends RefreshableState { } // Search stock items - if (api.checkPermission("stock", "view")) { + if (InvenTreeStockItem().canView) { nPendingSearches++; InvenTreeStockItem().count(searchQuery: term).then((int n) { if (term == searchController.text) { @@ -298,7 +298,7 @@ class _SearchDisplayState extends RefreshableState { } // Search stock locations - if (api.checkPermission("stock_location", "view")) { + if (InvenTreeStockLocation().canView) { nPendingSearches++; InvenTreeStockLocation().count(searchQuery: term).then((int n) { if (term == searchController.text) { @@ -313,7 +313,7 @@ class _SearchDisplayState extends RefreshableState { } // Search purchase orders - if (api.checkPermission("purchase_order", "view")) { + if (InvenTreePurchaseOrder().canView) { nPendingSearches++; InvenTreePurchaseOrder().count( searchQuery: term, diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 0149e09..b2dcc2c 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -25,7 +25,7 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_item_history.dart"; import "package:inventree/widget/stock_item_test_results.dart"; -import "package:inventree/widget/stock_notes.dart"; +import "package:inventree/widget/notes_widget.dart"; class StockDetailWidget extends StatefulWidget { @@ -64,7 +64,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (api.checkPermission("stock", "change")) { + if (widget.item.canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -84,7 +84,7 @@ class _StockItemDisplayState extends RefreshableState { List actions = []; - if (api.checkPermission("stock", "change")) { + if (widget.item.canEdit) { // Stock adjustment actions available if item is *not* serialized if (!widget.item.isSerialized()) { @@ -138,7 +138,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (api.checkPermission("stock", "delete")) { + if (widget.item.canDelete) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), @@ -157,7 +157,7 @@ class _StockItemDisplayState extends RefreshableState { List barcodeButtons(BuildContext context) { List actions = []; - if (api.checkPermission("stock", "change")) { + if (widget.item.canEdit) { // Scan item into location actions.add( SpeedDialChild( @@ -816,7 +816,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => StockNotesWidget(widget.item)) + MaterialPageRoute(builder: (context) => NotesWidget(widget.item)) ); } ) @@ -829,13 +829,14 @@ class _StockItemDisplayState extends RefreshableState { trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeStockItemAttachment(), - widget.item.pk, - InvenTreeAPI().checkPermission("stock", "change")) + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeStockItemAttachment(), + widget.item.pk, + widget.item.canEdit, ) + ) ); }, ) diff --git a/lib/widget/stock_notes.dart b/lib/widget/stock_notes.dart deleted file mode 100644 index c990d0e..0000000 --- a/lib/widget/stock_notes.dart +++ /dev/null @@ -1,77 +0,0 @@ - -import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/stock.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:flutter_markdown/flutter_markdown.dart"; -import "package:inventree/l10.dart"; - -import "package:inventree/api.dart"; - - -class StockNotesWidget extends StatefulWidget { - - const StockNotesWidget(this.item, {Key? key}) : super(key: key); - - final InvenTreeStockItem item; - - @override - _StockNotesState createState() => _StockNotesState(item); -} - - -class _StockNotesState extends RefreshableState { - - _StockNotesState(this.item); - - final InvenTreeStockItem item; - - @override - String getAppBarTitle() => L10().stockItemNotes; - - @override - Future request(BuildContext context) async { - if (item.pk > 0) { - await item.reload(); - } - } - - @override - List appBarActions(BuildContext context) { - List actions = []; - - if (InvenTreeAPI().checkPermission("stock", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), - tooltip: L10().edit, - onPressed: () { - item.editForm( - context, - L10().editNotes, - fields: { - "notes": { - "multiline": true, - } - }, - onSuccess: (data) async { - refresh(context); - } - ); - } - ) - ); - } - - return actions; - } - - @override - Widget getBody(BuildContext context) { - return Markdown( - selectable: false, - data: item.notes, - ); - } - -} \ No newline at end of file diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index 85661d4..662e266 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -57,10 +57,7 @@ class _SupplierPartDisplayState extends RefreshableState barcodeButtons(BuildContext context) { List actions = []; - if (api.checkPermission("purchase_order", "change") || - api.checkPermission("sales_order", "change") || - api.checkPermission("return_order", "change")) { - + if (widget.supplierPart.canEdit) { actions.add( customBarcodeAction( context, this, @@ -78,9 +75,7 @@ class _SupplierPartDisplayState extends RefreshableState appBarActions(BuildContext context) { List actions = []; - if (api.checkPermission("purchase_order", "change") || - api.checkPermission("sales_order", "change") || - api.checkPermission("return_order", "change")) { + if (widget.supplierPart.canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), From 8510034a81aa387e5c6c849556485970a4b89044 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 19 Apr 2023 22:04:18 +1000 Subject: [PATCH 348/746] Bump build version to 0.11.5 (#328) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e5415a7..36b1d51 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.4+63 +version: 0.11.5+64 environment: sdk: ">=2.16.0 <3.0.0" From caa4fdd2a1c324418af8904f4e145ed6b73c5e0c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 19 Apr 2023 23:05:16 +1000 Subject: [PATCH 349/746] Tweak to get invoke command to work on mac --- tasks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tasks.py b/tasks.py index c1629db..feda09d 100644 --- a/tasks.py +++ b/tasks.py @@ -1,5 +1,6 @@ """Invoke tasks for building the app""" +import sys from invoke import task @@ -12,7 +13,8 @@ def clean(c): @task def translate(c): """Update translation files""" - c.run("cd lib/l10n && python collect_translations.py") + python = 'python3' if sys.platform.lower() == 'darwin' else 'python' + c.run(f"cd lib/l10n && {python} collect_translations.py") @task(pre=[clean, translate]) From 0c4179480d484ec460e994814f64a183f9f964bd Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Apr 2023 18:41:03 +1000 Subject: [PATCH 350/746] New translations app_en.arb (Norwegian) (#331) --- lib/l10n/no_NO/app_no_NO.arb | 881 ++++++++++++++++++++++++++++++++++- 1 file changed, 880 insertions(+), 1 deletion(-) diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index f0ac65c..3c9740c 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -1,5 +1,884 @@ { "@@locale": "no", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Om", + "@about": {}, + "accountDetails": "Kontodetaljer", + "@accountDetails": {}, + "actions": "Handlinger", + "@actions": { + "description": "" + }, + "actionsNone": "Ingen handlinger tilgjengelig", + "@actionsNone": {}, + "add": "Legg til", + "@add": { + "description": "add" + }, + "addStock": "Legg til lagerbeholdning", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "Om InvenTree", + "@appAbout": {}, + "appCredits": "Ytterligere app-krediteringer", + "@appCredits": {}, + "appDetails": "App-detaljer", + "@appDetails": {}, + "appReleaseNotes": "Vis appens utgivelsesnotater", + "@appReleaseNotes": {}, + "appSettings": "Appinnstillinger", + "@appSettings": {}, + "appSettingsDetails": "Konfigurer InvenTree appinnstillinger", + "@appSettingsDetails": {}, + "attachments": "Vedlegg", + "@attachments": {}, + "attachImage": "Legg ved bilde", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Ingen vedlegg funnet", + "@attachmentNone": {}, + "attachmentNoneDetail": "Ingen vedlegg funnet", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Velg vedlegg", + "@attachmentSelect": {}, + "attention": "Merknad", + "@attention": {}, + "availableStock": "Tilgjengelig lagerbeholdning", + "@availableStock": {}, + "barcodeAssign": "Tildel Strekkode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Skann egendefinert strekkode for å tildele", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Strekkode tildelt", + "@barcodeAssigned": {}, + "barcodeError": "Feil under skanning av strekkode", + "@barcodeError": {}, + "barcodeInUse": "Strekkode allerede tildelt", + "@barcodeInUse": {}, + "barcodeMissingHash": "Strekkode-hash-data mangler fra svar", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Ingen treff for strekkode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Strekkode ikke tildelt", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Skann for å tildele strekkode", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Skann en InvenTree-strekkode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Skann lagervarer til denne lokasjonen", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skann lagerlokasjon", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Skannet til lokasjon", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artikkelen ble ikke skannet inn", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skann lagervare", + "@barcodeScanItem": {}, + "barcodeTones": "Strekkodetoner", + "@barcodeTones": {}, + "barcodeUnassign": "Fjern tildeling av strekkode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Strekkoden ble ikke gjenkjent", + "@barcodeUnknown": {}, + "batchCode": "Batchkode", + "@batchCode": {}, + "billOfMaterials": "Stykkliste", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Vis stykkliste", + "@bomEnable": {}, + "cancel": "Avbryt", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Kanseller ordre", + "@cancelOrder": {}, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Ny kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Opprett ny del-kategori", + "@categoryCreateDetail": {}, + "categoryUpdated": "Del-kategori oppdatert", + "@categoryUpdated": {}, + "company": "Bedrift", + "@company": {}, + "companyEdit": "Rediger bedrift", + "@companyEdit": {}, + "companyNoResults": "Ingen bedrifter samsvarer spørringen", + "@companyNoResults": {}, + "companyUpdated": "Bedriftsinformasjon oppdatert", + "@companyUpdated": {}, + "companies": "Bedrifter", + "@companies": {}, + "configureServer": "Konfigurer serverinnstillinger", + "@configureServer": {}, + "connectionRefused": "Tilkobling avvist", + "@connectionRefused": {}, + "count": "Antall", + "@count": { + "description": "Count" + }, + "countStock": "Tell beholdning", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Krediteringer", + "@credits": {}, + "customers": "Kunder", + "@customers": {}, + "damaged": "Skadet", + "@damaged": {}, + "darkMode": "Mørk Modus", + "@darkMode": {}, + "darkModeEnable": "Aktiver mørk modus", + "@darkModeEnable": {}, + "delete": "Slett", + "@delete": {}, + "deleteFailed": "Slettingen mislyktes", + "@deleteFailed": {}, + "deletePart": "Slett del", + "@deletePart": {}, + "deletePartDetail": "Fjern denne delen fra databasen", + "@deletePartDetail": {}, + "deleteSuccess": "Sletting var vellykket", + "@deleteSuccess": {}, + "description": "Beskrivelse", + "@description": {}, + "destroyed": "Ødelagt", + "@destroyed": {}, + "details": "Detaljer", + "@details": { + "description": "details" + }, + "documentation": "Dokumentasjon", + "@documentation": {}, + "downloading": "Laster ned fil", + "@downloading": {}, + "downloadError": "Feil ved nedlasting", + "@downloadError": {}, + "edit": "Rediger", + "@edit": { + "description": "edit" + }, + "editCategory": "Rediger kategori", + "@editCategory": {}, + "editLocation": "Rediger lokasjon", + "@editLocation": {}, + "editNotes": "Rediger notater", + "@editNotes": {}, + "editPart": "Rediger del", + "@editPart": { + "description": "edit part" + }, + "editItem": "Rediger lagervare", + "@editItem": {}, + "enterPassword": "Skriv inn passord", + "@enterPassword": {}, + "enterUsername": "Skriv inn brukernavn", + "@enterUsername": {}, + "error": "Feil", + "@error": { + "description": "Error" + }, + "errorCreate": "Feil ved opprettelse av databaseoppføring", + "@errorCreate": {}, + "errorDelete": "Feil ved sletting av databaseoppføring", + "@errorDelete": {}, + "errorDetails": "Feildetaljer", + "@errorDetails": {}, + "errorFetch": "Feil ved henting av data fra server", + "@errorFetch": {}, + "errorUserRoles": "Feil ved forespørsel om brukerroller fra server", + "@errorUserRoles": {}, + "errorPluginInfo": "Feil ved forespørsel om utvidelsesdata fra server", + "@errorPluginInfo": {}, + "errorReporting": "Feilrapportering", + "@errorReporting": {}, + "errorReportUpload": "Last opp feilrapporter", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Last opp anonyme feilrapporter og krasjlogger", + "@errorReportUploadDetails": {}, + "feedback": "Tilbakemelding", + "@feedback": {}, + "feedbackError": "Feil ved innsending av tilbakemelding", + "@feedbackError": {}, + "feedbackSuccess": "Tilbakemelding sendt", + "@feedbackSuccess": {}, + "filterActive": "Aktiv", + "@filterActive": {}, + "filterActiveDetail": "Vis aktive deler", + "@filterActiveDetail": {}, + "filterAssembly": "Sammenstilt", + "@filterAssembly": {}, + "filterAssemblyDetail": "Vis sammenstilte deler", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponent", + "@filterComponent": {}, + "filterComponentDetail": "Vis komponentdeler", + "@filterComponentDetail": {}, + "filterInStock": "På lager", + "@filterInStock": {}, + "filterInStockDetail": "Vis deler som har lagerbeholdning", + "@filterInStockDetail": {}, + "filterSerialized": "Serialisert", + "@filterSerialized": {}, + "filterSerializedDetail": "Vis serialiserte lagervarer", + "@filterSerializedDetail": {}, + "filterTemplate": "Mal", + "@filterTemplate": {}, + "filterTemplateDetail": "Vis maldeler", + "@filterTemplateDetail": {}, + "filterTrackable": "Sporbar", + "@filterTrackable": {}, + "filterTrackableDetail": "Vis sporbare deler", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuell", + "@filterVirtual": {}, + "filterVirtualDetail": "Vis virtuelle deler", + "@filterVirtualDetail": {}, + "filteringOptions": "Alternativer for filtrering", + "@filteringOptions": {}, + "formatException": "Formatunntak", + "@formatException": {}, + "formatExceptionJson": "JSON-data formatunntak", + "@formatExceptionJson": {}, + "formError": "Skjemafeil", + "@formError": {}, + "history": "Historikk", + "@history": { + "description": "history" + }, + "home": "Hjem", + "@homeScreen": {}, + "homeScreen": "Startside", + "homeScreenSettings": "Konfigurer innstillinger for startside", + "@homeScreenSettings": {}, + "homeShowPo": "Vis innkjøpsordrer", + "@homeShowPo": {}, + "homeShowSubscribed": "Abonnerte deler", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Vis abonnerte deler på startside", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowPoDescription": "Vis innkjøpsordre-knappen på startside", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Vis leverandører", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Vis leverandørknapp på startside", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Vis produsenter", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Vis produsenter-knappen på startside", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Vis kunder", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Vis kunder-knapp på startside", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Bildeopplasting mislyktes", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Bilde lastet opp", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveDetail": "Denne delen er merket som inaktiv", + "@inactiveDetail": {}, + "includeSubcategories": "Inkluder underkategorier", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Vis resultater fra underkategorier", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inkluder underlokasjoner", + "@includeSublocations": {}, + "includeSublocationsDetail": "Vis resulateter fra underlokasjoner", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Ufullstendige profildetaljer", + "@incompleteDetails": {}, + "internalPartNumber": "Internt delnummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "I produksjon", + "@inProduction": {}, + "inProductionDetail": "Denne lagervaren er i produksjon", + "@inProductionDetail": {}, + "internalPart": "Intern del", + "@internalPart": {}, + "invalidHost": "Ugyldig vertsnavn", + "@invalidHost": {}, + "invalidHostDetails": "Angitt vertsnavn er ikke gyldig", + "@invalidHostDetails": {}, + "invalidPart": "Ugyldig del", + "@invalidPart": {}, + "invalidPartCategory": "Ugyldig delkategori", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ugyldig lagerlokasjon", + "@invalidStockLocation": {}, + "invalidStockItem": "Ugyldig lagervare", + "@invalidStockItem": {}, + "invalidSupplierPart": "Ugyldig leverandørdel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Ugyldig brukernavn- / passordkombinasjon", + "@invalidUsernamePassword": {}, + "issue": "Send", + "@issue": {}, + "issueDate": "Sendt dato", + "@issueDate": {}, + "issueOrder": "Send ordre", + "@issueOrder": {}, + "itemInLocation": "Artikkelen er allerede i lokasjonen", + "@itemInLocation": {}, + "keywords": "Nøkkelord", + "@keywords": {}, + "labelTemplate": "Etikettmal", + "@labelTemplate": {}, + "language": "Språk", + "@language": {}, + "languageDefault": "Standard systemspråk", + "@languageDefault": {}, + "languageSelect": "Velg språk", + "@languageSelect": {}, + "lastStocktake": "Siste Lagertelling", + "@lastStocktake": {}, + "lastUpdated": "Sist oppdatert", + "@lastUpdated": {}, + "level": "Nivå", + "@level": {}, + "lineItem": "Ordrelinje", + "@lineItem": {}, + "lineItems": "Ordrelinjer", + "@lineItems": {}, + "locateItem": "Finn lagervare", + "@locateItem": {}, + "locateLocation": "Finn lagerlokasjon", + "@locateLocation": {}, + "locationCreate": "Ny lokasjon", + "@locationCreate": {}, + "locationCreateDetail": "Opprett ny lagerlokasjon", + "@locationCreateDetail": {}, + "locationNotSet": "Ingen lokasjon spesifisert", + "@locationNotSet": {}, + "locationUpdated": "Lagerlokasjon oppdatert", + "@locationUpdated": {}, + "link": "Lenke", + "@link": {}, + "lost": "Tapt", + "@lost": {}, + "manufacturerPartNumber": "Produsentens varenummer", + "@manufacturerPartNumber": {}, + "manufacturer": "Produsent", + "@manufacturer": {}, + "manufacturers": "Produsenter", + "@manufacturers": {}, + "missingData": "Manglende data", + "@missingData": {}, + "name": "Navn", + "@name": {}, + "notConnected": "Ikke tilkoblet", + "@notConnected": {}, + "notes": "Notater", + "@notes": { + "description": "Notes" + }, + "notifications": "Varsler", + "@notifications": {}, + "notificationsEmpty": "Ingen uleste varsler", + "@notificationsEmpty": {}, + "noResponse": "Ingen svar fra serveren", + "@noResponse": {}, + "noResults": "Ingen resultater", + "@noResults": {}, + "noSubcategories": "Ingen underkategorier", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Ingen underkategorier tilgjengelig", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ugyldig tall", + "@numberInvalid": {}, + "onOrder": "I bestilling", + "@onOrder": {}, + "onOrderDetails": "Artikler i bestilling for øyeblikket", + "@onOrderDetails": {}, + "outstanding": "Utestående", + "@outstanding": {}, + "outstandingOrderDetail": "Vis utestående ordre", + "@outstandingOrderDetail": {}, + "packaging": "Emballasje", + "@packaging": {}, + "packageName": "Pakkenavn", + "@packageName": {}, + "parameters": "Parametere", + "@parameters": {}, + "parametersSettingDetail": "Vis parametere for del", + "@parametersSettingDetail": {}, + "parent": "Overordnet", + "@parent": {}, + "parentCategory": "Overordnet kategori", + "@parentCategory": {}, + "parentLocation": "Overordnet lokasjon", + "@parentLocation": {}, + "part": "Del", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Ny del", + "@partCreate": {}, + "partCreateDetail": "Opprett ny del i denne kategorien", + "@partCreateDetail": {}, + "partEdited": "Delen er oppdatert", + "@partEdited": {}, + "parts": "Deler", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Ingen deler", + "@partsNone": {}, + "partNoResults": "Ingen deler samsvarer med spørring", + "@partNoResults": {}, + "partSettings": "Innstillinger for del", + "@partSettings": {}, + "partsStarred": "Abonnerte deler", + "@partsStarred": {}, + "partsStarredNone": "Ingen stjernemerkede deler tilgjengelig", + "@partsStarredNone": {}, + "partSuppliers": "Deleleverandører", + "@partSuppliers": {}, + "partCategory": "Delkategori", + "@partCategory": {}, + "partCategoryTopLevel": "Toppnivå delkategori", + "@partCategoryTopLevel": {}, + "partCategories": "Delkategorier", + "@partCategories": {}, + "partDetails": "Deldetaljer", + "@partDetails": {}, + "partNotes": "Delnotater", + "@partNotes": {}, + "partStock": "Dellager", + "@partStock": { + "description": "part stock" + }, + "password": "Passord", + "@password": {}, + "passwordEmpty": "Passordet kan ikke være tomt", + "@passwordEmpty": {}, + "permissionAccountDenied": "Kontoen din har ikke tillatelse til å utføre denne handlingen", + "@permissionAccountDenied": {}, + "permissionRequired": "Tillatelse kreves", + "@permissionRequired": {}, + "printLabel": "Skriv ut etikett", + "@printLabel": {}, + "plugin": "Utvidelse", + "@plugin": {}, + "pluginPrinter": "Skriver", + "@pluginPrinter": {}, + "pluginSupport": "Utvidelsesstøtte aktivert", + "@pluginSupport": {}, + "pluginSupportDetail": "Tjeneren støtter egendefinerte utvidelser", + "@pluginSupportDetail": {}, + "printLabelFailure": "Utskrift av etikett mislyktes", + "@printLabelFailure": {}, + "printLabelSuccess": "Etikett sendt til skriver", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Legg til serverprofil", + "@profileAdd": {}, + "profileConnect": "Koble til server", + "@profileConnect": {}, + "profileEdit": "Rediger serverprofil", + "@profileEdit": {}, + "profileDelete": "Slett serverprofil", + "@profileDelete": {}, + "profileName": "Profilnavn", + "@profileName": {}, + "profileNone": "Ingen profiler tilgjengelig", + "@profileNone": {}, + "profileNotSelected": "Ingen profil valgt", + "@profileNotSelected": {}, + "profileSelect": "Velg InvenTree-server", + "@profileSelect": {}, + "profileSelectOrCreate": "Velg server eller opprett en ny profil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Trykk for å opprette eller velge en profil", + "@profileTapToCreate": {}, + "purchaseOrder": "Innkjøpsordre", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Ny innkjøpsordre", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Rediger innkjøpsordre", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Innkjøpsordrer", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Innkjøpsordre oppdatert", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Innkjøpspris", + "@purchasePrice": {}, + "quantity": "Antall", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Tilgjengelig antall", + "@quantityAvailable": {}, + "quantityEmpty": "Mengde er tom", + "@quantityEmpty": {}, + "quantityInvalid": "Mengde er ugyldig", + "@quantityInvalid": {}, + "quantityPositive": "Mengde må være positiv", + "@quantityPositive": {}, + "quarantined": "I Karantene", + "@quarantined": {}, + "queryEmpty": "Angi søkeord", + "@queryEmpty": {}, + "queryNoResults": "Ingen resultater for søk", + "@queryNoResults": {}, + "received": "Mottatt", + "@received": {}, + "receiveItem": "Motta artikkel", + "@receiveItem": {}, + "receivedItem": "Mottatt lagervare", + "@receivedItem": {}, + "reference": "Referanse", + "@reference": {}, + "refresh": "Oppdater", + "@refresh": {}, + "refreshing": "Oppdaterer", + "@refreshing": {}, + "rejected": "Avvist", + "@rejected": {}, + "releaseNotes": "Utgivelsesnotater", + "@releaseNotes": {}, + "remove": "Fjern", + "@remove": { + "description": "remove" + }, + "removeStock": "Fjern lagerbeholdning", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Rapporter feil", + "@reportBug": {}, + "reportBugDescription": "Send feilrapport (krever GitHub-konto)", + "@reportBugDescription": {}, + "results": "Resultater", + "@results": {}, + "request": "Forespørsel", + "@request": {}, + "requestFailed": "Forespørselen mislyktes", + "@requestFailed": {}, + "requestSuccessful": "Forespørselen var vellykket", + "@requestSuccessful": {}, + "requestingData": "Etterspør data", + "@requestingData": {}, + "required": "Påkrevet", + "@required": { + "description": "This field is required" + }, + "response400": "Ugyldig forespørsel", + "@response400": {}, + "response401": "Uautorisert", + "@response401": {}, + "response403": "Tilgang nektet", + "@response403": {}, + "response404": "Ressurs ikke funnet", + "@response404": {}, + "response405": "Metode ikke tillatt", + "@response405": {}, + "response429": "For mange forespørsler", + "@response429": {}, + "response500": "Intern serverfeil", + "@response500": {}, + "response501": "Ikke implementert", + "@response501": {}, + "response502": "Dårlig gateway", + "@response502": {}, + "response503": "Tjenesten er ikke tilgjengelig", + "@response503": {}, + "response504": "Tidsavbrudd for gateway", + "@response504": {}, + "response505": "HTTP-versjon støttes ikke", + "@response505": {}, + "responseData": "Responsdata", + "@responseData": {}, + "responseInvalid": "Ugyldig responskode", + "@responseInvalid": {}, + "responseUnknown": "Ukjent svar", + "@responseUnknown": {}, + "result": "Resultat", + "@result": { + "description": "" + }, + "returned": "Returnert", + "@returned": {}, + "salesOrders": "Salgsordre", + "@salesOrders": {}, + "save": "Lagre", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skann strekkode", + "@scanBarcode": {}, + "scanIntoLocation": "Skann til lokasjon", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Skann denne artikkelen til lokasjon", + "@scanIntoLocationDetail": {}, + "search": "Søk", + "@search": { + "description": "search" + }, + "searching": "Søker", + "@searching": {}, + "searchLocation": "Søk etter lokasjon", + "@searchLocation": {}, + "searchParts": "Søk i deler", + "@searchParts": {}, + "searchStock": "Søk i lagervarer", + "@searchStock": {}, + "select": "Velg", + "@select": {}, + "selectFile": "Velg fil", + "@selectFile": {}, + "selectImage": "Velg bilde", + "@selectImage": {}, + "selectLocation": "Velg en lokasjon", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradresse", + "@serverAddress": {}, + "serverApiRequired": "Nødvendig API-versjon", + "@serverApiRequired": {}, + "serverApiVersion": "Serverens API-versjon", + "@serverApiVersion": {}, + "serverAuthenticationError": "Autentiseringsfeil", + "@serverAuthenticationError": {}, + "serverCertificateError": "Sertifikatfeil", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Serverens HTTPS-sertifikat er ugyldig", + "@serverCertificateInvalid": {}, + "serverConnected": "Koblet til server", + "@serverConnected": {}, + "serverConnecting": "Kobler til server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Klarte ikke å koble til server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server kan ikke være tom", + "@serverEmpty": {}, + "serverError": "Serverfeil", + "@serverError": {}, + "serverDetails": "Serverdetaljer", + "@serverDetails": {}, + "serverMissingData": "Svar fra server mangler påkrevde felter", + "@serverMissingData": {}, + "serverOld": "Gammel serverversjon", + "@serverOld": {}, + "serverSettings": "Serverinnstillinger", + "@serverSettings": {}, + "serverStart": "Serveren må begynne med http[s]", + "@serverStart": {}, + "settings": "Innstillinger", + "@settings": {}, + "serverInstance": "Serverinstans", + "@serverInstance": {}, + "serverNotConnected": "Serveren er ikke tilkoblet", + "@serverNotConnected": {}, + "serverNotSelected": "Server ikke valgt", + "@serverNotSelected": {}, + "sounds": "Lyder", + "@sounds": {}, + "soundOnBarcodeAction": "Spill akustisk tone ved strekkodehandling", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Spill akustisk tone ved serverfeil", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuskode", + "@statusCode": {}, + "stock": "Lagerbeholdning", + "@stock": { + "description": "stock" + }, + "stockDetails": "Nåværende tilgjengelig lagerbeholdning", + "@stockDetails": {}, + "stockItem": "Lagervare", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Lagervarer", + "@stockItems": {}, + "stockItemCreate": "Ny lagervare", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Opprett ny lagervare på denne lokasjonen", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Slett lagervare", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Er du sikker på at du vil slette denne lagervaren?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Kunne ikke slette lagervare", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagervare slettet", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Lagerhistorikk", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Vis historisk lagersporingsinformasjon", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Lagervare overført", + "@stockItemTransferred": {}, + "stockItemUpdated": "Lagervare oppdatert", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Ingen lagervarer tilgjengelig", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Lagervarenotater", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Lagervare oppdatert", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Oppdatering av lagervare feilet", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerlokasjon", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerlokasjoner", + "@stockLocations": {}, + "stockTopLevel": "Toppnivå lagerlokasjon", + "@stockTopLevel": {}, + "strictHttps": "Bruk streng HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Tving streng HTTPS-sertifikatsjekk", + "@strictHttpsDetails": {}, + "subcategory": "Underkategori", + "@subcategory": {}, + "subcategories": "Underkategorier", + "@subcategories": {}, + "sublocation": "Underlokasjon", + "@sublocation": {}, + "sublocations": "Underlokasjoner", + "@sublocations": {}, + "sublocationNone": "Ingen underlokasjoner", + "@sublocationNone": {}, + "sublocationNoneDetail": "Ingen underlokasjoner tilgjengelig", + "@sublocationNoneDetail": {}, + "submitFeedback": "Send tilbakemelding", + "@submitFeedback": {}, + "suppliedParts": "Leverte deler", + "@suppliedParts": {}, + "supplier": "Leverandør", + "@supplier": {}, + "supplierPart": "Leverandørdel", + "@supplierPart": {}, + "supplierPartEdit": "Rediger Leverandørdel", + "@supplierPartEdit": {}, + "supplierPartNumber": "Leverandørens delnummer", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Leverandørdel oppdatert", + "@supplierPartUpdated": {}, + "supplierParts": "Leverandørdeler", + "@supplierParts": {}, + "suppliers": "Leverandører", + "@suppliers": {}, + "supplierReference": "Leverandørreferanse", + "@supplierReference": {}, + "takePicture": "Ta bilde", + "@takePicture": {}, + "targetDate": "Måldato", + "@targetDate": {}, + "templatePart": "Overordnet maldel", + "@templatePart": {}, + "testName": "Testnavn", + "@testName": {}, + "testPassedOrFailed": "Test bestått eller mislyktes", + "@testPassedOrFailed": {}, + "testsRequired": "Nødvendige tester", + "@testsRequired": {}, + "testResults": "Testresultater", + "@testResults": { + "description": "" + }, + "testResultAdd": "Legg til testresultat", + "@testResultAdd": {}, + "testResultNone": "Ingen testresultater", + "@testResultNone": {}, + "testResultNoneDetail": "Ingen testresultater tilgjengelig", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Feil ved opplasting av testresultat", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testresultat lastet opp", + "@testResultUploadPass": {}, + "timeout": "Tidsavbrudd", + "@timeout": { + "description": "" + }, + "tokenError": "Token-lfeil", + "@tokenError": {}, + "tokenMissing": "Manglende token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Adgangstoken mangler i respons", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total pris", + "@totalPrice": {}, + "transfer": "Overfør", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Overfør lagerbeholdning", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Overfør artikkelen til en annen lokasjon", + "@transferStockDetail": {}, + "transferStockLocation": "Overfør lagerlokasjon", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Overfør denne lagerlokasjonen til en annen", + "@transferStockLocationDetail": {}, + "translate": "Oversett", + "@translate": {}, + "translateHelp": "Hjelp til med å oversette InvenTree-appen", + "@translateHelp": {}, + "units": "Enheter", + "@units": {}, + "unknownResponse": "Ukjent svar", + "@unknownResponse": {}, + "upload": "Last opp", + "@upload": {}, + "uploadFailed": "Filopplasting mislyktes", + "@uploadFailed": {}, + "uploadSuccess": "Fil lastet opp", + "@uploadSuccess": {}, + "usedIn": "Brukt i", + "@usedIn": {}, + "usedInDetails": "Sammenstillinger som krever denne delen", + "@usedInDetails": {}, + "username": "Brukernavn", + "@username": {}, + "usernameEmpty": "Brukernavn kan ikke være tomt", + "@usernameEmpty": {}, + "value": "Verdi", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Verdi kan ikke være tom", + "@valueCannotBeEmpty": {}, + "valueRequired": "Verdi er påkrevd", + "@valueRequired": {}, + "variants": "Varianter", + "@variants": {}, + "version": "Versjon", + "@version": {}, + "viewSupplierPart": "Vis leverandørdel", + "@viewSupplierPart": {}, + "website": "Nettside", + "@website": {} } \ No newline at end of file From ac57c532029132ca1f9ae400907c99101ccf5c61 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Apr 2023 18:55:22 +1000 Subject: [PATCH 351/746] Bump version number to 0.11.6 (#332) --- assets/release_notes.md | 5 +++++ pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index a298327..17ff235 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.11.6 - April 2023 +--- + +- Added Norwegian translations + ### 0.11.5 - April 2023 --- diff --git a/pubspec.yaml b/pubspec.yaml index 36b1d51..8e49145 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.5+64 +version: 0.11.6+65 environment: sdk: ">=2.16.0 <3.0.0" From 1d6708fbca9b158edf0a63356d27fd678b4b1e95 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Apr 2023 20:47:24 +1000 Subject: [PATCH 352/746] Adjust colors of action buttons (#333) Fixes https://github.com/inventree/inventree-app/issues/330 --- assets/release_notes.md | 1 + lib/widget/refreshable_state.dart | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 17ff235..ae70bfb 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.11.6 - April 2023 --- +- Fix action button colors - Added Norwegian translations ### 0.11.5 - April 2023 diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 1bd1fb3..c713daa 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/widget/back.dart"; @@ -63,11 +64,10 @@ mixin BaseWidgetProperties { BottomAppBar? buildBottomAppBar(BuildContext context, GlobalKey key) { const double iconSize = 32; - const Color iconColor = Colors.blueGrey; List icons = [ IconButton( - icon: Icon(Icons.menu, color: iconColor), + icon: Icon(Icons.menu, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (key.currentState != null) { @@ -76,7 +76,7 @@ mixin BaseWidgetProperties { }, ), IconButton( - icon: Icon(Icons.search, color: iconColor), + icon: Icon(Icons.search, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { @@ -90,7 +90,7 @@ mixin BaseWidgetProperties { }, ), IconButton( - icon: Icon(Icons.qr_code_scanner, color: iconColor), + icon: Icon(Icons.qr_code_scanner, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { From 232f72171229c8d492da382e9c8e0b9b25d5b666 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Apr 2023 20:47:40 +1000 Subject: [PATCH 353/746] Fix duplicate serial number field (#334) --- assets/release_notes.md | 1 + lib/inventree/stock.dart | 2 +- lib/l10n/app_en.arb | 3 +++ lib/widget/location_display.dart | 9 +++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ae70bfb..20e102f 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Fix action button colors - Added Norwegian translations +- Fix serial number field when creating stock item ### 0.11.5 - April 2023 --- diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index cd22e3f..10b5448 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -160,7 +160,7 @@ class InvenTreeStockItem extends InvenTreeModel { "quantity": {}, "serial": {}, "serial_numbers": { - "label": L10().serialNumber, + "label": L10().serialNumbers, "type": "string", }, "status": {}, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2d353b7..66ded8b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -969,6 +969,9 @@ "serialNumber": "Serial Number", "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", "@server": {}, diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 38cc63d..9f74e8b 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -239,6 +239,9 @@ class _LocationDisplayState extends RefreshableState { ); } + /* + * Launch a dialog form to create a new stock item + */ Future _newStockItem(BuildContext context) async { int pk = location?.pk ?? -1; @@ -246,12 +249,18 @@ class _LocationDisplayState extends RefreshableState { return; } + var fields = InvenTreeStockItem().formFields(); + + // Serial number field is not required here + fields.remove("serial"); + InvenTreeStockItem().createForm( context, L10().stockItemCreate, data: { "location": location != null ? pk : null, }, + fields: fields, onSuccess: (result) async { Map data = result as Map; From 95573a27848f0530a8aa9f56e38920b7fa811ebf Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 21 Apr 2023 19:35:07 +1000 Subject: [PATCH 354/746] New Crowdin updates (#335) * New translations app_en.arb (Czech) * New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index c26fa6d..e52baff 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -30,6 +30,8 @@ "@address": {}, "appAbout": "O InvenTree", "@appAbout": {}, + "appCredits": "Poděkování dalším stranám", + "@appCredits": {}, "appDetails": "Informace o aplikaci", "@appDetails": {}, "appReleaseNotes": "Zobrazit poznámky k verzi aplikace", @@ -74,10 +76,20 @@ "@barcodeScanAssign": {}, "barcodeScanGeneral": "Naskenuj čárový kód InvenTree", "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Skenovat skladové položky do tohoto umístění", + "@barcodeScanInItems": {}, "barcodeScanLocation": "Skenovat skladové místo", "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Naskenováno do umístění", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Položka není naskenována v", + "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "Skenovat skladovou položku", "@barcodeScanItem": {}, + "barcodeTones": "Zvuky čtení čárového kódu", + "@barcodeTones": {}, + "barcodeUnassign": "Zrušit přiřazení čárového kódu", + "@barcodeUnassign": {}, "barcodeUnknown": "Čárkový kód nebyl rozpoznán", "@barcodeUnknown": {}, "batchCode": "Kód šarže", @@ -96,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Zrušit objednávku", + "@cancelOrder": {}, "category": "Kategorie", "@category": {}, "categoryCreate": "Nová kategorie", @@ -132,6 +146,10 @@ "@customers": {}, "damaged": "Poškozeno", "@damaged": {}, + "darkMode": "Tmavý motiv", + "@darkMode": {}, + "darkModeEnable": "Nastaví tmavý motiv aplikace", + "@darkModeEnable": {}, "delete": "Odstranit", "@delete": {}, "deleteFailed": "Odstranění se nezdařilo", @@ -188,6 +206,10 @@ "@errorDetails": {}, "errorFetch": "Chyba při načítání dat ze serveru", "@errorFetch": {}, + "errorUserRoles": "Chyba při požadavku na uživatelské role ze serveru", + "@errorUserRoles": {}, + "errorPluginInfo": "Chyba při požadování dat pluginu ze serveru", + "@errorPluginInfo": {}, "errorReporting": "Hlášení chyb", "@errorReporting": {}, "errorReportUpload": "Nahrát zprávu o chybách", @@ -295,6 +317,8 @@ "@inProduction": {}, "inProductionDetail": "Tato skladová položka je ve výrobě", "@inProductionDetail": {}, + "internalPart": "Vnitřní součást", + "@internalPart": {}, "invalidHost": "Neplatný název hostitele", "@invalidHost": {}, "invalidHostDetails": "Zadaný název hostitele není platný", @@ -311,8 +335,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Neplatné uživatelské jméno nebo heslo.", "@invalidUsernamePassword": {}, + "issue": "Vystavit", + "@issue": {}, "issueDate": "Datum nahlášení", "@issueDate": {}, + "issueOrder": "Vystav objednávku", + "@issueOrder": {}, "itemInLocation": "Položka je již umístěna", "@itemInLocation": {}, "keywords": "Klíčová slova", @@ -333,6 +361,8 @@ "@level": {}, "lineItem": "Řádek položky", "@lineItem": {}, + "lineItems": "Položky", + "@lineItems": {}, "locateItem": "Najít skladovou položku", "@locateItem": {}, "locateLocation": "Najít skladové umístění", @@ -349,6 +379,10 @@ "@link": {}, "lost": "Ztraceno", "@lost": {}, + "manufacturerPartNumber": "Číslo dílu výrobce", + "@manufacturerPartNumber": {}, + "manufacturer": "Výrobce", + "@manufacturer": {}, "manufacturers": "Výrobci", "@manufacturers": {}, "missingData": "Chybějící data", @@ -379,6 +413,10 @@ "@onOrder": {}, "onOrderDetails": "Položky momentálně v objednávce", "@onOrderDetails": {}, + "outstanding": "Nevyřízené", + "@outstanding": {}, + "outstandingOrderDetail": "Zobrazit nevyřízené objednávky", + "@outstandingOrderDetail": {}, "packaging": "Balení", "@packaging": {}, "packageName": "Název balíčku", @@ -479,6 +517,8 @@ "@profileTapToCreate": {}, "purchaseOrder": "Objednávka", "@purchaseOrder": {}, + "purchaseOrderCreate": "Nová objednávka", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Upravit objednávku", "@purchaseOrderEdit": {}, "purchaseOrders": "Objednávky", @@ -511,6 +551,8 @@ "@receiveItem": {}, "receivedItem": "Přijatá skladová položka", "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, "refresh": "Obnovit", "@refresh": {}, "refreshing": "Obnovuji…", @@ -561,10 +603,18 @@ "@response500": {}, "response501": "Není implementováno", "@response501": {}, + "response502": "Špatná brána", + "@response502": {}, "response503": "Služba nedostupná", "@response503": {}, + "response504": "Časová odezva brány vypršela", + "@response504": {}, "response505": "HTTP verze není podporována", "@response505": {}, + "responseData": "Data odpovědi", + "@responseData": {}, + "responseInvalid": "Neplatný kód odpovědi", + "@responseInvalid": {}, "responseUnknown": "Neznámá odpověď", "@responseUnknown": {}, "result": "Výsledek", @@ -583,6 +633,8 @@ "@scanBarcode": {}, "scanIntoLocation": "Skenovat umístění", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Skenovat tuto položku do umístění", + "@scanIntoLocationDetail": {}, "search": "Hledat", "@search": { "description": "search" @@ -607,6 +659,8 @@ "@send": {}, "serialNumber": "Sériové číslo", "@serialNumber": {}, + "serialNumbers": "Sériová čísla", + "@serialNumbers": {}, "server": "Server", "@server": {}, "serverAddress": "Adresa serveru", @@ -685,6 +739,8 @@ "@stockItemDeleteSuccess": {}, "stockItemHistory": "Historie skladu", "@stockItemHistory": {}, + "stockItemHistoryDetail": "Zobrazit historické informace o sledování zásob", + "@stockItemHistoryDetail": {}, "stockItemTransferred": "Skladová položka převedena", "@stockItemTransferred": {}, "stockItemUpdated": "Skladová položka upravena", @@ -703,6 +759,12 @@ }, "stockLocations": "Skladová místa", "@stockLocations": {}, + "stockTopLevel": "Skladové místo nejvyšší úrovně", + "@stockTopLevel": {}, + "strictHttps": "Striktně používat HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Vynutit přísnou kontrolu HTTPs certifikátů", + "@strictHttpsDetails": {}, "subcategory": "Podkategorie", "@subcategory": {}, "subcategories": "Podkategorie", @@ -725,6 +787,8 @@ "@supplierPart": {}, "supplierPartEdit": "Upravit dodavatele dílu", "@supplierPartEdit": {}, + "supplierPartNumber": "Číslo dílu dodavatele", + "@supplierPartNumber": {}, "supplierPartUpdated": "Dodavatel dílu upraven", "@supplierPartUpdated": {}, "supplierParts": "Dodavatel dílů", @@ -737,8 +801,12 @@ "@takePicture": {}, "targetDate": "Cílové datum", "@targetDate": {}, + "templatePart": "Rodičovská šablona dúlu", + "@templatePart": {}, "testName": "Název testu", "@testName": {}, + "testPassedOrFailed": "Test byl úspěšný nebo selhal", + "@testPassedOrFailed": {}, "testsRequired": "Požadované testy", "@testsRequired": {}, "testResults": "Výsledky testu", @@ -751,6 +819,8 @@ "@testResultNone": {}, "testResultNoneDetail": "Žádné výsledky testu nejsou k dispozici", "@testResultNoneDetail": {}, + "testResultUploadFail": "Chyba při odesílání výsledku testu", + "@testResultUploadFail": {}, "testResultUploadPass": "Výsledek testu nahrán", "@testResultUploadPass": {}, "timeout": "Časový limit", @@ -761,6 +831,10 @@ "@tokenError": {}, "tokenMissing": "Chybějící token", "@tokenMissing": {}, + "tokenMissingFromResponse": "V odpovědi chybí přístupový token", + "@tokenMissingFromResponse": {}, + "totalPrice": "Celková cena", + "@totalPrice": {}, "transfer": "Převod", "@transfer": { "description": "transfer" From e23a8b4d5efefe76b969dfc7539c25ae56db3a5b Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 21 Apr 2023 21:12:22 +1000 Subject: [PATCH 355/746] Project code support (#336) * Determine if project codes are supported * Add helpers for boolean functions * Adds helper methods for generic "model" class - Will allow us to do some good refactoring * Refactor the refactor * Add debug support and getMap function * Major refactoring for model data accessors * Handle null values * Add sentry reporting if key is used incorrectly * Fix typo * Refactor createFromJson function * Add model for ProjectCode * Display and edit project code for purchase orders --- assets/release_notes.md | 1 + lib/api.dart | 15 +++ lib/api_form.dart | 8 ++ lib/inventree/bom.dart | 14 ++- lib/inventree/company.dart | 94 ++++++++--------- lib/inventree/model.dart | 145 ++++++++++++++++++++------ lib/inventree/notification.dart | 4 +- lib/inventree/part.dart | 139 ++++++++++-------------- lib/inventree/project_code.dart | 28 +++++ lib/inventree/purchase_order.dart | 76 +++++++------- lib/inventree/stock.dart | 135 +++++++++--------------- lib/l10n/app_en.arb | 3 + lib/widget/purchase_order_detail.dart | 20 ++++ 13 files changed, 383 insertions(+), 299 deletions(-) create mode 100644 lib/inventree/project_code.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 20e102f..1d67fe5 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.11.6 - April 2023 --- +- Add support for Project Codes - Fix action button colors - Added Norwegian translations - Fix serial number field when creating stock item diff --git a/lib/api.dart b/lib/api.dart index 0950eeb..7a41572 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -300,6 +300,9 @@ class InvenTreeAPI { // Order barcodes API v107 or newer bool get supportsOrderBarcodes => isConnected() && apiVersion >= 107; + // Project codes require v109 or newer + bool get supportsProjectCodes => isConnected() && apiVersion >= 109; + // Are plugins enabled on the server? bool _pluginsEnabled = false; @@ -1362,6 +1365,12 @@ class InvenTreeAPI { } } + // Return a boolean global setting value + Future getGlobalBooleanSetting(String key) async { + String value = await getGlobalSetting(key); + return value.toLowerCase() == "true"; + } + Future getUserSetting(String key) async { if (!supportsSettings) return ""; @@ -1382,6 +1391,12 @@ class InvenTreeAPI { } } + // Return a boolean user setting value + Future getUserBooleanSetting(String key) async { + String value = await getUserSetting(key); + return value.toLowerCase() == "true"; + } + /* * Send a request to the server to locate / identify either a StockItem or StockLocation */ diff --git a/lib/api_form.dart b/lib/api_form.dart index 1b72360..d08d29a 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -15,6 +15,7 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/project_code.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/inventree/stock.dart"; @@ -667,6 +668,13 @@ class APIFormField { height: 40 ) ); + case "projectcode": + var project_code = InvenTreeProjectCode.fromJson(data); + return ListTile( + title: Text(project_code.code), + subtitle: Text(project_code.description), + leading: FaIcon(FontAwesomeIcons.list) + ); default: return ListTile( title: Text( diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart index ec326fe..cf708c6 100644 --- a/lib/inventree/bom.dart +++ b/lib/inventree/bom.dart @@ -12,9 +12,7 @@ class InvenTreeBomItem extends InvenTreeModel { InvenTreeBomItem.fromJson(Map json) : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeBomItem.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreeBomItem.fromJson(json); @override String get URL => "bom/"; @@ -36,13 +34,13 @@ class InvenTreeBomItem extends InvenTreeModel { } // Extract the 'reference' value associated with this BomItem - String get reference => (jsondata["reference"] ?? "") as String; - + String get reference => getString("reference"); + // Extract the 'quantity' value associated with this BomItem - double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; + double get quantity => getDouble("quantity"); // Extract the ID of the related part - int get partId => int.tryParse(jsondata["part"].toString()) ?? -1; + int get partId => getInt("part"); // Return a Part instance for the referenced part InvenTreePart? get part { @@ -69,5 +67,5 @@ class InvenTreeBomItem extends InvenTreeModel { } // Extract the ID of the related sub-part - int get subPartId => int.tryParse(jsondata["sub_part"].toString()) ?? -1; + int get subPartId => getInt("sub_part"); } \ No newline at end of file diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 7af1229..78f83d3 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -38,22 +38,22 @@ class InvenTreeCompany extends InvenTreeModel { String get thumbnail => (jsondata["thumbnail"] ?? jsondata["image"] ?? InvenTreeAPI.staticThumb) as String; - String get website => (jsondata["website"] ?? "") as String; + String get website => getString("website"); + + String get phone => getString("phone"); - String get phone => (jsondata["phone"] ?? "") as String; + String get email => getString("email"); - String get email => (jsondata["email"] ?? "") as String; + bool get isSupplier => getBool("is_supplier"); - bool get isSupplier => (jsondata["is_supplier"] ?? false) as bool; + bool get isManufacturer => getBool("is_manufacturer"); - bool get isManufacturer => (jsondata["is_manufacturer"] ?? false) as bool; - - bool get isCustomer => (jsondata["is_customer"] ?? false) as bool; - - int get partSuppliedCount => (jsondata["parts_supplied"] ?? 0) as int; - - int get partManufacturedCount => (jsondata["parts_manufactured"] ?? 0) as int; + bool get isCustomer => getBool("is_customer"); + int get partSuppliedCount => getInt("part_supplied"); + + int get partManufacturedCount => getInt("parts_manufactured"); + // Request a list of purchase orders against this company Future> getPurchaseOrders({bool? outstanding}) async { @@ -81,11 +81,7 @@ class InvenTreeCompany extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) { - var company = InvenTreeCompany.fromJson(json); - - return company; - } + InvenTreeModel createFromJson(Map json) => InvenTreeCompany.fromJson(json); } @@ -154,40 +150,36 @@ class InvenTreeSupplierPart extends InvenTreeModel { return _filters(); } - int get manufacturerId => (jsondata["manufacturer_detail"]["pk"] ?? -1) as int; - - String get manufacturerName => (jsondata["manufacturer_detail"]?["name"] ?? "") as String; - - String get MPN => (jsondata["manufacturer_part_detail"]?["MPN"] ?? "") as String; - + int get manufacturerId => getInt("pk", subKey: "manufacturer_detail"); + + String get manufacturerName => getString("name", subKey: "manufacturer_detail"); + + String get MPN => getString("MPN", subKey: "manufacturer_part_detail"); + String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - int get manufacturerPartId => (jsondata["manufacturer_part"] ?? -1) as int; - - int get supplierId => (jsondata["supplier"] ?? -1) as int; - - String get supplierName => (jsondata["supplier_detail"]?["name"] ?? "") as String; - + int get manufacturerPartId => getInt("manufacturer_part"); + + int get supplierId => getInt("supplier"); + + String get supplierName => getString("name", subKey: "supplier_detail"); + String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - String get SKU => (jsondata["SKU"] ?? "") as String; - - int get partId => (jsondata["part"] ?? -1) as int; - + String get SKU => getString("SKU"); + + int get partId => getInt("part"); + String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - String get partName => (jsondata["part_detail"]?["full_name"] ?? "") as String; - - String get partDescription => (jsondata["part_detail"]?["description"] ?? "") as String; - - String get note => (jsondata["note"] ?? "") as String; + String get partName => getString("full_name", subKey: "part_detail"); + + String get partDescription => getString("description", subKey: "part_detail"); + + String get note => getString("note"); @override - InvenTreeModel createFromJson(Map json) { - var part = InvenTreeSupplierPart.fromJson(json); - - return part; - } + InvenTreeModel createFromJson(Map json) => InvenTreeSupplierPart.fromJson(json); } @@ -207,16 +199,12 @@ class InvenTreeManufacturerPart extends InvenTreeModel { }; } - int get partId => (jsondata["part"] ?? -1) as int; - - int get manufacturerId => (jsondata["manufacturer"] ?? -1) as int; - - String get MPN => (jsondata["MPN"] ?? "") as String; - + int get partId => getInt("part"); + + int get manufacturerId => getInt("manufacturer"); + + String get MPN => getString("MPN"); + @override - InvenTreeModel createFromJson(Map json) { - var part = InvenTreeManufacturerPart.fromJson(json); - - return part; - } + InvenTreeModel createFromJson(Map json) => InvenTreeManufacturerPart.fromJson(json); } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 576329f..97b2f16 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -63,6 +63,96 @@ class InvenTreeModel { // Note: If the WEB_URL is the same (except for /api/) as URL then just leave blank String get WEB_URL => ""; + // Helper function to set a value in the JSON data + void setValue(String key, dynamic value) { + jsondata[key] = value; + } + + // return a dynamic value from the JSON data + // optionally we can specifiy a "subKey" to get a value from a sub-dictionary + dynamic getValue(String key, {dynamic backup, String subKey = ""}) { + Map data = jsondata; + + // If a subKey is specified, we need to dig deeper into the JSON data + if (subKey.isNotEmpty) { + + if (!data.containsKey(subKey)) { + debug("JSON data does not contain subKey '$subKey' for key '$key'"); + return backup; + } + + dynamic sub_data = data[subKey]; + + if (sub_data is Map) { + data = (data[subKey] ?? {}) as Map; + } + + } + + if (data.containsKey(key)) { + return data[key]; + } else { + debug("JSON data does not contain key '$key' (subKey '${subKey}')"); + return backup; + } + } + + // Helper function to get sub-map from JSON data + Map getMap(String key, {Map backup = const {}, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return value as Map; + } + + // Helper function to get string value from JSON data + String getString(String key, {String backup = "", String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return value.toString(); + } + + // Helper function to get integer value from JSON data + int getInt(String key, {int backup = -1, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return int.tryParse(value.toString()) ?? backup; + } + + // Helper function to get double value from JSON data + double getDouble(String key, {double backup = 0.0, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return double.tryParse(value.toString()) ?? backup; + } + + // Helper function to get boolean value from json data + bool getBool(String key, {bool backup = false, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return value.toString().toLowerCase() == "true"; + } + + // Return the InvenTree web server URL for this object String get webUrl { if (api.isConnected()) { @@ -191,16 +281,16 @@ class InvenTreeModel { // Accessor for the API InvenTreeAPI get api => InvenTreeAPI(); - int get pk => (jsondata["pk"] ?? -1) as int; - + int get pk => getInt("pk"); + // Some common accessors - String get name => (jsondata["name"] ?? "") as String; + String get name => getString("name"); - String get description => (jsondata["description"] ?? "") as String; + String get description => getString("description"); + + String get notes => getString("notes"); - String get notes => (jsondata["notes"] ?? "") as String; - - int get parentId => (jsondata["parent"] ?? -1) as int; + int get parentId => getInt("parent"); // Legacy API provided external link as "URL", while newer API uses "link" String get link => (jsondata["link"] ?? jsondata["URL"] ?? "") as String; @@ -297,15 +387,10 @@ class InvenTreeModel { } } - String get keywords => (jsondata["keywords"] ?? "") as String; - + String get keywords => getString("keywords"); + // Create a new object from JSON data (not a constructor!) - InvenTreeModel createFromJson(Map json) { - - var obj = InvenTreeModel.fromJson(json); - - return obj; - } + InvenTreeModel createFromJson(Map json) => InvenTreeModel.fromJson(json); // Return the API detail endpoint for this Model object String get url => "${URL}/${pk}/".replaceAll("//", "/"); @@ -746,9 +831,7 @@ class InvenTreePlugin extends InvenTreeModel { InvenTreePlugin.fromJson(Map json) : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePlugin.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePlugin.fromJson(json); @override String get URL { @@ -765,10 +848,10 @@ class InvenTreePlugin extends InvenTreeModel { } } - String get key => (jsondata["key"] ?? "") as String; - - bool get active => (jsondata["active"] ?? false) as bool; - + String get key => getString("key"); + + bool get active => getBool("active"); + // Return the metadata struct for this plugin Map get _meta => (jsondata["meta"] ?? {}) as Map; @@ -803,11 +886,11 @@ class InvenTreeGlobalSetting extends InvenTreeModel { @override String get URL => "settings/global/"; - String get key => (jsondata["key"] ?? "") as String; - - String get value => (jsondata["value"] ?? "") as String; - - String get type => (jsondata["type"] ?? "") as String; + String get key => getString("key"); + + String get value => getString("value"); + + String get type => getString("type"); } @@ -836,8 +919,8 @@ class InvenTreeAttachment extends InvenTreeModel { // Override this reference field for any subclasses String get REFERENCE_FIELD => ""; - String get attachment => (jsondata["attachment"] ?? "") as String; - + String get attachment => getString("attachment"); + // Return the filename of the attachment String get filename { return attachment.split("/").last; @@ -874,8 +957,8 @@ class InvenTreeAttachment extends InvenTreeModel { return FontAwesomeIcons.fileLines; } - String get comment => (jsondata["comment"] ?? "") as String; - + String get comment => getString("comment"); + DateTime? get uploadDate { if (jsondata.containsKey("upload_date")) { return DateTime.tryParse((jsondata["upload_date"] ?? "") as String); diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart index a533319..ae79fa2 100644 --- a/lib/inventree/notification.dart +++ b/lib/inventree/notification.dart @@ -27,8 +27,8 @@ class InvenTreeNotification extends InvenTreeModel { }; } - String get message => (jsondata["message"] ?? "") as String; - + String get message => getString("message"); + DateTime? get creationDate { if (jsondata.containsKey("creation")) { return DateTime.tryParse((jsondata["creation"] ?? "") as String); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index e2ef2d9..b476937 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -43,8 +43,8 @@ class InvenTreePartCategory extends InvenTreeModel { return fields; } - String get pathstring => (jsondata["pathstring"] ?? "") as String; - + String get pathstring => getString("pathstring"); + String get parentPathString { List psplit = pathstring.split("/"); @@ -67,11 +67,7 @@ class InvenTreePartCategory extends InvenTreeModel { int get partcount => (jsondata["part_count"] ?? jsondata["parts"] ?? 0) as int; @override - InvenTreeModel createFromJson(Map json) { - var cat = InvenTreePartCategory.fromJson(json); - - return cat; - } + InvenTreeModel createFromJson(Map json) => InvenTreePartCategory.fromJson(json); } @@ -87,22 +83,18 @@ class InvenTreePartTestTemplate extends InvenTreeModel { @override String get URL => "part/test-template/"; - String get key => (jsondata["key"] ?? "") as String; + String get key => getString("key"); - String get testName => (jsondata["test_name"] ?? "") as String; + String get testName => getString("test_name"); - bool get required => (jsondata["required"] ?? false) as bool; + bool get required => getBool("required"); + + bool get requiresValue => getBool("requires_value"); - bool get requiresValue => (jsondata["requires_value"] ?? false) as bool; - - bool get requiresAttachment => (jsondata["requires_attachment"] ?? false) as bool; + bool get requiresAttachment => getBool("requires_attachment"); @override - InvenTreeModel createFromJson(Map json) { - var template = InvenTreePartTestTemplate.fromJson(json); - - return template; - } + InvenTreeModel createFromJson(Map json) => InvenTreePartTestTemplate.fromJson(json); bool passFailStatus() { @@ -142,9 +134,7 @@ class InvenTreePartParameter extends InvenTreeModel { String get URL => "part/parameter/"; @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePartParameter.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePartParameter.fromJson(json); @override Map formFields() { @@ -152,13 +142,13 @@ class InvenTreePartParameter extends InvenTreeModel { } @override - String get name => (jsondata["template_detail"]?["name"] ?? "") as String; + String get name => getString("name", subKey: "template_detail"); @override - String get description => (jsondata["template_detail"]?["description"] ?? "") as String; - - String get value => jsondata["data"] as String; - + String get description => getString("description", subKey: "template_detail"); + + String get value => getString("data"); + String get valueString { String v = value; @@ -170,7 +160,7 @@ class InvenTreePartParameter extends InvenTreeModel { return v; } - String get units => (jsondata["template_detail"]?["units"] ?? "") as String; + String get units => getString("units", subKey: "template_detail"); } /* @@ -254,8 +244,8 @@ class InvenTreePart extends InvenTreeModel { }); } - int get supplierCount => (jsondata["suppliers"] ?? 0) as int; - + int get supplierCount => getInt("suppliers", backup: 0); + // Request supplier parts for this part Future> getSupplierParts() async { List _supplierParts = []; @@ -301,40 +291,26 @@ class InvenTreePart extends InvenTreeModel { int? get defaultLocation => jsondata["default_location"] as int?; - // Get the number of stock on order for this Part - double get onOrder => double.tryParse(jsondata["ordering"].toString()) ?? 0; + double get onOrder => getDouble("ordering"); - String get onOrderString { + String get onOrderString => simpleNumberString(onOrder); - return simpleNumberString(onOrder); + double get inStock => getDouble("in_stock"); + + String get inStockString => simpleNumberString(inStock); + + // Get the 'available stock' for this Part + double get unallocatedStock { + + // Note that the 'available_stock' was not added until API v35 + if (jsondata.containsKey("unallocated_stock")) { + return double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; + } else { + return inStock; } + } - // Get the stock count for this Part - double get inStock => double.tryParse(jsondata["in_stock"].toString()) ?? 0; - - String get inStockString { - - String q = simpleNumberString(inStock); - - return q; - } - - // Get the 'available stock' for this Part - double get unallocatedStock { - - // Note that the 'available_stock' was not added until API v35 - if (jsondata.containsKey("unallocated_stock")) { - return double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; - } else { - return inStock; - } - } - - String get unallocatedStockString { - String q = simpleNumberString(unallocatedStock); - - return q; - } + String get unallocatedStockString => simpleNumberString(unallocatedStock); String stockString({bool includeUnits = true}) { String q = unallocatedStockString; @@ -350,39 +326,39 @@ class InvenTreePart extends InvenTreeModel { return q; } - String get units => (jsondata["units"] ?? "") as String; + String get units => getString("units"); // Get the ID of the Part that this part is a variant of (or null) int? get variantOf => jsondata["variant_of"] as int?; // Get the number of units being build for this Part - double get building => double.tryParse(jsondata["building"].toString()) ?? 0; + double get building => getDouble("building"); // Get the number of BOMs this Part is used in (if it is a component) - int get usedInCount => (jsondata["used_in"] ?? 0) as int; + int get usedInCount => jsondata.containsKey("used_in") ? getInt("used_in", backup: 0) : 0; - bool get isAssembly => (jsondata["assembly"] ?? false) as bool; + bool get isAssembly => getBool("assembly"); - bool get isComponent => (jsondata["component"] ?? false) as bool; + bool get isComponent => getBool("component"); - bool get isPurchaseable => (jsondata["purchaseable"] ?? false) as bool; + bool get isPurchaseable => getBool("purchaseable"); - bool get isSalable => (jsondata["salable"] ?? false) as bool; + bool get isSalable => getBool("salable"); - bool get isActive => (jsondata["active"] ?? false) as bool; + bool get isActive => getBool("active"); - bool get isVirtual => (jsondata["virtual"] ?? false) as bool; + bool get isVirtual => getBool("virtual"); - bool get isTrackable => (jsondata["trackable"] ?? false) as bool; + bool get isTrackable => getBool("trackable"); // Get the IPN (internal part number) for the Part instance - String get IPN => (jsondata["IPN"] ?? "") as String; + String get IPN => getString("IPN"); // Get the revision string for the Part instance - String get revision => (jsondata["revision"] ?? "") as String; + String get revision => getString("revision"); // Get the category ID for the Part instance (or "null" if does not exist) - int get categoryId => (jsondata["category"] ?? -1) as int; + int get categoryId => getInt("category"); // Get the category name for the Part instance String get categoryName { @@ -404,15 +380,15 @@ class InvenTreePart extends InvenTreeModel { return (jsondata["category_detail"]?["description"] ?? "") as String; } // Get the image URL for the Part instance - String get _image => (jsondata["image"] ?? "") as String; + String get _image => getString("image"); // Get the thumbnail URL for the Part instance - String get _thumbnail => (jsondata["thumbnail"] ?? "") as String; + String get _thumbnail => getString("thumbnail"); // Return the fully-qualified name for the Part instance String get fullname { - String fn = (jsondata["full_name"] ?? "") as String; + String fn = getString("full_name"); if (fn.isNotEmpty) return fn; @@ -456,15 +432,10 @@ class InvenTreePart extends InvenTreeModel { } // Return the "starred" status of this part - bool get starred => (jsondata["starred"] ?? false) as bool; + bool get starred => getBool("starred"); @override - InvenTreeModel createFromJson(Map json) { - - var part = InvenTreePart.fromJson(json); - - return part; - } + InvenTreeModel createFromJson(Map json) => InvenTreePart.fromJson(json); } /* @@ -483,8 +454,6 @@ class InvenTreePartAttachment extends InvenTreeAttachment { String get URL => "part/attachment/"; @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePartAttachment.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePartAttachment.fromJson(json); } diff --git a/lib/inventree/project_code.dart b/lib/inventree/project_code.dart new file mode 100644 index 0000000..8e2c75b --- /dev/null +++ b/lib/inventree/project_code.dart @@ -0,0 +1,28 @@ +import "package:inventree/inventree/model.dart"; + + +/* + * Class representing the ProjectCode database model + */ +class InvenTreeProjectCode extends InvenTreeModel { + + InvenTreeProjectCode() : super(); + + InvenTreeProjectCode.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeProjectCode.fromJson(json); + + @override + String get URL => "project-code/"; + + @override + Map formFields() { + return { + "code": {}, + "description": {}, + }; + } + + String get code => getString("code"); +} diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 53a297a..e22d009 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -34,6 +34,7 @@ class InvenTreePurchaseOrder extends InvenTreeModel { }, "supplier_reference": {}, "description": {}, + "project_code": {}, "target_date": {}, "link": {}, "responsible": {}, @@ -59,23 +60,32 @@ class InvenTreePurchaseOrder extends InvenTreeModel { }; } - String get issueDate => (jsondata["issue_date"] ?? "") as String; + String get issueDate => getString("issue_date"); - String get completeDate => (jsondata["complete_date"] ?? "") as String; + String get completeDate => getString("complete_date"); - String get creationDate => (jsondata["creation_date"] ?? "") as String; + String get creationDate => getString("creation_date"); - String get targetDate => (jsondata["target_date"] ?? "") as String; + String get targetDate => getString("target_date"); - int get lineItemCount => (jsondata["line_items"] ?? 0) as int; + int get lineItemCount => getInt("line_items", backup: 0); + + bool get overdue => getBool("overdue"); - bool get overdue => (jsondata["overdue"] ?? false) as bool; + String get reference => getString("reference"); - String get reference => (jsondata["reference"] ?? "") as String; + int get responsibleId => getInt("responsible"); - int get responsibleId => (jsondata["responsible"] ?? -1) as int; + int get supplierId => getInt("supplier"); - int get supplierId => (jsondata["supplier"] ?? -1) as int; + // Project code information + int get projectCodeId => getInt("project_code"); + + String get projectCode => getString("code", subKey: "project_code_detail"); + + String get projectCodeDescription => getString("description", subKey: "project_code_detail"); + + bool get hasProjectCode => projectCode.isNotEmpty; InvenTreeCompany? get supplier { @@ -88,11 +98,11 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } } - String get supplierReference => (jsondata["supplier_reference"] ?? "") as String; + String get supplierReference => getString("supplier_reference"); - int get status => (jsondata["status"] ?? -1) as int; + int get status => getInt("status"); - String get statusText => (jsondata["status_text"] ?? "") as String; + String get statusText => getString("status_text"); bool get isOpen => status == PO_STATUS_PENDING || status == PO_STATUS_PLACED; @@ -103,7 +113,7 @@ class InvenTreePurchaseOrder extends InvenTreeModel { bool get isFailed => status == PO_STATUS_CANCELLED || status == PO_STATUS_LOST || status == PO_STATUS_RETURNED; double? get totalPrice { - String price = (jsondata["total_price"] ?? "") as String; + String price = getString("total_price"); if (price.isEmpty) { return null; @@ -112,7 +122,7 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } } - String get totalPriceCurrency => (jsondata["total_price_currency"] ?? "") as String; + String get totalPriceCurrency => getString("total_price_currency"); Future> getLineItems() async { @@ -134,9 +144,7 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePurchaseOrder.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrder.fromJson(json); /// Mark this order as "placed" / "issued" Future issueOrder() async { @@ -199,17 +207,17 @@ class InvenTreePOLineItem extends InvenTreeModel { bool get isComplete => received >= quantity; - double get quantity => (jsondata["quantity"] ?? 0) as double; + double get quantity => getDouble("quantity"); - double get received => (jsondata["received"] ?? 0) as double; + double get received => getDouble("received"); double get outstanding => quantity - received; - String get reference => (jsondata["reference"] ?? "") as String; + String get reference => getString("reference"); - int get orderId => (jsondata["order"] ?? -1) as int; + int get orderId => getInt("order"); - int get supplierPartId => (jsondata["part"] ?? -1) as int; + int get supplierPartId => getInt("part"); InvenTreePart? get part { dynamic part_detail = jsondata["part_detail"]; @@ -232,20 +240,19 @@ class InvenTreePOLineItem extends InvenTreeModel { } } - double get purchasePrice => double.parse((jsondata["purchase_price"] ?? "") as String); + double get purchasePrice => getDouble("purchase_price"); + + String get purchasePriceCurrency => getString("purchase_price_currency"); - String get purchasePriceCurrency => (jsondata["purchase_price_currency"] ?? "") as String; + String get purchasePriceString => getString("purchase_price_string"); - String get purchasePriceString => (jsondata["purchase_price_string"] ?? "") as String; - - int get destination => (jsondata["destination"] ?? -1) as int; - - Map get destinationDetail => (jsondata["destination_detail"] ?? {}) as Map; + int get destination => getInt("destination"); + Map get destinationDetail => getMap("destination_detail"); + @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePOLineItem.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePOLineItem.fromJson(json); + } /* @@ -264,7 +271,6 @@ class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { String get URL => "order/po/attachment/"; @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePurchaseOrderAttachment.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrderAttachment.fromJson(json); + } diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 10b5448..4a02617 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -35,18 +35,18 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { }; } - String get key => (jsondata["key"] ?? "") as String; - - String get testName => (jsondata["test"] ?? "") as String; - - bool get result => (jsondata["result"] ?? false) as bool; - - String get value => (jsondata["value"] ?? "") as String; - - String get attachment => (jsondata["attachment"] ?? "") as String; - - String get date => (jsondata["date"] ?? "") as String; + String get key => getString("key"); + + String get testName => getString("test"); + bool get result => getBool("result"); + + String get value => getString("value"); + + String get attachment => getString("attachment"); + + String get date => getString("date"); + @override InvenTreeStockItemTestResult createFromJson(Map json) { var result = InvenTreeStockItemTestResult.fromJson(json); @@ -63,9 +63,7 @@ class InvenTreeStockItemHistory extends InvenTreeModel { InvenTreeStockItemHistory.fromJson(Map json) : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeStockItemHistory.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreeStockItemHistory.fromJson(json); @override String get URL => "stock/track/"; @@ -98,16 +96,10 @@ class InvenTreeStockItemHistory extends InvenTreeModel { return DateFormat("yyyy-MM-dd").format(d); } - String get label => (jsondata["label"] ?? "") as String; - + String get label => getString("label"); + // Return the "deltas" associated with this historical object - Map get deltas { - if (jsondata.containsKey("deltas")) { - return jsondata["deltas"] as Map; - } else { - return {}; - } - } + Map get deltas => getMap("deltas"); // Return the quantity string for this historical object String get quantityString { @@ -122,12 +114,13 @@ class InvenTreeStockItemHistory extends InvenTreeModel { } } - String get userString { - return (jsondata["user_detail"]?["username"] ?? "") as String; - } + String get userString => getString("username", subKey: "user_detail"); } +/* + * Class representing a StockItem database instance + */ class InvenTreeStockItem extends InvenTreeModel { InvenTreeStockItem() : super(); @@ -237,16 +230,16 @@ class InvenTreeStockItem extends InvenTreeModel { }); } - int get status => (jsondata["status"] ?? -1) as int; + int get status => getInt("status"); + + String get packaging => getString("packaging"); - String get packaging => (jsondata["packaging"] ?? "") as String; + String get batch => getString("batch"); - String get batch => (jsondata["batch"] ?? "") as String; - - int get partId => (jsondata["part"] ?? -1) as int; + int get partId => getInt("part"); double? get purchasePrice { - String pp = (jsondata["purchase_price"] ?? "") as String; + String pp = getString("purchase_price"); if (pp.isEmpty) { return null; @@ -255,18 +248,18 @@ class InvenTreeStockItem extends InvenTreeModel { } } - String get purchasePriceCurrency => (jsondata["purchase_price_currency"] ?? "") as String; + String get purchasePriceCurrency => getString("purchase_price_currency"); bool get hasPurchasePrice { double? pp = purchasePrice; return pp != null && pp > 0; } - int get purchaseOrderId => (jsondata["purchase_order"] ?? -1) as int; + int get purchaseOrderId => getInt("purchase_order"); - int get trackingItemCount => (jsondata["tracking_items"] ?? 0) as int; - - bool get isBuilding => (jsondata["is_building"] ?? false) as bool; + int get trackingItemCount => getInt("tracking_items", backup: 0); + + bool get isBuilding => getBool("is_building"); // Date of last update DateTime? get updatedDate { @@ -320,7 +313,7 @@ class InvenTreeStockItem extends InvenTreeModel { // Backup if first value fails if (nm.isEmpty) { - nm = (jsondata["part__name"] ?? "") as String; + nm = getString("part__name"); } return nm; @@ -335,7 +328,7 @@ class InvenTreeStockItem extends InvenTreeModel { } if (desc.isEmpty) { - desc = (jsondata["part__description"] ?? "") as String; + desc = getString("part__description"); } return desc; @@ -349,7 +342,7 @@ class InvenTreeStockItem extends InvenTreeModel { } if (img.isEmpty) { - img = (jsondata["part__thumbnail"] ?? "") as String; + img = getString("part__thumbnail"); } return img; @@ -371,7 +364,7 @@ class InvenTreeStockItem extends InvenTreeModel { // Try a different approach if (thumb.isEmpty) { - thumb = (jsondata["part__thumbnail"] ?? "") as String; + thumb = getString("part__thumbnail"); } // Still no thumbnail? Use the "no image" image @@ -380,7 +373,7 @@ class InvenTreeStockItem extends InvenTreeModel { return thumb; } - int get supplierPartId => (jsondata["supplier_part"] ?? -1) as int; + int get supplierPartId => getInt("supplier_part"); String get supplierImage { String thumb = ""; @@ -394,33 +387,15 @@ class InvenTreeStockItem extends InvenTreeModel { return thumb; } - String get supplierName { - String sname = ""; + String get supplierName => getString("supplier_name", subKey: "supplier_detail"); - if (jsondata.containsKey("supplier_detail")) { - sname = (jsondata["supplier_detail"]["supplier_name"] ?? "") as String; - } + String get units => getString("units", subKey: "part_detail"); - return sname; - } + String get supplierSKU => getString("SKU", subKey: "supplier_part_detail"); - String get units { - return (jsondata["part_detail"]?["units"] ?? "") as String; - } + String get serialNumber => getString("serial"); - String get supplierSKU { - String sku = ""; - - if (jsondata.containsKey("supplier_part_detail")) { - sku = (jsondata["supplier_part_detail"]["SKU"] ?? "") as String; - } - - return sku; - } - - String get serialNumber => (jsondata["serial"] ?? "") as String; - - double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; + double get quantity => getDouble("quantity"); String quantityString({bool includeUnits = false}){ @@ -440,11 +415,11 @@ class InvenTreeStockItem extends InvenTreeModel { return q; } - double get allocated => double.tryParse(jsondata["allocated"].toString()) ?? 0; + double get allocated => getDouble("allocated"); double get available => quantity - allocated; - int get locationId => (jsondata["location"] ?? -1) as int; + int get locationId => getInt("location"); bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; @@ -459,15 +434,14 @@ class InvenTreeStockItem extends InvenTreeModel { } String get locationName { - String loc = ""; if (locationId == -1 || !jsondata.containsKey("location_detail")) return "Unknown Location"; - loc = (jsondata["location_detail"]["name"] ?? "") as String; + String loc = getString("name", subKey: "location_detail"); // Old-style name if (loc.isEmpty) { - loc = (jsondata["location__name"] ?? "") as String; + loc = getString("location__name"); } return loc; @@ -477,8 +451,7 @@ class InvenTreeStockItem extends InvenTreeModel { if (locationId == -1 || !jsondata.containsKey("location_detail")) return L10().locationNotSet; - String _loc = (jsondata["location_detail"]["pathstring"] ?? "") as String; - + String _loc = getString("pathstring", subKey: "location_detail"); if (_loc.isNotEmpty) { return _loc; } else { @@ -497,9 +470,7 @@ class InvenTreeStockItem extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeStockItem.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreeStockItem.fromJson(json); /* * Perform stocktake action: @@ -601,9 +572,7 @@ class InvenTreeStockItemAttachment extends InvenTreeAttachment { String get URL => "stock/attachment/"; @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeStockItemAttachment.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => InvenTreeStockItemAttachment.fromJson(json); } @@ -620,7 +589,7 @@ class InvenTreeStockLocation extends InvenTreeModel { @override List get rolesRequired => ["stock_location"]; - String get pathstring => (jsondata["pathstring"] ?? "") as String; + String get pathstring => getString("pathstring"); @override Map formFields() { @@ -658,10 +627,6 @@ class InvenTreeStockLocation extends InvenTreeModel { int get itemcount => (jsondata["items"] ?? 0) as int; @override - InvenTreeModel createFromJson(Map json) { + InvenTreeModel createFromJson(Map json) => InvenTreeStockLocation.fromJson(json); - var loc = InvenTreeStockLocation.fromJson(json); - - return loc; - } -} \ No newline at end of file +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 66ded8b..9802d72 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -759,6 +759,9 @@ "profileTapToCreate": "Tap to create or select a profile", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 1e405f0..e6017c5 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -43,6 +43,8 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; @@ -139,6 +141,8 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { var fields = order.formFields(); + + // Cannot edit supplier field from here fields.remove("supplier"); + // Contact model not supported by server if (!api.supportsContactModel) { fields.remove("contact"); } + // ProjectCode model not supported by server + if (!supportProjectCodes) { + fields.remove("project_code"); + } + order.editForm( context, L10().purchaseOrderEdit, @@ -202,6 +214,14 @@ class _PurchaseOrderDetailState extends RefreshableState Date: Fri, 21 Apr 2023 21:24:06 +1000 Subject: [PATCH 356/746] Allow stock items to be created from top-level location (#338) (cherry picked from commit fd85abf9d8e4760dd3ed793cf38d3bc5c29f17b8) --- lib/widget/location_display.dart | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 9f74e8b..d693314 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -157,7 +157,7 @@ class _LocationDisplayState extends RefreshableState { } // Create new item - if (location != null && InvenTreeStockItem().canCreate) { + if (InvenTreeStockItem().canCreate) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.boxesStacked), @@ -243,11 +243,6 @@ class _LocationDisplayState extends RefreshableState { * Launch a dialog form to create a new stock item */ Future _newStockItem(BuildContext context) async { - int pk = location?.pk ?? -1; - - if (location != null && pk <= 0) { - return; - } var fields = InvenTreeStockItem().formFields(); @@ -258,7 +253,7 @@ class _LocationDisplayState extends RefreshableState { context, L10().stockItemCreate, data: { - "location": location != null ? pk : null, + "location": location != null ? location!.pk : null, }, fields: fields, onSuccess: (result) async { From 2c5ceeabdba7799e2d2db886fa66069f02e9674e Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 21 Apr 2023 21:24:14 +1000 Subject: [PATCH 357/746] Handle OSError when attempting connection (#339) --- lib/api.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/api.dart b/lib/api.dart index 7a41572..be2ba80 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1078,6 +1078,10 @@ class InvenTreeAPI { debug("TimeoutException at ${url}"); showTimeoutError(url); return null; + } on OSError catch (error) { + debug("OSError at ${url}: ${error.toString()}"); + showServerError(url, L10().connectionRefused, error.toString()); + return null; } on CertificateException catch (error) { debug("CertificateException at ${url}:"); debug(error.toString()); From b7e806efeee5e4941be620b811cbbf962c428426 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 21 Apr 2023 23:15:00 +1000 Subject: [PATCH 358/746] PO Line Item Improvements (#340) * Refactor thumbnail image * Add paginated list of purchase order line items * Refactor getBody() function - No longer "have" to specify - Can use getTiles for a simpler interface * Add detail widget for polineitem * add pricing info * Receive line items via action button * tweak color * update release notes * linting fixes --- assets/release_notes.md | 1 + lib/api.dart | 2 + lib/api_form.dart | 8 +- lib/inventree/purchase_order.dart | 39 +++- lib/l10n/app_en.arb | 20 +- lib/widget/attachment_widget.dart | 14 +- lib/widget/bom_list.dart | 12 +- lib/widget/company_detail.dart | 14 +- lib/widget/company_list.dart | 8 +- lib/widget/notifications.dart | 18 +- lib/widget/part_list.dart | 6 +- lib/widget/part_suppliers.dart | 6 +- lib/widget/po_line_detail.dart | 249 ++++++++++++++++++++++++ lib/widget/po_line_list.dart | 91 +++++++++ lib/widget/purchase_order_detail.dart | 166 +--------------- lib/widget/purchase_order_list.dart | 6 +- lib/widget/refreshable_state.dart | 26 +-- lib/widget/search.dart | 14 +- lib/widget/stock_detail.dart | 20 +- lib/widget/stock_item_test_results.dart | 16 +- lib/widget/stock_list.dart | 6 +- lib/widget/supplier_part_detail.dart | 31 +-- lib/widget/supplier_part_list.dart | 12 +- 23 files changed, 442 insertions(+), 343 deletions(-) create mode 100644 lib/widget/po_line_detail.dart create mode 100644 lib/widget/po_line_list.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 1d67fe5..39384b7 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Add support for Project Codes +- Improve purchase order support - Fix action button colors - Added Norwegian translations - Fix serial number field when creating stock item diff --git a/lib/api.dart b/lib/api.dart index be2ba80..fdb1fbc 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1312,6 +1312,8 @@ class InvenTreeAPI { static String get staticThumb => "/static/img/blank_image.thumbnail.png"; + CachedNetworkImage getThumbnail(String imageUrl, {double size = 40}) => getImage(imageUrl, width: size, height: size); + /* * Load image from the InvenTree server, * or from local cache (if it has been cached!) diff --git a/lib/api_form.dart b/lib/api_form.dart index d08d29a..83cf3e8 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -612,7 +612,7 @@ class APIFormField { part.description, style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), ) : null, - leading: extended ? InvenTreeAPI().getImage(part.thumbnail, width: 40, height: 40) : null, + leading: extended ? InvenTreeAPI().getThumbnail(part.thumbnail) : null, ); case "partcategory": @@ -662,11 +662,7 @@ class APIFormField { return ListTile( title: Text(company.name), subtitle: extended ? Text(company.description) : null, - leading: InvenTreeAPI().getImage( - company.thumbnail, - width: 40, - height: 40 - ) + leading: InvenTreeAPI().getThumbnail(company.thumbnail) ); case "projectcode": var project_code = InvenTreeProjectCode.fromJson(data); diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index e22d009..5a4ac72 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,3 +1,4 @@ +import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/model.dart"; @@ -175,19 +176,27 @@ class InvenTreePOLineItem extends InvenTreeModel { @override String get URL => "order/po-line/"; + @override + List get rolesRequired => ["purchase_order"]; + @override Map formFields() { return { - // TODO: @Guusggg Not sure what will come here. - // "quantity": {}, - // "reference": {}, - // "notes": {}, - // "order": {}, - // "part": {}, - "received": {}, - // "purchase_price": {}, - // "purchase_price_currency": {}, - // "destination": {} + "part": { + // We cannot edit the supplier part field here + "hidden": true, + }, + "order": { + // We cannot edit the order field here + "hidden": true, + }, + "reference": {}, + "quantity": {}, + "purchase_price": {}, + "purchase_price_currency": {}, + "destination": {}, + "notes": {}, + "link": {}, }; } @@ -211,6 +220,8 @@ class InvenTreePOLineItem extends InvenTreeModel { double get received => getDouble("received"); + String get progressString => simpleNumberString(received) + " / " + simpleNumberString(quantity); + double get outstanding => quantity - received; String get reference => getString("reference"); @@ -229,6 +240,12 @@ class InvenTreePOLineItem extends InvenTreeModel { } } + int get partId => getInt("pk", subKey: "part_detail"); + + String get partName => getString("name", subKey: "part_detail"); + + String get partImage => getString("thumbnail", subKey: "part_detail"); + InvenTreeSupplierPart? get supplierPart { dynamic detail = jsondata["supplier_part_detail"]; @@ -240,6 +257,8 @@ class InvenTreePOLineItem extends InvenTreeModel { } } + String get SKU => getString("SKU", subKey: "supplier_part_detail"); + double get purchasePrice => getDouble("purchase_price"); String get purchasePriceCurrency => getString("purchase_price_currency"); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9802d72..89edcc9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -274,6 +274,9 @@ "editItem": "Edit Stock Item", "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", "@enterPassword": {}, @@ -534,6 +537,9 @@ "lineItems": "Line Items", "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", "@locateItem": {}, @@ -612,7 +618,7 @@ "outstanding": "Outstanding", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Show outstanding items", "@outstandingOrderDetail": {}, "packaging": "Packaging", @@ -797,9 +803,6 @@ "quantityPositive": "Quantity must be positive", "@quantityPositive": {}, - "quarantined": "Quarantined", - "@quarantined": {}, - "queryEmpty": "Enter search query", "@queryEmpty": {}, @@ -809,6 +812,9 @@ "received": "Received", "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", "@receiveItem": {}, @@ -1038,6 +1044,9 @@ "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", "@sounds": {}, @@ -1256,6 +1265,9 @@ "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", "@units": {}, diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index bdfb415..1a31993 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -147,19 +147,7 @@ class _AttachmentWidgetState extends RefreshableState { } @override - Widget getBody(BuildContext context) { - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: attachmentTiles(context) - ).toList(), - ) - ); - } - - - List attachmentTiles(BuildContext context) { + List getTiles(BuildContext context) { List tiles = []; diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 8504c75..f1d867d 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -71,11 +71,7 @@ class _BillOfMaterialsState extends RefreshableState { return Column( children: [ ListTile( - leading: InvenTreeAPI().getImage( - widget.part.thumbnail, - width: 32, - height: 32, - ), + leading: InvenTreeAPI().getThumbnail(widget.part.thumbnail), title: Text(widget.part.fullname), subtitle: Text(widget.isParentComponent ? L10().billOfMaterials : L10().usedInDetails), trailing: Text(L10().quantity), @@ -153,11 +149,7 @@ class _PaginatedBomListState extends PaginatedSearchState { simpleNumberString(bomItem.quantity), style: TextStyle(fontWeight: FontWeight.bold), ), - leading: InvenTreeAPI().getImage( - subPart?.thumbnail ?? "", - width: 40, - height: 40, - ), + leading: InvenTreeAPI().getThumbnail(subPart?.thumbnail ?? ""), onTap: subPart == null ? null : () async { showLoadingOverlay(context); diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index c1d98a5..15684a1 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -130,7 +130,8 @@ class _CompanyDetailState extends RefreshableState { /* * Construct a list of tiles to display for this Company instance */ - List _companyTiles() { + @override + List getTiles(BuildContext context) { List tiles = []; @@ -140,7 +141,7 @@ class _CompanyDetailState extends RefreshableState { child: ListTile( title: Text("${widget.company.name}"), subtitle: Text("${widget.company.description}"), - leading: InvenTreeAPI().getImage(widget.company.image, width: 40, height: 40), + leading: InvenTreeAPI().getThumbnail(widget.company.image), ), )); @@ -290,13 +291,4 @@ class _CompanyDetailState extends RefreshableState { return tiles; } - @override - Widget getBody(BuildContext context) { - - return Center( - child: ListView( - children: _companyTiles(), - ) - ); - } } \ No newline at end of file diff --git a/lib/widget/company_list.dart b/lib/widget/company_list.dart index de9a539..fe6ecca 100644 --- a/lib/widget/company_list.dart +++ b/lib/widget/company_list.dart @@ -69,14 +69,10 @@ class _CompanyListState extends PaginatedSearchState { return ListTile( title: Text(company.name), subtitle: Text(company.description), - leading: InvenTreeAPI().getImage( - company.image, - width: 40, - height: 40 - ), + leading: InvenTreeAPI().getThumbnail(company.image), onTap: () async { Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyDetailWidget(company))); }, ); } -} \ No newline at end of file +} diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 6b37d83..966890c 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -54,7 +54,8 @@ class _NotificationState extends RefreshableState { /* * Display an individual notification message */ - List renderNotifications(BuildContext context) { + @override + List getTiles(BuildContext context) { List tiles = []; @@ -87,17 +88,4 @@ class _NotificationState extends RefreshableState { return tiles; } - - @override - Widget getBody(BuildContext context) { - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: renderNotifications(context), - ).toList() - ) - ); - } - -} \ No newline at end of file +} diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index b6b7bc5..0b00bb9 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -133,11 +133,7 @@ class _PaginatedPartListState extends PaginatedSearchState { title: Text(part.fullname), subtitle: Text(part.description), trailing: Text(part.stockString()), - leading: InvenTreeAPI().getImage( - part.thumbnail, - width: 40, - height: 40, - ), + leading: InvenTreeAPI().getThumbnail(part.thumbnail), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); }, diff --git a/lib/widget/part_suppliers.dart b/lib/widget/part_suppliers.dart index 36b3900..b9fb05a 100644 --- a/lib/widget/part_suppliers.dart +++ b/lib/widget/part_suppliers.dart @@ -51,11 +51,7 @@ class _PartSupplierState extends RefreshableState { InvenTreeSupplierPart _part = _supplierParts[index]; return ListTile( - leading: InvenTreeAPI().getImage( - _part.supplierImage, - width: 40, - height: 40, - ), + leading: InvenTreeAPI().getThumbnail(_part.supplierImage), title: Text("${_part.SKU}"), subtitle: Text("${_part.manufacturerName}: ${_part.MPN}"), onTap: () async { diff --git a/lib/widget/po_line_detail.dart b/lib/widget/po_line_detail.dart new file mode 100644 index 0000000..9391cdf --- /dev/null +++ b/lib/widget/po_line_detail.dart @@ -0,0 +1,249 @@ +import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +import "package:inventree/api_form.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/part_detail.dart"; + +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/snacks.dart"; +import "package:inventree/widget/supplier_part_detail.dart"; + +/* + * Widget for displaying detail view of a purchase order line item +*/ +class POLineDetailWidget extends StatefulWidget { + + const POLineDetailWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreePOLineItem item; + + @override + _POLineDetailWidgetState createState() => _POLineDetailWidgetState(); + +} + + +/* + * State for the POLineDetailWidget + */ +class _POLineDetailWidgetState extends RefreshableState { + + _POLineDetailWidgetState(); + + @override + String getAppBarTitle() => L10().lineItem; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.item.canEdit) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + onPressed: () { + _editLineItem(context); + }, + ) + ); + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List buttons = []; + + if (widget.item.canCreate) { + // Receive items + if (!widget.item.isComplete) { + buttons.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.rightToBracket, color: Colors.blue), + label: L10().receiveItem, + onTap: () async { + receiveLineItem(context); + } + ) + ); + } + } + + return buttons; + } + + @override + Future request(BuildContext context) async { + await widget.item.reload(); + } + + // Callback to edit this line item + Future _editLineItem(BuildContext context) async { + var fields = widget.item.formFields(); + + widget.item.editForm( + context, + L10().editLineItem, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().lineItemUpdated, success: true); + } + ); + } + + // Launch a form to 'receive' this line item + Future receiveLineItem(BuildContext context) async { + + // Construct fields to receive + Map fields = { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + "value": widget.item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": widget.item.outstanding, + }, + "status": { + "parent": "items", + "nested": true, + }, + "location": { + }, + "barcode": { + "parent": "items", + "nested": true, + "type": "barcode", + "label": L10().barcodeAssign, + "required": false, + } + }; + + showLoadingOverlay(context); + var order = await InvenTreePurchaseOrder().get(widget.item.orderId); + hideLoadingOverlay(); + + if (order is InvenTreePurchaseOrder) { + launchApiForm( + context, + L10().receiveItem, + order.receive_url, + fields, + method: "POST", + icon: FontAwesomeIcons.rightToBracket, + onSuccess: (data) async { + showSnackIcon(L10().receivedItem, success: true); + refresh(context); + } + ); + } else { + showSnackIcon(L10().error); + return; + } + } + + @override + List getTiles(BuildContext context) { + List tiles = []; + + // Reference to the part + tiles.add( + ListTile( + title: Text(L10().internalPart), + subtitle: Text(widget.item.partName), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + trailing: api.getThumbnail(widget.item.partImage), + onTap: () async { + showLoadingOverlay(context); + print("part id: ${widget.item.partId}"); + var part = await InvenTreePart().get(widget.item.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + } + }, + ) + ); + + // Reference to the supplier part + tiles.add( + ListTile( + title: Text(L10().supplierPart), + subtitle: Text(widget.item.SKU), + leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), + onTap: () async { + showLoadingOverlay(context); + var part = await InvenTreeSupplierPart().get(widget.item.supplierPartId); + hideLoadingOverlay(); + + if (part is InvenTreeSupplierPart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierPartDetailWidget(part))); + } + }, + ) + ); + + // Recevied + tiles.add( + ListTile( + title: Text(L10().received), + subtitle: Text(widget.item.received.toString()), + trailing: Text(widget.item.progressString, style: TextStyle(color: widget.item.isComplete ? COLOR_SUCCESS: COLOR_WARNING)), + leading: FaIcon(FontAwesomeIcons.boxOpen), + ) + ); + + // Pricing information + tiles.add( + ListTile( + title: Text(L10().unitPrice), + leading: FaIcon(FontAwesomeIcons.dollarSign), + trailing: Text( + renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) + ), + ) + ); + + // Note + if (widget.item.notes.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.item.notes), + leading: FaIcon(FontAwesomeIcons.noteSticky), + ) + ); + } + + // External link + if (widget.item.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().link), + subtitle: Text(widget.item.link), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + onTap: () async { + await openLink(widget.item.link); + }, + ) + ); + } + + return tiles; + } + +} \ No newline at end of file diff --git a/lib/widget/po_line_list.dart b/lib/widget/po_line_list.dart new file mode 100644 index 0000000..13946a1 --- /dev/null +++ b/lib/widget/po_line_list.dart @@ -0,0 +1,91 @@ +import "package:flutter/material.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/purchase_order.dart"; + +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/po_line_detail.dart"; +import "package:inventree/widget/progress.dart"; + +/* + * Paginated widget class for displaying a list of purchase order line items + */ +class PaginatedPOLineList extends PaginatedSearchWidget { + + const PaginatedPOLineList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + + @override + _PaginatedPOLineListState createState() => _PaginatedPOLineListState(); + +} + +/* + * State class for PaginatedPOLineList +*/ +class _PaginatedPOLineListState extends PaginatedSearchState { + + _PaginatedPOLineListState() : super(); + + @override + String get prefix => "po_line_"; + + @override + Map get orderingOptions => { + "part": L10().part, + "SKU": L10().sku, + "quantity": L10().quantity, + }; + + @override + Map> get filterOptions => { + "pending": { + "label": L10().outstanding, + "help_text": L10().outstandingOrderDetail, + "tristate": true, + }, + "received": { + "label": L10().received, + "help_text": L10().receivedFilterDetail, + "tristate": true, + } + }; + + @override + Future requestPage(int limit, int offset, Map params) async { + + final page = await InvenTreePOLineItem().listPaginated(limit, offset, filters: params); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreePOLineItem item = model as InvenTreePOLineItem; + InvenTreeSupplierPart? supplierPart = item.supplierPart; + + if (supplierPart != null) { + return ListTile( + title: Text(supplierPart.SKU), + subtitle: Text(supplierPart.partName), + trailing: Text(item.progressString, style: TextStyle(color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING)), + leading: InvenTreeAPI().getThumbnail(supplierPart.partImage), + onTap: () async { + showLoadingOverlay(context); + await item.reload(); + hideLoadingOverlay(); + Navigator.push(context, MaterialPageRoute(builder: (context) => POLineDetailWidget(item))); + }, + ); + } else { + // Return an error tile + return ListTile( + title: Text(L10().error), + subtitle: Text("supplier part not defined", style: TextStyle(color: COLOR_DANGER)), + ); + } + } +} diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index e6017c5..8b2b650 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -2,10 +2,9 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:one_context/one_context.dart"; +import "package:inventree/widget/po_line_list.dart"; import "package:inventree/api.dart"; -import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -194,7 +193,7 @@ class _PurchaseOrderDetailState extends RefreshableState fields = { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - "value": lineItem.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": lineItem.outstanding, - }, - "status": { - "parent": "items", - "nested": true, - }, - "location": { - }, - "barcode": { - "parent": "items", - "nested": true, - "type": "barcode", - "label": L10().barcodeAssign, - "required": false, - } - }; - - // TODO: Pre-fill the "location" value if the part has a default location specified - - launchApiForm( - context, - L10().receiveItem, - order.receive_url, - fields, - method: "POST", - icon: FontAwesomeIcons.rightToBracket, - onSuccess: (data) async { - showSnackIcon(L10().receivedItem, success: true); - refresh(context); - } - ); - } - - /* - * Display a context menu for a particular PurhaseOrderLineItem - */ - void lineItemMenu(BuildContext context, InvenTreePOLineItem lineItem) { - - List children = []; - - // TODO: Add in this option once the SupplierPart detail view is implemented - /* - children.add( - SimpleDialogOption( - onPressed: () { - OneContext().popDialog(); - - // TODO: Navigate to the "SupplierPart" display? - }, - child: ListTile( - title: Text(L10().viewSupplierPart), - leading: FaIcon(FontAwesomeIcons.eye), - ) - ) - ); - */ - - if (order.isPlaced && InvenTreeAPI().supportsPoReceive) { - children.add( - SimpleDialogOption( - onPressed: () { - // Hide the dialog option - OneContext().popDialog(); - - receiveLine(context, lineItem); - }, - child: ListTile( - title: Text(L10().receiveItem), - leading: FaIcon(FontAwesomeIcons.rightToBracket), - ) - ) - ); - } - - // No valid actions available - if (children.isEmpty) { - return; - } - - children.insert(0, Divider()); - - OneContext().showDialog( - builder: (BuildContext context) { - return SimpleDialog( - title: Text(L10().lineItem), - children: children, - ); - } - ); - - } - - List lineTiles(BuildContext context) { - - List tiles = []; - - for (var line in lines) { - - InvenTreeSupplierPart? supplierPart = line.supplierPart; - - if (supplierPart != null) { - - String q = simpleNumberString(line.quantity); - - Color c = Colors.black; - - if (order.isOpen) { - - q = simpleNumberString(line.received) + " / " + simpleNumberString(line.quantity); - - if (line.isComplete) { - c = COLOR_SUCCESS; - } else { - c = COLOR_DANGER; - } - } - - tiles.add( - ListTile( - title: Text(supplierPart.SKU), - subtitle: Text(supplierPart.partName), - leading: InvenTreeAPI().getImage(supplierPart.partImage, width: 40, height: 40), - trailing: Text( - q, - style: TextStyle( - color: c, - ), - ), - onTap: () { - lineItemMenu(context, line); - }, - ) - ); - } - } - - return tiles; - } - @override List getTabIcons(BuildContext context) { return [ @@ -484,7 +331,8 @@ class _PurchaseOrderDetailState extends RefreshableState getTabs(BuildContext context) { return [ ListView(children: orderTiles(context)), - ListView(children: lineTiles(context)), + PaginatedPOLineList({"order": order.pk.toString()}, true), + // ListView(children: lineTiles(context)), PaginatedStockItemList({"purchase_order": order.pk.toString()}, true), ]; } diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index a228198..913a7e2 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -154,11 +154,7 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState getTabs(BuildContext context) => []; - // Function to construct a body (MUST BE PROVIDED) + // Function to construct a set of tiles for this widget (override if needed) + List getTiles(BuildContext context) => []; + + // Function to construct a body Widget getBody(BuildContext context) { - // Default return is an empty ListView - return ListView(); + // Default body calls getTiles() + return Column( + children: getTiles(context) + ); } @@ -257,15 +263,11 @@ abstract class RefreshableState extends State with floatingActionButton: buildSpeedDial(context), floatingActionButtonLocation: FloatingActionButtonLocation .miniEndDocked, - body: Builder( - builder: (BuildContext context) { - return RefreshIndicator( - onRefresh: () async { - refresh(context); - }, - child: body - ); - } + body: RefreshIndicator( + onRefresh: () async { + refresh(context); + }, + child: body ), bottomNavigationBar: buildBottomAppBar(context, refreshableKey), ); diff --git a/lib/widget/search.dart b/lib/widget/search.dart index fd8fcab..a719633 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -333,7 +333,8 @@ class _SearchDisplayState extends RefreshableState { } } - List _tiles(BuildContext context) { + @override + List getTiles(BuildContext context) { List tiles = []; @@ -542,15 +543,4 @@ class _SearchDisplayState extends RefreshableState { return tiles; } - @override - Widget getBody(BuildContext context) { - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: _tiles(context), - ).toList() - ) - ); - } } diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index b2dcc2c..7dc3c11 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -567,7 +567,7 @@ class _StockItemDisplayState extends RefreshableState { child: ListTile( title: Text("${widget.item.partName}"), subtitle: Text("${widget.item.partDescription}"), - leading: InvenTreeAPI().getImage(widget.item.partImage), + leading: InvenTreeAPI().getThumbnail(widget.item.partImage), trailing: Text( api.StockStatus.label(widget.item.status), style: TextStyle( @@ -595,7 +595,8 @@ class _StockItemDisplayState extends RefreshableState { * Construct a list of detail elements about this StockItem. * The number of elements may vary depending on the StockItem details */ - List detailTiles() { + @override + List getTiles(BuildContext context) { List tiles = []; // Image / name / description @@ -667,11 +668,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), - trailing: InvenTreeAPI().getImage( - widget.item.supplierImage, - width: 40, - height: 40, - ), + trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage), onTap: () async { showLoadingOverlay(context); var sp = await InvenTreeSupplierPart().get( @@ -845,13 +842,4 @@ class _StockItemDisplayState extends RefreshableState { return tiles; } - @override - Widget getBody(BuildContext context) { - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: detailTiles() - ).toList() - ); - } } \ No newline at end of file diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index fc0ef4b..b89a01b 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -113,7 +113,8 @@ class _StockItemTestResultDisplayState extends RefreshableState resultsList() { + @override + List getTiles(BuildContext context) { List tiles = []; tiles.add( @@ -121,7 +122,7 @@ class _StockItemTestResultDisplayState extends RefreshableState detailTiles(BuildContext context) { + @override + List getTiles(BuildContext context) { List tiles = []; if (loading) { @@ -116,11 +117,7 @@ class _SupplierPartDisplayState extends RefreshableState Date: Sat, 22 Apr 2023 22:26:16 +1000 Subject: [PATCH 359/746] New Crowdin updates (#341) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (German) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (French) * New translations app_en.arb (Norwegian) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ---- lib/l10n/de_DE/app_de_DE.arb | 2 -- lib/l10n/es_ES/app_es_ES.arb | 2 -- lib/l10n/es_MX/app_es_MX.arb | 2 -- lib/l10n/fr_FR/app_fr_FR.arb | 4 ---- lib/l10n/hu_HU/app_hu_HU.arb | 4 ---- lib/l10n/it_IT/app_it_IT.arb | 2 -- lib/l10n/nl_NL/app_nl_NL.arb | 2 -- lib/l10n/no_NO/app_no_NO.arb | 32 +++++++++++++++++++++----------- lib/l10n/pt_BR/app_pt_BR.arb | 2 -- lib/l10n/tr_TR/app_tr_TR.arb | 2 -- 11 files changed, 21 insertions(+), 37 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index e52baff..8567644 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -415,8 +415,6 @@ "@onOrderDetails": {}, "outstanding": "Nevyřízené", "@outstanding": {}, - "outstandingOrderDetail": "Zobrazit nevyřízené objednávky", - "@outstandingOrderDetail": {}, "packaging": "Balení", "@packaging": {}, "packageName": "Název balíčku", @@ -539,8 +537,6 @@ "@quantityInvalid": {}, "quantityPositive": "Množství musí být kladné.", "@quantityPositive": {}, - "quarantined": "V karanténě", - "@quarantined": {}, "queryEmpty": "Zadejte hledaný dotaz", "@queryEmpty": {}, "queryNoResults": "Žádné výsledky dotazu", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index a975d45..32fdd56 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -513,8 +513,6 @@ "@quantityInvalid": {}, "quantityPositive": "Menge muss positiv sein", "@quantityPositive": {}, - "quarantined": "In Quarantäne", - "@quarantined": {}, "queryEmpty": "Suchanfrage eingeben", "@queryEmpty": {}, "queryNoResults": "Keine Ergebnisse für die Anfrage", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index ce3bb38..6417056 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -511,8 +511,6 @@ "@quantityInvalid": {}, "quantityPositive": "La longitud debe ser positiva", "@quantityPositive": {}, - "quarantined": "En Cuarentena", - "@quarantined": {}, "queryEmpty": "Ingresar consulta de búsqueda", "@queryEmpty": {}, "queryNoResults": "No hay resultados para la consulta", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index e2a5f9c..3fce6a2 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -511,8 +511,6 @@ "@quantityInvalid": {}, "quantityPositive": "La cantidad debe ser positiva", "@quantityPositive": {}, - "quarantined": "En cuarentena", - "@quarantined": {}, "queryEmpty": "Ingresar consulta de búsqueda", "@queryEmpty": {}, "queryNoResults": "No hay resultados para la consulta", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index e2b6eb7..0dca298 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -407,8 +407,6 @@ "@onOrder": {}, "onOrderDetails": "Articles en cours de commande", "@onOrderDetails": {}, - "outstandingOrderDetail": "Afficher les commandes en cours", - "@outstandingOrderDetail": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -531,8 +529,6 @@ "@quantityInvalid": {}, "quantityPositive": "La quantité doit être positive", "@quantityPositive": {}, - "quarantined": "En quarantaine", - "@quarantined": {}, "queryEmpty": "Entrer un critère de recherche", "@queryEmpty": {}, "queryNoResults": "Pas de résultat pour votre requête", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 3a51552..d262313 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -405,8 +405,6 @@ "@onOrderDetails": {}, "outstanding": "Kintlévő", "@outstanding": {}, - "outstandingOrderDetail": "Kintlévő rendelések megjelenítése", - "@outstandingOrderDetail": {}, "packaging": "Csomagolás", "@packaging": {}, "packageName": "Csomag neve", @@ -529,8 +527,6 @@ "@quantityInvalid": {}, "quantityPositive": "Mennyiség pozitív kell legyen", "@quantityPositive": {}, - "quarantined": "Karanténban", - "@quarantined": {}, "queryEmpty": "Add meg a keresési lekérdezést", "@queryEmpty": {}, "queryNoResults": "Nincs találat", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 6f57e55..6c50a36 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -513,8 +513,6 @@ "@quantityInvalid": {}, "quantityPositive": "La quantità deve essere positiva", "@quantityPositive": {}, - "quarantined": "In Quarantena", - "@quarantined": {}, "queryEmpty": "Inserisci ricerca", "@queryEmpty": {}, "queryNoResults": "Nessun risultato per la tua ricerca", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 04478ec..1afd385 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -511,8 +511,6 @@ "@quantityInvalid": {}, "quantityPositive": "Aantal moet positief zijn", "@quantityPositive": {}, - "quarantined": "In quarantaine geplaatst", - "@quarantined": {}, "queryEmpty": "Voer zoekterm in", "@queryEmpty": {}, "queryNoResults": "Geen resultaten", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 3c9740c..43d2408 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -186,6 +186,8 @@ }, "editItem": "Rediger lagervare", "@editItem": {}, + "editLineItem": "Rediger ordrelinje", + "@editLineItem": {}, "enterPassword": "Skriv inn passord", "@enterPassword": {}, "enterUsername": "Skriv inn brukernavn", @@ -250,7 +252,7 @@ "@filterVirtual": {}, "filterVirtualDetail": "Vis virtuelle deler", "@filterVirtualDetail": {}, - "filteringOptions": "Alternativer for filtrering", + "filteringOptions": "Filtreringsvalg", "@filteringOptions": {}, "formatException": "Formatunntak", "@formatException": {}, @@ -349,7 +351,7 @@ "@languageDefault": {}, "languageSelect": "Velg språk", "@languageSelect": {}, - "lastStocktake": "Siste Lagertelling", + "lastStocktake": "Siste lagertelling", "@lastStocktake": {}, "lastUpdated": "Sist oppdatert", "@lastUpdated": {}, @@ -359,6 +361,8 @@ "@lineItem": {}, "lineItems": "Ordrelinjer", "@lineItems": {}, + "lineItemUpdated": "Ordrelinje oppdatert", + "@lineItemUpdated": {}, "locateItem": "Finn lagervare", "@locateItem": {}, "locateLocation": "Finn lagerlokasjon", @@ -411,7 +415,7 @@ "@onOrderDetails": {}, "outstanding": "Utestående", "@outstanding": {}, - "outstandingOrderDetail": "Vis utestående ordre", + "outstandingOrderDetail": "Vis utestående artikler", "@outstandingOrderDetail": {}, "packaging": "Emballasje", "@packaging": {}, @@ -443,7 +447,7 @@ }, "partsNone": "Ingen deler", "@partsNone": {}, - "partNoResults": "Ingen deler samsvarer med spørring", + "partNoResults": "Ingen deler samsvarer med spørringen", "@partNoResults": {}, "partSettings": "Innstillinger for del", "@partSettings": {}, @@ -483,7 +487,7 @@ "@pluginPrinter": {}, "pluginSupport": "Utvidelsesstøtte aktivert", "@pluginSupport": {}, - "pluginSupportDetail": "Tjeneren støtter egendefinerte utvidelser", + "pluginSupportDetail": "Serveren støtter egendefinerte utvidelser", "@pluginSupportDetail": {}, "printLabelFailure": "Utskrift av etikett mislyktes", "@printLabelFailure": {}, @@ -511,6 +515,8 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Trykk for å opprette eller velge en profil", "@profileTapToCreate": {}, + "projectCode": "Prosjektkode", + "@projectCode": {}, "purchaseOrder": "Innkjøpsordre", "@purchaseOrder": {}, "purchaseOrderCreate": "Ny innkjøpsordre", @@ -535,14 +541,14 @@ "@quantityInvalid": {}, "quantityPositive": "Mengde må være positiv", "@quantityPositive": {}, - "quarantined": "I Karantene", - "@quarantined": {}, "queryEmpty": "Angi søkeord", "@queryEmpty": {}, "queryNoResults": "Ingen resultater for søk", "@queryNoResults": {}, "received": "Mottatt", "@received": {}, + "receivedFilterDetail": "Vis mottatte artikler", + "@receivedFilterDetail": {}, "receiveItem": "Motta artikkel", "@receiveItem": {}, "receivedItem": "Mottatt lagervare", @@ -641,7 +647,7 @@ "@searchLocation": {}, "searchParts": "Søk i deler", "@searchParts": {}, - "searchStock": "Søk i lagervarer", + "searchStock": "Søk i lagerbeholdning", "@searchStock": {}, "select": "Velg", "@select": {}, @@ -655,6 +661,8 @@ "@send": {}, "serialNumber": "Serienummer", "@serialNumber": {}, + "serialNumbers": "Serienummer", + "@serialNumbers": {}, "server": "Server", "@server": {}, "serverAddress": "Serveradresse", @@ -699,9 +707,9 @@ "@serverNotSelected": {}, "sounds": "Lyder", "@sounds": {}, - "soundOnBarcodeAction": "Spill akustisk tone ved strekkodehandling", + "soundOnBarcodeAction": "Spill hørbar tone ved strekkodehandling", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Spill akustisk tone ved serverfeil", + "soundOnServerError": "Spill hørbar tone ved serverfeil", "@soundOnServerError": {}, "status": "Status", "@status": {}, @@ -821,7 +829,7 @@ "@timeout": { "description": "" }, - "tokenError": "Token-lfeil", + "tokenError": "Token-feil", "@tokenError": {}, "tokenMissing": "Manglende token", "@tokenMissing": {}, @@ -847,6 +855,8 @@ "@translate": {}, "translateHelp": "Hjelp til med å oversette InvenTree-appen", "@translateHelp": {}, + "unitPrice": "Enhetspris", + "@unitPrice": {}, "units": "Enheter", "@units": {}, "unknownResponse": "Ukjent svar", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index b19e134..8e6b4c5 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -513,8 +513,6 @@ "@quantityInvalid": {}, "quantityPositive": "Quantidade precisa ser positiva", "@quantityPositive": {}, - "quarantined": "Quarantina", - "@quarantined": {}, "queryEmpty": "Entre dados para busca", "@queryEmpty": {}, "queryNoResults": "Nenhuma resultado para busca", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index b5d2a76..af53074 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -473,8 +473,6 @@ "@quantityInvalid": {}, "quantityPositive": "Adet pozitif bir sayı olmalı", "@quantityPositive": {}, - "quarantined": "Karantinaya alındı", - "@quarantined": {}, "queryEmpty": "Arama metni girin", "@queryEmpty": {}, "queryNoResults": "Sorgu için sonuç yok", From 49226a5fce1dbcc52ea92643bca520ce07ea0728 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 27 Apr 2023 19:09:19 +1000 Subject: [PATCH 360/746] New Crowdin updates (#343) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Italian) * New translations app_en.arb (Czech) * New translations app_en.arb (Vietnamese) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 14 ++++ lib/l10n/hu_HU/app_hu_HU.arb | 28 ++++++++ lib/l10n/it_IT/app_it_IT.arb | 20 ++++++ lib/l10n/no_NO/app_no_NO.arb | 74 +++++++++++---------- lib/l10n/vi_VN/app_vi_VN.arb | 120 +++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 34 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 8567644..cf7cb81 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -190,6 +190,8 @@ }, "editItem": "Upravit skladovou položku", "@editItem": {}, + "editLineItem": "Upravit položku", + "@editLineItem": {}, "enterPassword": "Zadejte heslo", "@enterPassword": {}, "enterUsername": "Zadejte uživatelské jméno", @@ -363,6 +365,8 @@ "@lineItem": {}, "lineItems": "Položky", "@lineItems": {}, + "lineItemUpdated": "Položka byla aktualizována", + "@lineItemUpdated": {}, "locateItem": "Najít skladovou položku", "@locateItem": {}, "locateLocation": "Najít skladové umístění", @@ -415,6 +419,8 @@ "@onOrderDetails": {}, "outstanding": "Nevyřízené", "@outstanding": {}, + "outstandingOrderDetail": "Zobrazit nevyřízené položky", + "@outstandingOrderDetail": {}, "packaging": "Balení", "@packaging": {}, "packageName": "Název balíčku", @@ -513,6 +519,8 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Klepnutím vytvoříte nebo vyberte profil", "@profileTapToCreate": {}, + "projectCode": "Kód projektu", + "@projectCode": {}, "purchaseOrder": "Objednávka", "@purchaseOrder": {}, "purchaseOrderCreate": "Nová objednávka", @@ -543,6 +551,8 @@ "@queryNoResults": {}, "received": "Přijato", "@received": {}, + "receivedFilterDetail": "Zobrazit přijaté položky", + "@receivedFilterDetail": {}, "receiveItem": "Přijaté položky", "@receiveItem": {}, "receivedItem": "Přijatá skladová položka", @@ -699,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server není vybrán", "@serverNotSelected": {}, + "sku": "Číslo zboží (SKU)", + "@sku": {}, "sounds": "Zvuky", "@sounds": {}, "soundOnBarcodeAction": "Přehrát zvuk při použití čárového kódu", @@ -849,6 +861,8 @@ "@translate": {}, "translateHelp": "Pomozte přeložit aplikaci InvenTree", "@translateHelp": {}, + "unitPrice": "Jednotková cena", + "@unitPrice": {}, "units": "Jednotky", "@units": {}, "unknownResponse": "Neznámá odpověď", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index d262313..924022c 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -146,6 +146,10 @@ "@customers": {}, "damaged": "Sérült", "@damaged": {}, + "darkMode": "Sötét mód", + "@darkMode": {}, + "darkModeEnable": "Sötét mód engedélyezése", + "@darkModeEnable": {}, "delete": "Törlés", "@delete": {}, "deleteFailed": "Törlés sikertelen", @@ -186,6 +190,8 @@ }, "editItem": "Készlet tétel szerkesztése", "@editItem": {}, + "editLineItem": "Sortétel szerkesztése", + "@editLineItem": {}, "enterPassword": "Jelszó megadása", "@enterPassword": {}, "enterUsername": "Felhasználó megadása", @@ -313,6 +319,8 @@ "@inProduction": {}, "inProductionDetail": "Ez a készlet tétel gyártásban van", "@inProductionDetail": {}, + "internalPart": "Belső alkatrész", + "@internalPart": {}, "invalidHost": "Érvénytelen hostnév", "@invalidHost": {}, "invalidHostDetails": "A megadott hostnév nem érvényes", @@ -357,6 +365,8 @@ "@lineItem": {}, "lineItems": "Sortételek", "@lineItems": {}, + "lineItemUpdated": "Sortétel módosítva", + "@lineItemUpdated": {}, "locateItem": "Készlet tétel keresése", "@locateItem": {}, "locateLocation": "Készlet hely keresése", @@ -373,6 +383,10 @@ "@link": {}, "lost": "Elveszett", "@lost": {}, + "manufacturerPartNumber": "Gyártói cikkszám", + "@manufacturerPartNumber": {}, + "manufacturer": "Gyártó", + "@manufacturer": {}, "manufacturers": "Gyártók", "@manufacturers": {}, "missingData": "Hiányzó adatok", @@ -405,6 +419,8 @@ "@onOrderDetails": {}, "outstanding": "Kintlévő", "@outstanding": {}, + "outstandingOrderDetail": "Hiányzó tételek megjelenítése", + "@outstandingOrderDetail": {}, "packaging": "Csomagolás", "@packaging": {}, "packageName": "Csomag neve", @@ -503,6 +519,8 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Koppints a profil létrehozásához vagy kiválasztásához", "@profileTapToCreate": {}, + "projectCode": "Projektszám", + "@projectCode": {}, "purchaseOrder": "Beszerzési rendelés", "@purchaseOrder": {}, "purchaseOrderCreate": "Új beszerzési rendelés", @@ -533,6 +551,8 @@ "@queryNoResults": {}, "received": "Beérkezett", "@received": {}, + "receivedFilterDetail": "Beérkezett készlet megjelenítése", + "@receivedFilterDetail": {}, "receiveItem": "Bevételezés", "@receiveItem": {}, "receivedItem": "Beérkezett készlet", @@ -645,6 +665,8 @@ "@send": {}, "serialNumber": "Sorozatszám", "@serialNumber": {}, + "serialNumbers": "Sorozatszámok", + "@serialNumbers": {}, "server": "Kiszolgáló", "@server": {}, "serverAddress": "Kiszolgáló címe", @@ -687,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Hangok", "@sounds": {}, "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", @@ -771,6 +795,8 @@ "@supplierPart": {}, "supplierPartEdit": "Beszállítói alkatrész szerkesztése", "@supplierPartEdit": {}, + "supplierPartNumber": "Beszállítói cikkszám", + "@supplierPartNumber": {}, "supplierPartUpdated": "Beszállítói alkatrész frissítve", "@supplierPartUpdated": {}, "supplierParts": "Beszállítói alkatrészek", @@ -835,6 +861,8 @@ "@translate": {}, "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", "@translateHelp": {}, + "unitPrice": "Egységár", + "@unitPrice": {}, "units": "Mértékegységek", "@units": {}, "unknownResponse": "Ismeretlen válasz", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 6c50a36..703ae7c 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -108,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Annulla Ordine", + "@cancelOrder": {}, "category": "Categoria", "@category": {}, "categoryCreate": "Nuova categoria", @@ -144,6 +146,10 @@ "@customers": {}, "damaged": "Danneggiato", "@damaged": {}, + "darkMode": "Modalità Scura", + "@darkMode": {}, + "darkModeEnable": "Abilita modalità scura", + "@darkModeEnable": {}, "delete": "Cancella", "@delete": {}, "deleteFailed": "Operazione di eliminazione fallita", @@ -184,6 +190,8 @@ }, "editItem": "Modifica elementi magazzino", "@editItem": {}, + "editLineItem": "Modifica linea elemento", + "@editLineItem": {}, "enterPassword": "Inserire la password", "@enterPassword": {}, "enterUsername": "Inserisci nome utente", @@ -200,6 +208,10 @@ "@errorDetails": {}, "errorFetch": "Si è verificato un errore durante il recupero dei dati dal server", "@errorFetch": {}, + "errorUserRoles": "Errore nella richiesta dei ruoli utente dal server", + "@errorUserRoles": {}, + "errorPluginInfo": "Errore nella richiesta dei dati dei plugin dal server", + "@errorPluginInfo": {}, "errorReporting": "Segnalazione Errori", "@errorReporting": {}, "errorReportUpload": "Carica i Report degli Errori", @@ -307,6 +319,8 @@ "@inProduction": {}, "inProductionDetail": "Questo elemento del magazzino è in produzione", "@inProductionDetail": {}, + "internalPart": "Articolo interno", + "@internalPart": {}, "invalidHost": "Nome host non valido", "@invalidHost": {}, "invalidHostDetails": "Il nome host fornito non è valido", @@ -323,8 +337,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinazione nome utente e password non valida", "@invalidUsernamePassword": {}, + "issue": "Problema", + "@issue": {}, "issueDate": "Data di emissione", "@issueDate": {}, + "issueOrder": "Problema nell'ordine", + "@issueOrder": {}, "itemInLocation": "Elemento già in posizione", "@itemInLocation": {}, "keywords": "Parole Chiave", @@ -347,6 +365,8 @@ "@lineItem": {}, "lineItems": "Elementi riga", "@lineItems": {}, + "lineItemUpdated": "Articolo modificato", + "@lineItemUpdated": {}, "locateItem": "Individua elemento di magazzino", "@locateItem": {}, "locateLocation": "Individua ubicazione di magazzino", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 43d2408..a6970cb 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -76,11 +76,11 @@ "@barcodeScanAssign": {}, "barcodeScanGeneral": "Skann en InvenTree-strekkode", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Skann lagervarer til denne lokasjonen", + "barcodeScanInItems": "Skann lagervarer til denne plasseringen", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Skann lagerlokasjon", + "barcodeScanLocation": "Skann lagerplassering", "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Skannet til lokasjon", + "barcodeScanIntoLocationSuccess": "Skannet til plassering", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artikkelen ble ikke skannet inn", "@barcodeScanIntoLocationFailure": {}, @@ -100,6 +100,10 @@ "@bom": {}, "bomEnable": "Vis stykkliste", "@bomEnable": {}, + "build": "Produksjon", + "@build": {}, + "building": "Produserer", + "@building": {}, "cancel": "Avbryt", "@cancel": { "description": "Cancel" @@ -114,15 +118,15 @@ "@categoryCreateDetail": {}, "categoryUpdated": "Del-kategori oppdatert", "@categoryUpdated": {}, - "company": "Bedrift", + "company": "Firma", "@company": {}, - "companyEdit": "Rediger bedrift", + "companyEdit": "Rediger Firma", "@companyEdit": {}, - "companyNoResults": "Ingen bedrifter samsvarer spørringen", + "companyNoResults": "Ingen firma samsvarer med søket", "@companyNoResults": {}, - "companyUpdated": "Bedriftsinformasjon oppdatert", + "companyUpdated": "Firmadetaljer oppdatert", "@companyUpdated": {}, - "companies": "Bedrifter", + "companies": "Firma", "@companies": {}, "configureServer": "Konfigurer serverinnstillinger", "@configureServer": {}, @@ -176,7 +180,7 @@ }, "editCategory": "Rediger kategori", "@editCategory": {}, - "editLocation": "Rediger lokasjon", + "editLocation": "Rediger plassering", "@editLocation": {}, "editNotes": "Rediger notater", "@editNotes": {}, @@ -301,9 +305,9 @@ "@includeSubcategories": {}, "includeSubcategoriesDetail": "Vis resultater fra underkategorier", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Inkluder underlokasjoner", + "includeSublocations": "Inkluder underplasseringer", "@includeSublocations": {}, - "includeSublocationsDetail": "Vis resulateter fra underlokasjoner", + "includeSublocationsDetail": "Vis resulateter fra underplasseringer", "@includeSublocationsDetail": {}, "incompleteDetails": "Ufullstendige profildetaljer", "@incompleteDetails": {}, @@ -325,7 +329,7 @@ "@invalidPart": {}, "invalidPartCategory": "Ugyldig delkategori", "@invalidPartCategory": {}, - "invalidStockLocation": "Ugyldig lagerlokasjon", + "invalidStockLocation": "Ugyldig lagerplassering", "@invalidStockLocation": {}, "invalidStockItem": "Ugyldig lagervare", "@invalidStockItem": {}, @@ -339,7 +343,7 @@ "@issueDate": {}, "issueOrder": "Send ordre", "@issueOrder": {}, - "itemInLocation": "Artikkelen er allerede i lokasjonen", + "itemInLocation": "Artikkelen er allerede i plasseringen", "@itemInLocation": {}, "keywords": "Nøkkelord", "@keywords": {}, @@ -365,15 +369,15 @@ "@lineItemUpdated": {}, "locateItem": "Finn lagervare", "@locateItem": {}, - "locateLocation": "Finn lagerlokasjon", + "locateLocation": "Finn lagerplassering", "@locateLocation": {}, - "locationCreate": "Ny lokasjon", + "locationCreate": "Ny plassering", "@locationCreate": {}, - "locationCreateDetail": "Opprett ny lagerlokasjon", + "locationCreateDetail": "Opprett ny lagerplassering", "@locationCreateDetail": {}, - "locationNotSet": "Ingen lokasjon spesifisert", + "locationNotSet": "Ingen plassering spesifisert", "@locationNotSet": {}, - "locationUpdated": "Lagerlokasjon oppdatert", + "locationUpdated": "Lagerplassering oppdatert", "@locationUpdated": {}, "link": "Lenke", "@link": {}, @@ -429,7 +433,7 @@ "@parent": {}, "parentCategory": "Overordnet kategori", "@parentCategory": {}, - "parentLocation": "Overordnet lokasjon", + "parentLocation": "Overordnet plassering", "@parentLocation": {}, "part": "Del", "@part": { @@ -633,9 +637,9 @@ }, "scanBarcode": "Skann strekkode", "@scanBarcode": {}, - "scanIntoLocation": "Skann til lokasjon", + "scanIntoLocation": "Skann til plassering", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Skann denne artikkelen til lokasjon", + "scanIntoLocationDetail": "Skann artikkelen til plassering", "@scanIntoLocationDetail": {}, "search": "Søk", "@search": { @@ -643,7 +647,7 @@ }, "searching": "Søker", "@searching": {}, - "searchLocation": "Søk etter lokasjon", + "searchLocation": "Søk etter plassering", "@searchLocation": {}, "searchParts": "Søk i deler", "@searchParts": {}, @@ -655,7 +659,7 @@ "@selectFile": {}, "selectImage": "Velg bilde", "@selectImage": {}, - "selectLocation": "Velg en lokasjon", + "selectLocation": "Velg en plassering", "@selectLocation": {}, "send": "Send", "@send": {}, @@ -705,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, + "sku": "SKU-kode", + "@sku": {}, "sounds": "Lyder", "@sounds": {}, "soundOnBarcodeAction": "Spill hørbar tone ved strekkodehandling", @@ -729,7 +735,7 @@ "@stockItems": {}, "stockItemCreate": "Ny lagervare", "@stockItemCreate": {}, - "stockItemCreateDetail": "Opprett ny lagervare på denne lokasjonen", + "stockItemCreateDetail": "Opprett ny lagervare på denne plasseringen", "@stockItemCreateDetail": {}, "stockItemDelete": "Slett lagervare", "@stockItemDelete": {}, @@ -755,13 +761,13 @@ "@stockItemUpdateSuccess": {}, "stockItemUpdateFailure": "Oppdatering av lagervare feilet", "@stockItemUpdateFailure": {}, - "stockLocation": "Lagerlokasjon", + "stockLocation": "Lagerplassering", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Lagerlokasjoner", + "stockLocations": "Lagerplasseringer", "@stockLocations": {}, - "stockTopLevel": "Toppnivå lagerlokasjon", + "stockTopLevel": "Toppnivå-lagerplassering", "@stockTopLevel": {}, "strictHttps": "Bruk streng HTTPS", "@strictHttps": {}, @@ -771,13 +777,13 @@ "@subcategory": {}, "subcategories": "Underkategorier", "@subcategories": {}, - "sublocation": "Underlokasjon", + "sublocation": "Underplassering", "@sublocation": {}, - "sublocations": "Underlokasjoner", + "sublocations": "Underplasseringer", "@sublocations": {}, - "sublocationNone": "Ingen underlokasjoner", + "sublocationNone": "Ingen underplasseringer", "@sublocationNone": {}, - "sublocationNoneDetail": "Ingen underlokasjoner tilgjengelig", + "sublocationNoneDetail": "Ingen underplasseringer tilgjengelig", "@sublocationNoneDetail": {}, "submitFeedback": "Send tilbakemelding", "@submitFeedback": {}, @@ -845,11 +851,11 @@ "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Overfør artikkelen til en annen lokasjon", + "transferStockDetail": "Overfør artikkelen til en annen plassering", "@transferStockDetail": {}, - "transferStockLocation": "Overfør lagerlokasjon", + "transferStockLocation": "Overfør lagerplassering", "@transferStockLocation": {}, - "transferStockLocationDetail": "Overfør denne lagerlokasjonen til en annen", + "transferStockLocationDetail": "Overfør denne lagerplasseringen til en annen", "@transferStockLocationDetail": {}, "translate": "Oversett", "@translate": {}, diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index c82145e..2a15835 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -1,5 +1,125 @@ { "@@locale": "vi", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "Đồng Ý", + "@ok": { + "description": "OK" + }, + "about": "Giới thiệu", + "@about": {}, + "accountDetails": "Thông tin tài khoản", + "@accountDetails": {}, + "actions": "Hành động", + "@actions": { + "description": "" + }, + "actionsNone": "Không có thao tác nào khả dụng", + "@actionsNone": {}, + "add": "Thêm", + "@add": { + "description": "add" + }, + "addStock": "Thêm tồn kho", + "@addStock": { + "description": "add stock" + }, + "address": "Địa chỉ", + "@address": {}, + "appAbout": "Giới thiệu", + "@appAbout": {}, + "appCredits": "Tín dụng bổ sung", + "@appCredits": {}, + "appDetails": "Chi tiết về ứng dụng", + "@appDetails": {}, + "appReleaseNotes": "Hiển thị ghi chú phát hành ứng dụng", + "@appReleaseNotes": {}, + "appSettings": "Cài đặt ứng dụng", + "@appSettings": {}, + "appSettingsDetails": "Cấu hình cài đặt ứng dụng", + "@appSettingsDetails": {}, + "attachments": "Tập tin đính kèm", + "@attachments": {}, + "attachImage": "Hình ảnh đính kèm", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Không tìm thấy tệp đính kèm", + "@attachmentNone": {}, + "attachmentNoneDetail": "Không tìm thấy tệp đính kèm", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Chọn tài liệu đính kèm", + "@attachmentSelect": {}, + "attention": "Chú ý", + "@attention": {}, + "availableStock": "Số lượng có sẵn", + "@availableStock": {}, + "barcodeAssign": "Gán mã vạch", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Quét mã vạch tùy chỉnh để gán", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Mã vạch đã được gán", + "@barcodeAssigned": {}, + "barcodeError": "Lỗi quét mã vạch", + "@barcodeError": {}, + "barcodeInUse": "Mã vạch đã được dùng", + "@barcodeInUse": {}, + "barcodeMissingHash": "Dữ liệu băm mã vạch bị thiếu trong phản hồi", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Không khớp với mã vạch", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Mã vạch chưa được quét", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Quét để gán mã vạch", + "@barcodeScanAssign": {}, + "barcodeScanGeneral": "Quét mã vạch InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Quét các mặt hàng trong kho vào vị trí này", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Quét vị trí kho hàng", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Đã quét vào vị trí", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item không được quét vào", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Quét mặt hàng tồn kho", + "@barcodeScanItem": {}, + "barcodeUnassign": "Gỡ mã vạch", + "@barcodeUnassign": {}, + "barcodeUnknown": "Mã vạch không xác định", + "@barcodeUnknown": {}, + "batchCode": "Mã lô hàng", + "@batchCode": {}, + "billOfMaterials": "Bảng kê chi tiết", + "@billOfMaterials": {}, + "bom": "Bảng kê chi tiết", + "@bom": {}, + "bomEnable": "Hiển thị hóa đơn vật liệu", + "@bomEnable": {}, + "build": "Nhiệm vụ", + "@build": {}, + "cancel": "Hủy bỏ", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Hủy đơn hàng", + "@cancelOrder": {}, + "category": "Thể loại", + "@category": {}, + "categoryCreate": "Danh mục mới", + "@categoryCreate": {}, + "categoryCreateDetail": "Thêm danh mục mới", + "@categoryCreateDetail": {}, + "categoryUpdated": "Danh mục đã được cập nhật", + "@categoryUpdated": {}, + "company": "Công ty", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "Không có công ty phù hợp", + "@companyNoResults": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "parameters": "Thông số", From 383571707ef9a66cda122cd1f6193da16a38c2ce Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 28 Apr 2023 23:27:59 +1000 Subject: [PATCH 361/746] Stock test actions (#345) * Use FAB for stock item test result * Change long press to tap * Add setting to control display of stock tests results * Add question mark if no result recorded --- assets/release_notes.md | 1 + lib/inventree/stock.dart | 3 ++ lib/l10n/app_en.arb | 3 ++ lib/preferences.dart | 1 + lib/settings/part_settings.dart | 16 ++++++ lib/widget/stock_detail.dart | 24 +++++---- lib/widget/stock_item_test_results.dart | 66 +++++++++++++++---------- 7 files changed, 80 insertions(+), 34 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 39384b7..5db870c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ - Add support for Project Codes - Improve purchase order support - Fix action button colors +- Improvements for stock item test result display - Added Norwegian translations - Fix serial number field when creating stock item diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 4a02617..da79778 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -11,6 +11,9 @@ import "package:inventree/inventree/model.dart"; +/* + * Class representing a test result for a single stock item + */ class InvenTreeStockItemTestResult extends InvenTreeModel { InvenTreeStockItemTestResult() : super(); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 89edcc9..dcb9c02 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1208,6 +1208,9 @@ "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", "@testResultAdd": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index d427392..fc08450 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -24,6 +24,7 @@ const String INV_PART_SHOW_BOM = "partShowBom"; // Stock settings const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; +const String INV_STOCK_SHOW_TESTS = "stockShowTests"; const String INV_REPORT_ERRORS = "reportErrors"; const String INV_STRICT_HTTPS = "strictHttps"; diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 50d3f0d..79b0929 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -18,6 +18,7 @@ class _InvenTreePartSettingsState extends State { bool partShowParameters = true; bool partShowBom = true; bool stockShowHistory = false; + bool stockShowTests = false; @override void initState() { @@ -30,6 +31,7 @@ class _InvenTreePartSettingsState extends State { partShowParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; partShowBom = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_BOM, true) as bool; stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; + stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; if (mounted) { setState(() { @@ -86,6 +88,20 @@ class _InvenTreePartSettingsState extends State { }, ), ), + ListTile( + title: Text(L10().testResults), + subtitle: Text(L10().testResultsDetail), + leading: FaIcon(FontAwesomeIcons.vial), + trailing: Switch( + value: stockShowTests, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_STOCK_SHOW_TESTS, value); + setState(() { + stockShowTests = value; + }); + }, + ), + ) ] ) ) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 7dc3c11..cb65679 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -47,6 +47,7 @@ class _StockItemDisplayState extends RefreshableState { String getAppBarTitle() => L10().stockItem; bool stockShowHistory = false; + bool stockShowTests = true; @override List appBarActions(BuildContext context) { @@ -214,6 +215,7 @@ class _StockItemDisplayState extends RefreshableState { await api.StockStatus.load(); stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; + stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; final bool result = widget.item.pk > 0 && await widget.item.reload(); @@ -226,15 +228,19 @@ class _StockItemDisplayState extends RefreshableState { // Request part information part = await InvenTreePart().get(widget.item.partId) as InvenTreePart?; - // Request test results (async) - widget.item.getTestResults().then((value) { + stockShowTests &= part?.isTrackable ?? false; - if (mounted) { - setState(() { - // Update - }); - } - }); + // Request test results (async) + if (stockShowTests) { + widget.item.getTestResults().then((value) { + + if (mounted) { + setState(() { + // Update + }); + } + }); + } // Request the number of attachments InvenTreeStockItemAttachment().count( @@ -753,7 +759,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - if ((widget.item.testResultCount > 0) || (part?.isTrackable ?? false)) { + if (stockShowTests || (widget.item.testResultCount > 0)) { tiles.add( ListTile( title: Text(L10().testResults), diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index b89a01b..b6315d9 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -1,15 +1,17 @@ +import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/l10.dart"; + import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/model.dart"; -import "package:inventree/api.dart"; + import "package:inventree/widget/progress.dart"; - -import "package:inventree/l10.dart"; - -import "package:flutter/material.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; class StockItemTestResultsWidget extends StatefulWidget { @@ -31,15 +33,25 @@ class _StockItemTestResultDisplayState extends RefreshableState L10().testResults; @override - List appBarActions(BuildContext context) { - return [ - IconButton( - icon: FaIcon(FontAwesomeIcons.circlePlus), - onPressed: () { - addTestResult(context); + List appBarActions(BuildContext context) => []; + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreeStockItemTestResult().canCreate) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus), + label: L10().testResultAdd, + onTap: () { + addTestResult(context); } - ), - ]; + ) + ); + } + + return actions; } @override @@ -153,6 +165,7 @@ class _StockItemTestResultDisplayState extends RefreshableState Date: Sat, 29 Apr 2023 20:06:35 +1000 Subject: [PATCH 362/746] New translations app_en.arb (Portuguese, Brazilian) (#346) --- lib/l10n/pt_BR/app_pt_BR.arb | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 8e6b4c5..86eaa1c 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -108,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancelar Pedido", + "@cancelOrder": {}, "category": "Categoria", "@category": {}, "categoryCreate": "Nova categoria", @@ -144,6 +146,10 @@ "@customers": {}, "damaged": "Danificado", "@damaged": {}, + "darkMode": "Modo Escuro", + "@darkMode": {}, + "darkModeEnable": "Habilitar o modo escuro", + "@darkModeEnable": {}, "delete": "Deletar", "@delete": {}, "deleteFailed": "A operação de apagar falhou", @@ -184,6 +190,8 @@ }, "editItem": "Editar Item do Estoque", "@editItem": {}, + "editLineItem": "Editar Item de Linha", + "@editLineItem": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, "enterUsername": "Informe o usuário", @@ -200,6 +208,10 @@ "@errorDetails": {}, "errorFetch": "Erro ao buscar dados do servidor", "@errorFetch": {}, + "errorUserRoles": "Erro ao solicitar funções de usuário do servidor", + "@errorUserRoles": {}, + "errorPluginInfo": "Erro ao solicitar dados da extensão do servidor", + "@errorPluginInfo": {}, "errorReporting": "Relatório de erros", "@errorReporting": {}, "errorReportUpload": "Enviar relatório de erros", @@ -307,6 +319,8 @@ "@inProduction": {}, "inProductionDetail": "Este item esta em producao", "@inProductionDetail": {}, + "internalPart": "Peça Interna", + "@internalPart": {}, "invalidHost": "Hostname invalido", "@invalidHost": {}, "invalidHostDetails": "Hostname invalido", @@ -323,8 +337,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Usuario ou senha invalidos", "@invalidUsernamePassword": {}, + "issue": "Emitir", + "@issue": {}, "issueDate": "Data de emissao", "@issueDate": {}, + "issueOrder": "Emitir Pedido", + "@issueOrder": {}, "itemInLocation": "Item ja na localizacao", "@itemInLocation": {}, "keywords": "Palavras chave", @@ -347,6 +365,8 @@ "@lineItem": {}, "lineItems": "Linhas do item", "@lineItems": {}, + "lineItemUpdated": "Item de linha atualizado", + "@lineItemUpdated": {}, "locateItem": "Localizar produto no estoque", "@locateItem": {}, "locateLocation": "Localizar no estoque", @@ -363,6 +383,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPartNumber": "Número de Peça do Fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, "manufacturers": "Fabricantes", "@manufacturers": {}, "missingData": "Dados indisponiveis", @@ -393,6 +417,10 @@ "@onOrder": {}, "onOrderDetails": "Itens atualmente com pedidos feitos", "@onOrderDetails": {}, + "outstanding": "Pendente", + "@outstanding": {}, + "outstandingOrderDetail": "Mostrar itens pendentes", + "@outstandingOrderDetail": {}, "packaging": "Embalagem", "@packaging": {}, "packageName": "Nome do pacote", @@ -491,8 +519,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Clique para criar ou selecionar o perfil", "@profileTapToCreate": {}, + "projectCode": "Código do projeto", + "@projectCode": {}, "purchaseOrder": "Ordem de Compra", "@purchaseOrder": {}, + "purchaseOrderCreate": "Novo Pedido de Compra", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Editar ordem de compra", "@purchaseOrderEdit": {}, "purchaseOrders": "Ordens de compras", @@ -519,6 +551,8 @@ "@queryNoResults": {}, "received": "Recebido", "@received": {}, + "receivedFilterDetail": "Mostrar itens recebidos", + "@receivedFilterDetail": {}, "receiveItem": "Item recebido", "@receiveItem": {}, "receivedItem": "Item de estoque recebido", @@ -631,6 +665,8 @@ "@send": {}, "serialNumber": "Número de Série", "@serialNumber": {}, + "serialNumbers": "Números de Série", + "@serialNumbers": {}, "server": "Servidor", "@server": {}, "serverAddress": "Endereço do servidor", @@ -673,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor não selecionado", "@serverNotSelected": {}, + "sku": "Código (SKU)", + "@sku": {}, "sounds": "Sons", "@sounds": {}, "soundOnBarcodeAction": "Tocar tom audível na ação do código de barras", @@ -757,6 +795,8 @@ "@supplierPart": {}, "supplierPartEdit": "Editar Fornecedor da Peça", "@supplierPartEdit": {}, + "supplierPartNumber": "Número da Peça do Fornecedor", + "@supplierPartNumber": {}, "supplierPartUpdated": "Fornecedor da Peça Atualizado", "@supplierPartUpdated": {}, "supplierParts": "Peças do Fornecedor", @@ -821,6 +861,8 @@ "@translate": {}, "translateHelp": "Ajude a traduzir", "@translateHelp": {}, + "unitPrice": "Preço unitário", + "@unitPrice": {}, "units": "Unidades", "@units": {}, "unknownResponse": "Reposta invalida", From 4ba19fcab2e246699359c33a1eb30dec0b63f098 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 29 Apr 2023 21:06:12 +1000 Subject: [PATCH 363/746] Increment to 0.12.0 (#347) --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 5db870c..0b92718 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,4 +1,4 @@ -### 0.11.6 - April 2023 +### 0.12.0 - April 2023 --- - Add support for Project Codes diff --git a/pubspec.yaml b/pubspec.yaml index 8e49145..bb473a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.11.6+65 +version: 0.12.0+66 environment: sdk: ">=2.16.0 <3.0.0" From 0296c4c22ac128e3be8ea0cb5cf7e3518225474e Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 30 Apr 2023 21:52:32 +1000 Subject: [PATCH 364/746] Ios build (#348) * Update package versions * Update xcode project * Further package updates --- ios/Runner.xcodeproj/project.pbxproj | 2 ++ pubspec.lock | 48 ++++++++++++++-------------- pubspec.yaml | 20 ++++++------ 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b35a1ca..7c4fdbc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -277,6 +277,7 @@ "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", + "${BUILT_PRODUCTS_DIR}/SentryPrivate/SentryPrivate.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/audioplayers_darwin/audioplayers_darwin.framework", "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", @@ -300,6 +301,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SentryPrivate.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers_darwin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", diff --git a/pubspec.lock b/pubspec.lock index ac1db99..d890c9e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -285,10 +285,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "7ff671ed0a6356fa8f2e1ae7d3558d3fb7b6a41e24455e4f8df75b811fb8e4ab" + sha256: f52ab3b76b36ede4d135aab80194df8925b553686f0fa12226b4e2d658e45903 url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "8.2.2" device_info_plus_platform_interface: dependency: transitive description: @@ -301,10 +301,10 @@ packages: dependency: "direct main" description: name: dropdown_search - sha256: "8862928805520ea7fdf60fee64195a2d460f4bf5ccf224c016c773a873756c5e" + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "5.0.6" fake_async: dependency: transitive description: @@ -333,10 +333,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 + sha256: e6c7ad8e572379df86ea64ef0a5395889fba3954411d47ca021b888d79f8e798 url: "https://pub.dev" source: hosted - version: "5.2.5" + version: "5.2.11" flutter: dependency: "direct main" description: flutter @@ -399,10 +399,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + sha256: "8ffe990dac54a4a5492747added38571a5ab474c8e5d196809ea08849c69b1bb" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.13" flutter_speed_dial: dependency: "direct main" description: @@ -481,10 +481,10 @@ packages: dependency: "direct main" description: name: image_picker - sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe + sha256: "3da954c3b8906d82ecb50fd5e2b5401758f06d5678904eed6cbc06172283a263" url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.7+4" image_picker_android: dependency: transitive description: @@ -657,10 +657,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: f619162573096d428ccde2e33f92e05b5a179cd6f0e3120c1005f181bee8ed16 + sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.2" package_info_plus_platform_interface: dependency: transitive description: @@ -721,10 +721,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.6" pedantic: dependency: transitive description: @@ -753,10 +753,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pointycastle: dependency: transitive description: @@ -825,18 +825,18 @@ packages: dependency: transitive description: name: sentry - sha256: c64db3444237ff747c5a68f5214897bcb078de248785d0d816e3c55ab94dd71d + sha256: cce8f5d696c7083e6915477b455de2134b689aff69bc31249844646f91a52ac7 url: "https://pub.dev" source: hosted - version: "6.19.0" + version: "7.5.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: a76cf5180d571535fb8fc3bf10358ab385d78134fcf652d0e03ba7741525ab09 + sha256: a772ad8abafdcf4ac04568bf3469cc541761412fd664a7aa99d9578fd0933a09 url: "https://pub.dev" source: hosted - version: "6.19.0" + version: "7.5.0" shared_preferences: dependency: transitive description: @@ -1070,10 +1070,10 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e8f2efc804810c0f2f5b485f49e7942179f56eabcfe81dce3387fec4bb55876b + sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" url: "https://pub.dev" source: hosted - version: "6.1.9" + version: "6.1.10" url_launcher_android: dependency: transitive description: @@ -1182,10 +1182,10 @@ packages: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: dd8f9344bc305ae2923e3d11a2a911d9a4e2c7dd6fe0ed10626d63211a69676e url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "4.1.3" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bb473a5..ac140a6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,14 +9,14 @@ environment: dependencies: adaptive_theme: ^3.2.0 # Theme management (e.g. dark mode) audioplayers: ^3.0.1 # Play audio files - cached_network_image: ^3.2.0 # Download and cache remote images + cached_network_image: ^3.2.3 # Download and cache remote images camera: ^0.10.3 # Camera cupertino_icons: ^1.0.3 currency_formatter: ^2.0.0 - datetime_picker_formfield: ^2.0.0 # Date / time picker - device_info_plus: ^8.0.0 # Information about the device - dropdown_search: ^5.0.5 # Dropdown autocomplete form fields - file_picker: ^5.2.5 # Select files from the device + datetime_picker_formfield: ^2.0.1 # Date / time picker + device_info_plus: ^8.2.2 # Information about the device + dropdown_search: ^5.0.6 # Dropdown autocomplete form fields + file_picker: ^5.2.11 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 @@ -27,9 +27,9 @@ dependencies: flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation font_awesome_flutter: ^10.3.0 # FontAwesome icon set - http: ^0.13.4 - image_picker: ^0.8.6+1 # Select or take photos - infinite_scroll_pagination: ^3.1.0 # Let the server do all the work! + http: ^0.13.5 + image_picker: ^0.8.7+4 # Select or take photos + infinite_scroll_pagination: ^3.2.0 # Let the server do all the work! intl: ^0.17.0 one_context: ^2.1.0 # Dialogs without requiring context open_filex: ^4.3.2 # Open local files @@ -38,8 +38,8 @@ dependencies: path_provider: ^2.0.12 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning sembast: ^3.4.0+6 # NoSQL data storage - sentry_flutter: ^6.19.0 # Error reporting - url_launcher: ^6.1.9 # Open link in system browser + sentry_flutter: ^7.5.0 # Error reporting + url_launcher: ^6.1.10 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.11.0 From 230627e2bb76997de6c2699278c579c29e02c751 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 1 May 2023 09:35:23 +1000 Subject: [PATCH 365/746] iOS Build Tweaks (#349) * Update package versions * Update xcode project * Further package updates * Add display name for ios --- ios/Runner.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7c4fdbc..d46f76c 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -419,6 +419,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -550,6 +551,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -581,6 +583,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", From 905cedf9aff4584841608b653fca8e33d9cab25a Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 13 May 2023 20:48:38 +1000 Subject: [PATCH 366/746] New Crowdin updates (#350) * New translations app_en.arb (Czech) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Spanish, Mexico) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 ++ lib/l10n/es_MX/app_es_MX.arb | 56 ++++++++++++++++++++++++++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ lib/l10n/vi_VN/app_vi_VN.arb | 62 ++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index cf7cb81..a95a56e 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -821,6 +821,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Zobrazit výsledky testu skladových položek", + "@testResultsDetail": {}, "testResultAdd": "Přidat výsledek testu", "@testResultAdd": {}, "testResultNone": "Žádné výsledky testu", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 3fce6a2..a45a991 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -108,6 +108,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancelar orden", + "@cancelOrder": {}, "category": "Categoria", "@category": {}, "categoryCreate": "Nueva Categoría", @@ -144,6 +146,10 @@ "@customers": {}, "damaged": "Dañado", "@damaged": {}, + "darkMode": "Modo Oscuro", + "@darkMode": {}, + "darkModeEnable": "Habilitar modo oscuro", + "@darkModeEnable": {}, "delete": "Eliminar", "@delete": {}, "deleteFailed": "Operación de borrado fallida", @@ -184,6 +190,8 @@ }, "editItem": "Editar artículo de stock", "@editItem": {}, + "editLineItem": "Editar artículo de línea", + "@editLineItem": {}, "enterPassword": "Introducir contraseña", "@enterPassword": {}, "enterUsername": "Introducir usuario", @@ -200,6 +208,10 @@ "@errorDetails": {}, "errorFetch": "Error obteniendo datos del servidor", "@errorFetch": {}, + "errorUserRoles": "Error al solicitar roles de usuario del servidor", + "@errorUserRoles": {}, + "errorPluginInfo": "Error al solicitar datos del complemento del servidor", + "@errorPluginInfo": {}, "errorReporting": "Informe de errores", "@errorReporting": {}, "errorReportUpload": "Subir informe de errores", @@ -307,6 +319,8 @@ "@inProduction": {}, "inProductionDetail": "El artículo de inventario está en producción", "@inProductionDetail": {}, + "internalPart": "Componente interno", + "@internalPart": {}, "invalidHost": "Nombre de host no válido", "@invalidHost": {}, "invalidHostDetails": "Este nombre de host no es válido", @@ -323,8 +337,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación inválida de usuario/contraseña", "@invalidUsernamePassword": {}, + "issue": "Emitir", + "@issue": {}, "issueDate": "Fecha de emisión", "@issueDate": {}, + "issueOrder": "Emitir pedido", + "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, "keywords": "Palabras claves", @@ -345,6 +363,10 @@ "@level": {}, "lineItem": "Artículo del pedido", "@lineItem": {}, + "lineItems": "Artículos de Línea", + "@lineItems": {}, + "lineItemUpdated": "Artículo de línea actualizado", + "@lineItemUpdated": {}, "locateItem": "Localizar artículo de inventario", "@locateItem": {}, "locateLocation": "Localizar ubicación de inventario", @@ -361,6 +383,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPartNumber": "Número de parte del fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, "manufacturers": "Fabricantes", "@manufacturers": {}, "missingData": "Datos faltantes", @@ -391,6 +417,10 @@ "@onOrder": {}, "onOrderDetails": "Artículos actualmente en pedido", "@onOrderDetails": {}, + "outstanding": "Pendiente", + "@outstanding": {}, + "outstandingOrderDetail": "Mostrar artículos pendientes", + "@outstandingOrderDetail": {}, "packaging": "Embalaje", "@packaging": {}, "packageName": "Nombre de Paquete", @@ -489,8 +519,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Toca para crear o seleccionar un perfil", "@profileTapToCreate": {}, + "projectCode": "Código del proyecto", + "@projectCode": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, + "purchaseOrderCreate": "Nueva orden de compra", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, "purchaseOrders": "Órdenes de compra", @@ -517,6 +551,8 @@ "@queryNoResults": {}, "received": "Recibido", "@received": {}, + "receivedFilterDetail": "Mostrar artículos recibidos", + "@receivedFilterDetail": {}, "receiveItem": "Recibir artículo", "@receiveItem": {}, "receivedItem": "Recibir artículo de inventario", @@ -629,6 +665,8 @@ "@send": {}, "serialNumber": "Número de serie", "@serialNumber": {}, + "serialNumbers": "Números de serie", + "@serialNumbers": {}, "server": "Servidor", "@server": {}, "serverAddress": "Dirección del servidor", @@ -671,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Sonidos", "@sounds": {}, "soundOnBarcodeAction": "Reproducir un tono audible en la acción de código de barras", @@ -751,6 +791,16 @@ "@suppliedParts": {}, "supplier": "Proveedor", "@supplier": {}, + "supplierPart": "Parte del proveedor", + "@supplierPart": {}, + "supplierPartEdit": "Editar parte del proveedor", + "@supplierPartEdit": {}, + "supplierPartNumber": "Número de parte del proveedor", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Parte del proveedor actualizada", + "@supplierPartUpdated": {}, + "supplierParts": "Partes de Proveedor", + "@supplierParts": {}, "suppliers": "Proveedores", "@suppliers": {}, "supplierReference": "Referencia del proveedor", @@ -771,6 +821,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Mostrar los resultados de prueba de artículos en stock", + "@testResultsDetail": {}, "testResultAdd": "Añadir Resultado de Prueba", "@testResultAdd": {}, "testResultNone": "No hay resultados de la prueba", @@ -791,6 +843,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Falta el token de acceso de la respuesta", "@tokenMissingFromResponse": {}, + "totalPrice": "Precio total", + "@totalPrice": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" @@ -809,6 +863,8 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, + "unitPrice": "Precio unitario", + "@unitPrice": {}, "units": "Unidades", "@units": {}, "unknownResponse": "Respuesta desconocida", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 86eaa1c..13a5516 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -821,6 +821,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Mostrar resultados do teste de item de estoque", + "@testResultsDetail": {}, "testResultAdd": "Adicionar resultado do test", "@testResultAdd": {}, "testResultNone": "Nenhum resultado do test", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 2a15835..802d954 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -120,8 +120,70 @@ "@companyEdit": {}, "companyNoResults": "Không có công ty phù hợp", "@companyNoResults": {}, + "companyUpdated": "Thông tin doanh nghiệp đã được cập nhật", + "@companyUpdated": {}, + "companies": "Doanh nghiệp", + "@companies": {}, + "configureServer": "Cấu hình thiết lập máy chủ", + "@configureServer": {}, + "connectionRefused": "Kết nối bị từ chối", + "@connectionRefused": {}, + "count": "Đếm", + "@count": { + "description": "Count" + }, + "countStock": "Kiểm kê", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Tín dụng", + "@credits": {}, + "customers": "Khách hàng", + "@customers": {}, + "damaged": "Bị hỏng", + "@damaged": {}, + "darkMode": "Chế độ tối", + "@darkMode": {}, + "darkModeEnable": "Bật Chế độ nền tối", + "@darkModeEnable": {}, + "delete": "Xóa", + "@delete": {}, + "deleteFailed": "Thao tác xóa đã thất bại", + "@deleteFailed": {}, + "description": "Mô tả", + "@description": {}, + "details": "Chi tiết", + "@details": { + "description": "details" + }, + "documentation": "Tài liệu", + "@documentation": {}, + "filterVirtual": "Ảo", + "@filterVirtual": {}, + "home": "Trang chủ", + "@homeScreen": {}, + "homeScreen": "Màn hình chính", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Hiện nhà cung cấp", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Hiện nút nhà cung cấp tại màn hình chính", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Hiện nhà sản xuất", + "@homeShowManufacturers": {}, + "homeShowCustomers": "Hiện khách hàng", + "@homeShowCustomers": {}, + "inactive": "Không hoạt động", + "@inactive": {}, + "keywords": "Từ khóa", + "@keywords": {}, + "language": "Ngôn ngữ", + "@language": {}, + "languageDefault": "Ngôn ngữ hệ thống mặc định", + "@languageDefault": {}, + "languageSelect": "Chọn ngôn ngữ", + "@languageSelect": {}, + "level": "Cấp độ", + "@level": {}, "parameters": "Thông số", "@parameters": {}, "parametersSettingDetail": "Hiển thị các thông số", From b733d00c374f1d90163d914c98555902f4f3d988 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 18 May 2023 20:55:50 +1000 Subject: [PATCH 367/746] Fix bug in purchase order form (#354) - Remove "project_code" field if the server API does not yet support it --- assets/release_notes.md | 4 ++++ lib/inventree/purchase_order.dart | 10 +++++++++- pubspec.yaml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 0b92718..10350fc 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,7 @@ +### 0.12.1 - May 2023 + +- Fixes bug in purchase order form + ### 0.12.0 - April 2023 --- diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 5a4ac72..199bc15 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,3 +1,4 @@ +import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; @@ -26,7 +27,7 @@ class InvenTreePurchaseOrder extends InvenTreeModel { @override Map formFields() { - return { + var fields = { "reference": {}, "supplier": { "filters": { @@ -45,6 +46,13 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } }, }; + + if (!InvenTreeAPI().supportsProjectCodes) { + fields.remove("project_code"); + } + + return fields; + } @override diff --git a/pubspec.yaml b/pubspec.yaml index ac140a6..d004089 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.0+66 +version: 0.12.1+67 environment: sdk: ">=2.16.0 <3.0.0" From 973f1fb0021c2b7345ad6a1d72778199fd948d84 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 30 May 2023 20:19:14 +1000 Subject: [PATCH 368/746] New translations app_en.arb (Finnish) (#357) --- lib/l10n/fi_FI/app_fi_FI.arb | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 lib/l10n/fi_FI/app_fi_FI.arb diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb new file mode 100644 index 0000000..58bc68a --- /dev/null +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -0,0 +1,57 @@ +{ + "@@locale": "fi", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "accountDetails": "Tilitiedot", + "@accountDetails": {}, + "address": "Osoite", + "@address": {}, + "attachImage": "Liitä kuva", + "@attachImage": { + "description": "Attach an image" + }, + "category": "Kategoria", + "@category": {}, + "categoryCreate": "Uusi kategoria", + "@categoryCreate": {}, + "configureServer": "Määritä palvelimen asetukset", + "@configureServer": {}, + "connectionRefused": "Yhteys kielletty", + "@connectionRefused": {}, + "damaged": "Vahingoittunut", + "@damaged": {}, + "darkMode": "Tumma tila", + "@darkMode": {}, + "delete": "Poista", + "@delete": {}, + "deletePart": "Poista osa", + "@deletePart": {}, + "deletePartDetail": "Poista tämä osa tietokannasta", + "@deletePartDetail": {}, + "edit": "Muokkaa", + "@edit": { + "description": "edit" + }, + "editCategory": "Muokkaa kategoriaa", + "@editCategory": {}, + "editLocation": "Muokkaa sijaintia", + "@editLocation": {}, + "editNotes": "Muokkaa merkintää", + "@editNotes": {}, + "editPart": "Muokkaa osaa", + "@editPart": { + "description": "edit part" + }, + "error": "Virhe", + "@error": { + "description": "Error" + }, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 7ca9a7ccc43f8e105bd591e2fe41b98cdf867826 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 6 Jun 2023 21:07:39 +1000 Subject: [PATCH 369/746] New Crowdin updates (#360) * New translations app_en.arb (Finnish) * New translations app_en.arb (Finnish) --- lib/l10n/fi_FI/app_fi_FI.arb | 387 ++++++++++++++++++++++++++++++++++- 1 file changed, 385 insertions(+), 2 deletions(-) diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 58bc68a..6c15c86 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -8,32 +8,102 @@ "@ok": { "description": "OK" }, + "about": "Tietoja", + "@about": {}, "accountDetails": "Tilitiedot", "@accountDetails": {}, + "actions": "Toiminnot", + "@actions": { + "description": "" + }, + "actionsNone": "Toimintoja ei saatavilla", + "@actionsNone": {}, + "add": "Lisää", + "@add": { + "description": "add" + }, + "addStock": "Lisää varastoon", + "@addStock": { + "description": "add stock" + }, "address": "Osoite", "@address": {}, + "appAbout": "Tietoja InvenTree:stä", + "@appAbout": {}, + "appDetails": "Sovelluksen tiedot", + "@appDetails": {}, + "appReleaseNotes": "Näytä sovelluksen julkaisutiedot", + "@appReleaseNotes": {}, + "appSettings": "Sovelluksen asetukset", + "@appSettings": {}, + "attachments": "Liitteet", + "@attachments": {}, "attachImage": "Liitä kuva", "@attachImage": { "description": "Attach an image" }, + "attachmentNone": "Liitteitä ei löytynyt", + "@attachmentNone": {}, + "attachmentNoneDetail": "Liitteitä ei löytynyt", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Valitse liite", + "@attachmentSelect": {}, + "attention": "Huomio", + "@attention": {}, + "barcodeAssign": "Aseta viivakoodi", + "@barcodeAssign": {}, + "barcodeUnknown": "Viivakoodia ei tunnistettu", + "@barcodeUnknown": {}, + "cancel": "Peruuta", + "@cancel": { + "description": "Cancel" + }, "category": "Kategoria", "@category": {}, "categoryCreate": "Uusi kategoria", "@categoryCreate": {}, + "company": "Yritys", + "@company": {}, + "companyEdit": "Muokkaa yritystä", + "@companyEdit": {}, + "companyUpdated": "Yrityksen tiedot päivitetty", + "@companyUpdated": {}, + "companies": "Yritykset", + "@companies": {}, "configureServer": "Määritä palvelimen asetukset", "@configureServer": {}, - "connectionRefused": "Yhteys kielletty", + "connectionRefused": "Yhteys evätty", "@connectionRefused": {}, + "customers": "Asiakkaat", + "@customers": {}, "damaged": "Vahingoittunut", "@damaged": {}, "darkMode": "Tumma tila", "@darkMode": {}, + "darkModeEnable": "Käytä tummaa tilaa", + "@darkModeEnable": {}, "delete": "Poista", "@delete": {}, + "deleteFailed": "Poisto epäonnistui", + "@deleteFailed": {}, "deletePart": "Poista osa", "@deletePart": {}, "deletePartDetail": "Poista tämä osa tietokannasta", "@deletePartDetail": {}, + "description": "Kuvaus", + "@description": {}, + "destroyed": "Tuhottu", + "@destroyed": {}, + "details": "Yksityiskohdat", + "@details": { + "description": "details" + }, + "documentation": "Dokumentaatio", + "@documentation": {}, + "downloading": "Ladataan tiedostoa", + "@downloading": {}, + "downloadError": "Latausvirhe", + "@downloadError": {}, "edit": "Muokkaa", "@edit": { "description": "edit" @@ -48,10 +118,323 @@ "@editPart": { "description": "edit part" }, + "enterPassword": "Syötä salasana", + "@enterPassword": {}, + "enterUsername": "Syötä käyttäjätunnus", + "@enterUsername": {}, "error": "Virhe", "@error": { "description": "Error" }, + "errorCreate": "Virhe luotaessa tietokantamerkintää", + "@errorCreate": {}, + "errorDelete": "Virhe poistettaessa tietokantamerkintää", + "@errorDelete": {}, + "errorDetails": "Virheen tiedot", + "@errorDetails": {}, + "errorReporting": "Virheen raportointi", + "@errorReporting": {}, + "errorReportUpload": "Lähetä virheraportit", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Lähetä nimettömät virheilmoitukset ja kaatumislokit", + "@errorReportUploadDetails": {}, + "feedback": "Palaute", + "@feedback": {}, + "feedbackError": "Palautetta lähetettäessä tapahtui virhe", + "@feedbackError": {}, + "feedbackSuccess": "Palaute lähetetty", + "@feedbackSuccess": {}, + "filterActive": "Aktiivinen", + "@filterActive": {}, + "filterComponent": "Komponentti", + "@filterComponent": {}, + "filterInStock": "Varastossa", + "@filterInStock": {}, + "filterVirtual": "Virtuaalinen", + "@filterVirtual": {}, + "history": "Historia", + "@history": { + "description": "history" + }, + "home": "Koti", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "inProduction": "Tuotannossa", + "@inProduction": {}, + "invalidHost": "Virheellinen isäntänimi", + "@invalidHost": {}, + "invalidUsernamePassword": "Virheellinen käyttäjätunnuksen / salasanan yhdistelmä", + "@invalidUsernamePassword": {}, + "keywords": "Avainsanat", + "@keywords": {}, + "language": "Kieli", + "@language": {}, + "languageDefault": "Järjestelmän oletuskieli", + "@languageDefault": {}, + "languageSelect": "Valitse kieli", + "@languageSelect": {}, + "lastUpdated": "Päivitetty viimeksi", + "@lastUpdated": {}, + "locationCreate": "Uusi sijainti", + "@locationCreate": {}, + "locationNotSet": "Sijaintia ei ole määritetty", + "@locationNotSet": {}, + "manufacturer": "Valmistaja", + "@manufacturer": {}, + "manufacturers": "Valmistajat", + "@manufacturers": {}, + "name": "Nimi", + "@name": {}, + "notes": "Merkinnät", + "@notes": { + "description": "Notes" + }, + "notifications": "Ilmoitukset", + "@notifications": {}, + "notificationsEmpty": "Ei lukemattomia ilmoituksia", + "@notificationsEmpty": {}, + "numberInvalid": "Virheellinen numero", + "@numberInvalid": {}, + "part": "Osa", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Uusi osa", + "@partCreate": {}, + "partCreateDetail": "Luo uusi osa tähän kategoriaan", + "@partCreateDetail": {}, + "partEdited": "Osa on päivitetty", + "@partEdited": {}, + "parts": "Osat", + "@parts": { + "description": "Part (multiple)" + }, + "partsNone": "Ei osia", + "@partsNone": {}, + "partNoResults": "Ei hakua vastaavia osia", + "@partNoResults": {}, + "partSettings": "Osan asetukset", + "@partSettings": {}, + "partDetails": "Osan tiedot", + "@partDetails": {}, + "partNotes": "Osan muistiinpanot", + "@partNotes": {}, + "password": "Salasana", + "@password": {}, + "passwordEmpty": "Salasana ei voi olla tyhjä", + "@passwordEmpty": {}, + "permissionAccountDenied": "Tililläsi ei ole tarvittavia oikeuksia tämän toiminnon suorittamiseen", + "@permissionAccountDenied": {}, + "permissionRequired": "Käyttöoikeus vaaditaan", + "@permissionRequired": {}, + "plugin": "Laajennus", + "@plugin": {}, + "pluginPrinter": "Tulostin", + "@pluginPrinter": {}, + "pluginSupport": "Laajennusten tuki käytössä", + "@pluginSupport": {}, + "profile": "Profiili", + "@profile": {}, + "profileAdd": "Lisää palvelinprofiili", + "@profileAdd": {}, + "profileConnect": "Yhdistä palvelimeen", + "@profileConnect": {}, + "profileEdit": "Muokkaa palvelinprofiilia", + "@profileEdit": {}, + "profileDelete": "Poista palvelinprofiili", + "@profileDelete": {}, + "profileName": "Profiilin nimi", + "@profileName": {}, + "profileNone": "Profiileja ei saatavilla", + "@profileNone": {}, + "profileNotSelected": "Profiilia ei valittu", + "@profileNotSelected": {}, + "profileSelect": "Valitsee InvenTree-palvelin", + "@profileSelect": {}, + "profileSelectOrCreate": "Valitse palvelin tai luo uusi profiili", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Napauta luodaksesi tai valitaksesi profiilin", + "@profileTapToCreate": {}, + "quantity": "Määrä", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Saatavilla oleva määrä", + "@quantityAvailable": {}, + "quantityEmpty": "Määrä on tyhjä", + "@quantityEmpty": {}, + "quantityInvalid": "Määrä on virheellinen", + "@quantityInvalid": {}, + "quantityPositive": "Määrän on oltava positiivinen", + "@quantityPositive": {}, + "received": "Vastaanotettu", + "@received": {}, + "receiveItem": "Vastaanota tuote", + "@receiveItem": {}, + "reference": "Viite", + "@reference": {}, + "refresh": "Päivitä", + "@refresh": {}, + "refreshing": "Päivitetään", + "@refreshing": {}, + "rejected": "Hylätty", + "@rejected": {}, + "releaseNotes": "Julkaisutiedot", + "@releaseNotes": {}, + "remove": "Poista", + "@remove": { + "description": "remove" + }, + "required": "Vaaditaan", + "@required": { + "description": "This field is required" + }, + "response403": "Lupa evätty", + "@response403": {}, + "response500": "Palvelimen sisäinen virhe", + "@response500": {}, + "response503": "Palvelu ei ole saatavilla", + "@response503": {}, + "response504": "Yhdyskäytävän aikakatkaisu", + "@response504": {}, + "responseUnknown": "Tuntematon vastaus", + "@responseUnknown": {}, + "save": "Tallenna", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skannaa viivakoodi", + "@scanBarcode": {}, + "searchParts": "Etsi osia", + "@searchParts": {}, + "searchStock": "Etsi varastosta", + "@searchStock": {}, + "select": "Valitse", + "@select": {}, + "selectFile": "Valitse tiedosto", + "@selectFile": {}, + "selectImage": "Valitse kuva", + "@selectImage": {}, + "selectLocation": "Valitse sijainti", + "@selectLocation": {}, + "send": "Lähetä", + "@send": {}, + "serialNumber": "Sarjanumero", + "@serialNumber": {}, + "serialNumbers": "Sarjanumerot", + "@serialNumbers": {}, + "server": "Palvelin", + "@server": {}, + "serverAddress": "Palvelimen osoite", + "@serverAddress": {}, + "serverApiRequired": "Vaadittu API-versio", + "@serverApiRequired": {}, + "serverApiVersion": "Palvelimen API-versio", + "@serverApiVersion": {}, + "serverAuthenticationError": "Todennusvirhe", + "@serverAuthenticationError": {}, + "serverCertificateError": "Varmennevirhe", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Palvelimen HTTPS-varmenne on virheellinen", + "@serverCertificateInvalid": {}, + "serverConnected": "Yhdistetty palvelimeen", + "@serverConnected": {}, + "serverConnecting": "Yhdistetään palvelimeen", + "@serverConnecting": {}, + "serverCouldNotConnect": "Palvelimeen yhdistäminen epäonnistui", + "@serverCouldNotConnect": {}, + "serverEmpty": "Palvelin ei voi olla tyhjä", + "@serverEmpty": {}, + "serverError": "Palvelimen virhe", + "@serverError": {}, + "serverDetails": "Palvelimen tiedot", + "@serverDetails": {}, + "serverMissingData": "Palvelimen vastauksesta puuttuu pakollisia kenttiä", + "@serverMissingData": {}, + "serverOld": "Vanha palvelimen versio", + "@serverOld": {}, + "serverSettings": "Palvelimen asetukset", + "@serverSettings": {}, + "serverStart": "Palvelimen täytyy alkaa http[s]:llä", + "@serverStart": {}, + "settings": "Asetukset", + "@settings": {}, + "serverNotSelected": "Palvelinta ei ole valittu", + "@serverNotSelected": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Äänet", + "@sounds": {}, + "status": "Tila", + "@status": {}, + "statusCode": "Tilakoodi", + "@statusCode": {}, + "stock": "Varasto", + "@stock": { + "description": "stock" + }, + "stockItem": "Varastotuote", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Varastotuotteet", + "@stockItems": {}, + "stockItemCreate": "Uusi varastotuote", + "@stockItemCreate": {}, + "stockItemDelete": "Poista varastotuote", + "@stockItemDelete": {}, + "stockItemDeleteSuccess": "Varastotuote poistettu", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Varastohistoria", + "@stockItemHistory": {}, + "stockItemTransferred": "Varastotuote siirretty", + "@stockItemTransferred": {}, + "stockItemUpdated": "Varastotuote päivitetty", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Varastotuotteita ei saatavilla", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Varastotuotteen muistiinpanot", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Varastotuote päivitetty", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Varastotuotteen päivitys epäonnistui", + "@stockItemUpdateFailure": {}, + "stockLocation": "Varastosijainti", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Varastosijainnit", + "@stockLocations": {}, + "supplier": "Toimittaja", + "@supplier": {}, + "takePicture": "Ota kuva", + "@takePicture": {}, + "timeout": "Aikakatkaisu", + "@timeout": { + "description": "" + }, + "transfer": "Siirrä", + "@transfer": { + "description": "transfer" + }, + "translate": "Käännä", + "@translate": {}, + "translateHelp": "Auta kääntämään InvenTree-sovellusta", + "@translateHelp": {}, + "username": "Käyttäjätunnus", + "@username": {}, + "usernameEmpty": "Käyttäjätunnus ei voi olla tyhjä", + "@usernameEmpty": {}, + "value": "Arvo", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Arvo ei voi olla tyhjä", + "@valueCannotBeEmpty": {}, + "valueRequired": "Arvo vaaditaan", + "@valueRequired": {}, + "version": "Versio", + "@version": {}, + "website": "Sivusto", + "@website": {} } \ No newline at end of file From 45fe79daf04c96e91c634ab3f94b047d87ddc274 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 10 Jun 2023 20:17:40 +1000 Subject: [PATCH 370/746] New translations app_en.arb (Finnish) (#362) --- lib/l10n/fi_FI/app_fi_FI.arb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 6c15c86..733dbcc 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -36,6 +36,8 @@ "@appReleaseNotes": {}, "appSettings": "Sovelluksen asetukset", "@appSettings": {}, + "appSettingsDetails": "Määritä InvenTree sovelluksen asetukset", + "@appSettingsDetails": {}, "attachments": "Liitteet", "@attachments": {}, "attachImage": "Liitä kuva", @@ -52,12 +54,20 @@ "@attention": {}, "barcodeAssign": "Aseta viivakoodi", "@barcodeAssign": {}, + "barcodeAssigned": "Viivakoodi asetettu", + "@barcodeAssigned": {}, + "barcodeError": "Viivakoodin skannausvirhe", + "@barcodeError": {}, + "barcodeInUse": "Viivakoodi on jo käytössä", + "@barcodeInUse": {}, "barcodeUnknown": "Viivakoodia ei tunnistettu", "@barcodeUnknown": {}, "cancel": "Peruuta", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Peru tilaus", + "@cancelOrder": {}, "category": "Kategoria", "@category": {}, "categoryCreate": "Uusi kategoria", @@ -90,6 +100,8 @@ "@deletePart": {}, "deletePartDetail": "Poista tämä osa tietokannasta", "@deletePartDetail": {}, + "deleteSuccess": "Poistaminen onnistui", + "@deleteSuccess": {}, "description": "Kuvaus", "@description": {}, "destroyed": "Tuhottu", @@ -157,12 +169,18 @@ "description": "history" }, "home": "Koti", + "@homeScreen": {}, + "homeScreen": "Aloitusnäyttö", "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, + "internalPartNumber": "Sisäinen osanumero", + "@internalPartNumber": {}, "inProduction": "Tuotannossa", "@inProduction": {}, "invalidHost": "Virheellinen isäntänimi", "@invalidHost": {}, + "invalidHostDetails": "Annettu isäntänimi ei kelpaa", + "@invalidHostDetails": {}, "invalidUsernamePassword": "Virheellinen käyttäjätunnuksen / salasanan yhdistelmä", "@invalidUsernamePassword": {}, "keywords": "Avainsanat", @@ -193,6 +211,8 @@ "@notifications": {}, "notificationsEmpty": "Ei lukemattomia ilmoituksia", "@notificationsEmpty": {}, + "noResults": "Ei tuloksia", + "@noResults": {}, "numberInvalid": "Virheellinen numero", "@numberInvalid": {}, "part": "Osa", @@ -285,6 +305,10 @@ "@remove": { "description": "remove" }, + "reportBug": "Ilmoita virheestä", + "@reportBug": {}, + "results": "Tulokset", + "@results": {}, "required": "Vaaditaan", "@required": { "description": "This field is required" @@ -297,6 +321,8 @@ "@response503": {}, "response504": "Yhdyskäytävän aikakatkaisu", "@response504": {}, + "response505": "HTTP-versiota ei tueta", + "@response505": {}, "responseUnknown": "Tuntematon vastaus", "@responseUnknown": {}, "save": "Tallenna", @@ -405,6 +431,8 @@ }, "stockLocations": "Varastosijainnit", "@stockLocations": {}, + "strictHttps": "Käytä tiukkaa HTTPS:ää", + "@strictHttps": {}, "supplier": "Toimittaja", "@supplier": {}, "takePicture": "Ota kuva", From b051aeccda657e01692ab816dd5a50f1093315b1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 11 Jun 2023 09:41:26 +1000 Subject: [PATCH 371/746] Barcode refactor (#363) * Move barcode.dart * Fix * Refactoring barcode scanner code: - Abstract the "controller" class (for future development) - Break barcode scanning code out into multiple files - Add CameraBarcodeController class (qr_code_scanner) * Add await * Make barcode scan delay configurable * remove unused import * Handle camera exceptions * Improve sequencing for camera scanner - Show loading overlay - Prevent reload if view is no longer mounted * Update docstring * Update release notes --- assets/release_notes.md | 6 + lib/api_form.dart | 5 +- lib/{ => barcode}/barcode.dart | 309 ++------------------------- lib/barcode/camera_controller.dart | 154 +++++++++++++ lib/barcode/controller.dart | 108 ++++++++++ lib/barcode/handler.dart | 121 +++++++++++ lib/barcode/tones.dart | 23 ++ lib/l10n/app_en.arb | 12 ++ lib/preferences.dart | 3 + lib/settings/barcode_settings.dart | 114 ++++++++++ lib/settings/settings.dart | 10 + lib/widget/location_display.dart | 8 +- lib/widget/part_detail.dart | 2 +- lib/widget/refreshable_state.dart | 2 +- lib/widget/stock_detail.dart | 7 +- lib/widget/supplier_part_detail.dart | 2 +- test/barcode_test.dart | 18 +- 17 files changed, 592 insertions(+), 312 deletions(-) rename lib/{ => barcode}/barcode.dart (64%) create mode 100644 lib/barcode/camera_controller.dart create mode 100644 lib/barcode/controller.dart create mode 100644 lib/barcode/handler.dart create mode 100644 lib/barcode/tones.dart create mode 100644 lib/settings/barcode_settings.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 10350fc..3aa2c2b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### - +--- +- Improvements to barcode scanning +- Translation updates + + ### 0.12.1 - May 2023 - Fixes bug in purchase order form diff --git a/lib/api_form.dart b/lib/api_form.dart index 83cf3e8..f8d82e0 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -9,7 +9,8 @@ import "package:flutter/material.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/tones.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -349,7 +350,7 @@ class APIFormField { Navigator.push( context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(handler) + MaterialPageRoute(builder: (context) => barcodeController(handler) ) ); }, diff --git a/lib/barcode.dart b/lib/barcode/barcode.dart similarity index 64% rename from lib/barcode.dart rename to lib/barcode/barcode.dart index 5487e3e..6c3c592 100644 --- a/lib/barcode.dart +++ b/lib/barcode/barcode.dart @@ -1,155 +1,42 @@ -import "dart:io"; import "package:flutter/material.dart"; + import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/purchase_order.dart"; -import "package:inventree/widget/purchase_order_detail.dart"; import "package:one_context/one_context.dart"; -import "package:qr_code_scanner/qr_code_scanner.dart"; + import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; -import "package:inventree/preferences.dart"; + +import "package:inventree/barcode/camera_controller.dart"; +import "package:inventree/barcode/controller.dart"; +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/tones.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/inventree/sentry.dart"; +import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/stock.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/supplier_part_detail.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/location_display.dart"; import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/purchase_order_detail.dart"; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_detail.dart"; +import "package:inventree/widget/supplier_part_detail.dart"; /* - * Play an audible 'success' alert to the user. + * Return a new BarcodeController instance */ -Future barcodeSuccessTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - playAudioFile("sounds/barcode_scan.mp3"); - } +InvenTreeBarcodeController barcodeController(BarcodeHandler handler) { + // TODO: Make this configurable + return CameraBarcodeController(handler); } -Future barcodeFailureTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - playAudioFile("sounds/barcode_error.mp3"); - } -} - - -/* Generic class which "handles" a barcode, by communicating with the InvenTree server, - * and handling match / unknown / error cases. - * - * Override functionality of this class to perform custom actions, - * based on the response returned from the InvenTree server - */ -class BarcodeHandler { - - BarcodeHandler(); - - String getOverlayText(BuildContext context) => "Barcode Overlay"; - - Future onBarcodeMatched(Map data) async { - // Called when the server "matches" a barcode - // Override this function - } - - Future onBarcodeUnknown(Map data) async { - // Called when the server does not know about a barcode - // Override this function - - barcodeFailureTone(); - - showSnackIcon( - L10().barcodeNoMatch, - success: false, - icon: Icons.qr_code, - ); - } - - // Called when the server returns an unhandled response - Future onBarcodeUnhandled(Map data) async { - barcodeFailureTone(); - showServerError("barcode/", L10().responseUnknown, data.toString()); - } - - /* - * Base function to capture and process barcode data. - * - * Returns true only if the barcode scanner should remain open - */ - Future processBarcode(QRViewController? _controller, String barcode, {String url = "barcode/"}) async { - - debug("Scanned barcode data: '${barcode}'"); - - barcode = barcode.trim(); - - // Empty barcode is invalid - if (barcode.isEmpty) { - - barcodeFailureTone(); - - showSnackIcon( - L10().barcodeError, - icon: FontAwesomeIcons.circleExclamation, - success: false - ); - - return; - } - - var response = await InvenTreeAPI().post( - url, - body: { - "barcode": barcode, - }, - expectedStatusCode: null, // Do not show an error on "unexpected code" - ); - - debug("Barcode scan response" + response.data.toString()); - - Map data = response.asMap(); - - // Handle strange response from the server - if (!response.isValid() || !response.isMap()) { - onBarcodeUnknown({}); - - showSnackIcon(L10().serverError, success: false); - - // We want to know about this one! - await sentryReportMessage( - "BarcodeHandler.processBarcode returned unexpected value", - context: { - "data": response.data?.toString() ?? "null", - "barcode": barcode, - "url": url, - "statusCode": response.statusCode.toString(), - "valid": response.isValid().toString(), - "error": response.error, - "errorDetail": response.errorDetail, - "className": "${this}", - } - ); - } else if (data.containsKey("success")) { - await onBarcodeMatched(data); - } else if ((response.statusCode >= 400) || data.containsKey("error")) { - await onBarcodeUnknown(data); - } else { - await onBarcodeUnhandled(data); - } - } -} /* * Class for general barcode scanning. @@ -638,168 +525,8 @@ class UniqueBarcodeHandler extends BarcodeHandler { } -class InvenTreeQRView extends StatefulWidget { - - const InvenTreeQRView(this._handler, {Key? key}) : super(key: key); - - final BarcodeHandler _handler; - - @override - State createState() => _QRViewState(); -} - - -class _QRViewState extends State { - - _QRViewState() : super(); - - final GlobalKey qrKey = GlobalKey(debugLabel: "QR"); - - QRViewController? _controller; - - bool flash_status = false; - - bool currently_processing = false; - - Future updateFlashStatus() async { - final bool? status = await _controller?.getFlashStatus(); - - flash_status = status != null && status; - - // Reload - if (mounted) { - setState(() {}); - } - } - - // In order to get hot reload to work we need to pause the camera if the platform - // is android, or resume the camera if the platform is iOS. - @override - void reassemble() { - super.reassemble(); - - if (mounted) { - if (Platform.isAndroid) { - _controller!.pauseCamera(); - } - - _controller!.resumeCamera(); - } - } - - /* Callback function when the Barcode scanner view is initially created */ - void _onViewCreated(BuildContext context, QRViewController controller) { - _controller = controller; - - controller.scannedDataStream.listen((barcode) { - handleBarcode(barcode.code); - }); - } - - /* Handle scanned data */ - Future handleBarcode(String? data) async { - - // Empty or missing data, or we have navigated away - if (!mounted || data == null || data.isEmpty) { - return; - } - - // Currently processing a barcode - return! - if (currently_processing) { - return; - } - - setState(() { - currently_processing = true; - }); - - // Pause camera functionality until we are done processing - _controller?.pauseCamera(); - - // processBarcode returns true if the scanner window is to remain open - widget._handler.processBarcode(_controller, data).then((value) { - // Re-start the process after some delay - Future.delayed(Duration(milliseconds: 500)).then((value) { - if (mounted) { - _controller?.resumeCamera(); - currently_processing = false; - } - }); - }); - } - - @override - void dispose() { - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - - return Scaffold( - appBar: AppBar( - title: Text(L10().scanBarcode), - actions: [ - IconButton( - icon: Icon(Icons.flip_camera_android), - onPressed: () { - _controller?.flipCamera(); - } - ), - IconButton( - icon: flash_status ? Icon(Icons.flash_off) : Icon(Icons.flash_on), - onPressed: () { - _controller?.toggleFlash(); - updateFlashStatus(); - }, - ) - ], - ), - body: Stack( - children: [ - Column( - children: [ - Expanded( - child: QRView( - key: qrKey, - onQRViewCreated: (QRViewController controller) { - _onViewCreated(context, controller); - }, - overlay: QrScannerOverlayShape( - borderColor: Colors.red, - borderRadius: 10, - borderLength: 30, - borderWidth: 10, - cutOutSize: 300, - ), - ) - ) - ] - ), - Center( - child: Column( - children: [ - Spacer(), - Padding( - child: Text(widget._handler.getOverlayText(context), - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.white), - ), - padding: EdgeInsets.all(20), - ), - ] - ) - ) - ], - ) - ); - } -} - Future scanQrCode(BuildContext context) async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeQRView(BarcodeScanHandler()))); + Navigator.push(context, MaterialPageRoute(builder: (context) => barcodeController(BarcodeScanHandler()))); return; } @@ -829,7 +556,7 @@ SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, Navigator.push( context, MaterialPageRoute( - builder: (context) => InvenTreeQRView(handler) + builder: (context) => barcodeController(handler) ) ); } diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart new file mode 100644 index 0000000..d7147ce --- /dev/null +++ b/lib/barcode/camera_controller.dart @@ -0,0 +1,154 @@ +import "dart:io"; +import "package:flutter/material.dart"; + +import "package:qr_code_scanner/qr_code_scanner.dart"; + +import "package:inventree/l10.dart"; + +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/controller.dart"; + +/* + * Barcode controller which uses the device's camera to scan barcodes. + * Under the hood it uses the qr_code_scanner package. + */ +class CameraBarcodeController extends InvenTreeBarcodeController { + + const CameraBarcodeController(BarcodeHandler handler, {Key? key}) : super(handler, key: key); + + @override + State createState() => _CameraBarcodeControllerState(); + +} + + +class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { + + _CameraBarcodeControllerState() : super(); + + QRViewController? _controller; + + bool flash_status = false; + + /* Callback function when the Barcode scanner view is initially created */ + void _onViewCreated(BuildContext context, QRViewController controller) { + _controller = controller; + + controller.scannedDataStream.listen((barcode) { + handleBarcodeData(barcode.code); + }); + } + + // In order to get hot reload to work we need to pause the camera if the platform + // is android, or resume the camera if the platform is iOS. + @override + void reassemble() { + super.reassemble(); + + if (mounted) { + if (Platform.isAndroid) { + _controller!.pauseCamera(); + } + + _controller!.resumeCamera(); + } + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + @override + Future pauseScan() async { + try { + await _controller?.pauseCamera(); + } on CameraException { + // do nothing + } + } + + @override + Future resumeScan() async { + try { + await _controller?.resumeCamera(); + } on CameraException { + // do nothing + } + } + + // Toggle the status of the camera flash + Future updateFlashStatus() async { + final bool? status = await _controller?.getFlashStatus(); + + if (mounted) { + setState(() { + flash_status = status != null && status; + }); + } + } + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: AppBar( + title: Text(L10().scanBarcode), + actions: [ + IconButton( + icon: Icon(Icons.flip_camera_android), + onPressed: () { + _controller?.flipCamera(); + } + ), + IconButton( + icon: flash_status ? Icon(Icons.flash_off) : Icon(Icons.flash_on), + onPressed: () { + _controller?.toggleFlash(); + updateFlashStatus(); + }, + ) + ], + ), + body: Stack( + children: [ + Column( + children: [ + Expanded( + child: QRView( + key: barcodeControllerKey, + onQRViewCreated: (QRViewController controller) { + _onViewCreated(context, controller); + }, + overlay: QrScannerOverlayShape( + borderColor: Colors.red, + borderRadius: 10, + borderLength: 30, + borderWidth: 10, + cutOutSize: 300, + ), + ) + ) + ] + ), + Center( + child: Column( + children: [ + Spacer(), + Padding( + child: Text(widget.handler.getOverlayText(context), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.white), + ), + padding: EdgeInsets.all(20), + ), + ] + ) + ) + ], + ) + ); + } +} diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart new file mode 100644 index 0000000..ca8e396 --- /dev/null +++ b/lib/barcode/controller.dart @@ -0,0 +1,108 @@ +import "package:flutter/material.dart"; +import "package:one_context/one_context.dart"; + +import "package:inventree/preferences.dart"; + +import "package:inventree/barcode/handler.dart"; + +import "package:inventree/widget/progress.dart"; + +/* + * Generic class which provides a barcode scanner interface. + * + * When the controller is instantiated, it is passed a "handler" class, + * which is used to process the scanned barcode. + */ +class InvenTreeBarcodeController extends StatefulWidget { + + const InvenTreeBarcodeController(this.handler, {Key? key}) : super(key: key); + + final BarcodeHandler handler; + + @override + State createState() => InvenTreeBarcodeControllerState(); +} + + +/* + * Base state widget for the barcode controller. + * This defines the basic interface for the barcode controller. + */ +class InvenTreeBarcodeControllerState extends State { + + InvenTreeBarcodeControllerState() : super(); + + final GlobalKey barcodeControllerKey = GlobalKey(debugLabel: "barcodeController"); + + // Internal state flag to test if we are currently processing a barcode + bool processingBarcode = false; + + /* + * Method to handle scanned data. + * Any implementing class should call this method when a barcode is scanned. + * Barcode data should be passed as a string + */ + Future handleBarcodeData(String? data) async { + + // Check that the data is valid, and this view is still mounted + if (!mounted || data == null || data.isEmpty) { + return; + } + + // Currently processing a barcode - ignore this one + if (processingBarcode) { + return; + } + + setState(() { + processingBarcode = true; + }); + + BuildContext? context = OneContext().context; + + showLoadingOverlay(context!); + await pauseScan(); + + await widget.handler.processBarcode(data); + + // processBarcode may have popped the context + if (!mounted) { + hideLoadingOverlay(); + return; + } + + int delay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + + Future.delayed(Duration(milliseconds: delay), () { + hideLoadingOverlay(); + if (mounted) { + resumeScan().then((_) { + if (mounted) { + setState(() { + processingBarcode = false; + }); + } + }); + } + }); + } + + // Hook function to "pause" the barcode scanner + Future pauseScan() async { + // Implement this function in subclass + } + + // Hook function to "resume" the barcode scanner + Future resumeScan() async { + // Implement this function in subclass + } + + /* + * Implementing classes are in control of building out the widget + */ + @override + Widget build(BuildContext context) { + return Container(); + } + +} \ No newline at end of file diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart new file mode 100644 index 0000000..3d72e9c --- /dev/null +++ b/lib/barcode/handler.dart @@ -0,0 +1,121 @@ + +import "package:flutter/material.dart"; + +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/barcode/tones.dart"; + +import "package:inventree/inventree/sentry.dart"; + +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/snacks.dart"; + + +/* Generic class which "handles" a barcode, by communicating with the InvenTree server, + * and handling match / unknown / error cases. + * + * Override functionality of this class to perform custom actions, + * based on the response returned from the InvenTree server + */ +class BarcodeHandler { + + BarcodeHandler(); + + // Return the text to display on the barcode overlay + // Note: Will be overridden by child classes + String getOverlayText(BuildContext context) => "Barcode Overlay"; + + // Called when the server "matches" a barcode + Future onBarcodeMatched(Map data) async { + // Override this function + } + + // Called when the server does not know about a barcode + Future onBarcodeUnknown(Map data) async { + // Override this function + + barcodeFailureTone(); + + showSnackIcon( + L10().barcodeNoMatch, + success: false, + icon: Icons.qr_code, + ); + } + + // Called when the server returns an unhandled response + Future onBarcodeUnhandled(Map data) async { + barcodeFailureTone(); + showServerError("barcode/", L10().responseUnknown, data.toString()); + } + + /* + * Base function to capture and process barcode data. + * + * Returns true only if the barcode scanner should remain open + */ + Future processBarcode(String barcode, {String url = "barcode/"}) async { + + debug("Scanned barcode data: '${barcode}'"); + + barcode = barcode.trim(); + + // Empty barcode is invalid + if (barcode.isEmpty) { + + barcodeFailureTone(); + + showSnackIcon( + L10().barcodeError, + icon: FontAwesomeIcons.circleExclamation, + success: false + ); + + return; + } + + var response = await InvenTreeAPI().post( + url, + body: { + "barcode": barcode, + }, + expectedStatusCode: null, // Do not show an error on "unexpected code" + ); + + debug("Barcode scan response" + response.data.toString()); + + Map data = response.asMap(); + + // Handle strange response from the server + if (!response.isValid() || !response.isMap()) { + onBarcodeUnknown({}); + + showSnackIcon(L10().serverError, success: false); + + // We want to know about this one! + await sentryReportMessage( + "BarcodeHandler.processBarcode returned unexpected value", + context: { + "data": response.data?.toString() ?? "null", + "barcode": barcode, + "url": url, + "statusCode": response.statusCode.toString(), + "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, + "className": "${this}", + } + ); + } else if (data.containsKey("success")) { + await onBarcodeMatched(data); + } else if ((response.statusCode >= 400) || data.containsKey("error")) { + await onBarcodeUnknown(data); + } else { + await onBarcodeUnhandled(data); + } + } +} diff --git a/lib/barcode/tones.dart b/lib/barcode/tones.dart new file mode 100644 index 0000000..a6e4b77 --- /dev/null +++ b/lib/barcode/tones.dart @@ -0,0 +1,23 @@ +import "package:inventree/helpers.dart"; +import "package:inventree/preferences.dart"; + +/* + * Play an audible 'success' alert to the user. + */ +Future barcodeSuccessTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_scan.mp3"); + } +} + +Future barcodeFailureTone() async { + + final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + + if (en) { + playAudioFile("sounds/barcode_error.mp3"); + } +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index dcb9c02..7116851 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -79,6 +79,12 @@ "availableStock": "Available Stock", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", "@barcodeAssign": {}, @@ -106,6 +112,12 @@ "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", "@barcodeScanGeneral": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index fc08450..23404df 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -29,6 +29,9 @@ const String INV_STOCK_SHOW_TESTS = "stockShowTests"; const String INV_REPORT_ERRORS = "reportErrors"; const String INV_STRICT_HTTPS = "strictHttps"; +// Barcode settings +const String INV_BARCODE_SCAN_DELAY = "barcodeScanDelay"; + /* * Class for storing InvenTree preferences in a NoSql DB */ diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart new file mode 100644 index 0000000..1624a10 --- /dev/null +++ b/lib/settings/barcode_settings.dart @@ -0,0 +1,114 @@ +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; + + +class InvenTreeBarcodeSettingsWidget extends StatefulWidget { + @override + _InvenTreeBarcodeSettingsState createState() => _InvenTreeBarcodeSettingsState(); +} + + +class _InvenTreeBarcodeSettingsState extends State { + + _InvenTreeBarcodeSettingsState(); + + int barcodeScanDelay = 500; + + final TextEditingController _barcodeScanDelayController = TextEditingController(); + + @override + void initState() { + super.initState(); + loadSettings(); + } + + Future loadSettings() async { + barcodeScanDelay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + + if (mounted) { + setState(() { + }); + } + } + + // Callback function to edit the barcode scan delay value + // TODO: Next time any new settings are added, refactor this into a generic function + Future _editBarcodeScanDelay(BuildContext context) async { + + _barcodeScanDelayController.text = barcodeScanDelay.toString(); + + return showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(L10().barcodeScanDelay), + content: TextField( + onChanged: (value) {}, + controller: _barcodeScanDelayController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: L10().barcodeScanDelayDetail, + ), + ), + actions: [ + MaterialButton( + color: Colors.red, + textColor: Colors.white, + child: Text(L10().cancel), + onPressed: () { + setState(() { + Navigator.pop(context); + }); + }, + ), + MaterialButton( + color: Colors.green, + textColor: Colors.white, + child: Text(L10().ok), + onPressed: () async { + int delay = int.tryParse(_barcodeScanDelayController.text) ?? barcodeScanDelay; + + // Apply limits + if (delay < 100) delay = 100; + if (delay > 2500) delay = 2500; + + InvenTreeSettingsManager().setValue(INV_BARCODE_SCAN_DELAY, delay); + setState(() { + barcodeScanDelay = delay; + Navigator.pop(context); + }); + }, + ), + ], + ); + } + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(L10().barcodes)), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().barcodeScanDelay), + subtitle: Text(L10().barcodeScanDelayDetail), + leading: FaIcon(FontAwesomeIcons.stopwatch), + trailing: GestureDetector( + child: Text("${barcodeScanDelay} ms"), + onTap: () { + _editBarcodeScanDelay(context); + }, + ), + ) + ], + ) + ) + ); + } + +} \ No newline at end of file diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index b202e6d..f5b8e2d 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -4,8 +4,10 @@ import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; + import "package:inventree/settings/about.dart"; import "package:inventree/settings/app_settings.dart"; +import "package:inventree/settings/barcode_settings.dart"; import "package:inventree/settings/home_settings.dart"; import "package:inventree/settings/login.dart"; import "package:inventree/settings/part_settings.dart"; @@ -68,6 +70,14 @@ class _InvenTreeSettingsState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } ), + ListTile( + title: Text(L10().barcodes), + subtitle: Text(L10().barcodeSettings), + leading: FaIcon(FontAwesomeIcons.barcode, color: COLOR_ACTION), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeBarcodeSettingsWidget())); + } + ), ListTile( title: Text(L10().part), subtitle: Text(L10().partSettings), diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index d693314..bd43ab4 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -4,7 +4,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; @@ -94,7 +94,7 @@ class _LocationDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute(builder: (context) => - InvenTreeQRView( + barcodeController( StockLocationScanInItemsHandler(location!))) ).then((value) { refresh(context); @@ -114,8 +114,8 @@ class _LocationDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute(builder: (context) => - InvenTreeQRView( - ScanParentLocationHandler(location!))) + barcodeController(ScanParentLocationHandler(location!)) + ) ).then((value) { refresh(context); }); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index bcfb733..1932780 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -4,7 +4,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 6946072..7d2eb34 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -3,7 +3,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/widget/back.dart"; import "package:inventree/widget/drawer.dart"; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index cb65679..37077f1 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -4,7 +4,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -168,8 +168,9 @@ class _StockItemDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute(builder: (context) => - InvenTreeQRView( - StockItemScanIntoLocationHandler(widget.item))) + barcodeController( + StockItemScanIntoLocationHandler(widget.item)) + ) ).then((ctx) { refresh(context); }); diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index 22768d1..9821bfb 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -4,7 +4,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; diff --git a/test/barcode_test.dart b/test/barcode_test.dart index e7b3eee..e896f44 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -8,7 +8,7 @@ import "package:flutter_test/flutter_test.dart"; import "package:inventree/api.dart"; -import "package:inventree/barcode.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; import "package:inventree/user_profile.dart"; @@ -57,7 +57,7 @@ void main() { test("Empty Barcode", () async { // Handle an 'empty' barcode - await handler.processBarcode(null, ""); + await handler.processBarcode(""); debugContains("Scanned barcode data: ''"); debugContains("showSnackIcon: 'Barcode scan error'"); @@ -68,7 +68,7 @@ void main() { test("Junk Data", () async { // test scanning 'junk' data - await handler.processBarcode(null, "abcdefg"); + await handler.processBarcode("abcdefg"); debugContains("Scanned barcode data: 'abcdefg'"); debugContains("showSnackIcon: 'No match for barcode'"); @@ -76,7 +76,7 @@ void main() { test("Invalid StockLocation", () async { // Scan an invalid stock location - await handler.processBarcode(null, '{"stocklocation": 999999}'); + await handler.processBarcode('{"stocklocation": 999999}'); debugContains("Scanned barcode data: '{\"stocklocation\": 999999}'"); debugContains("showSnackIcon: 'No match for barcode'"); @@ -97,7 +97,7 @@ void main() { var handler = StockItemScanIntoLocationHandler(item!); - await handler.processBarcode(null, '{"stocklocation": 7}'); + await handler.processBarcode('{"stocklocation": 7}'); // Check the location has been updated await item.reload(); assert(item.locationId == 7); @@ -105,7 +105,7 @@ void main() { debugContains("Scanned stock location 7"); // Scan into a new location - await handler.processBarcode(null, '{"stocklocation": 1}'); + await handler.processBarcode('{"stocklocation": 1}'); await item.reload(); assert(item.locationId == 1); @@ -125,7 +125,7 @@ void main() { // Scan multiple items into this location for (int id in [1, 2, 11]) { - await handler.processBarcode(null, '{"stockitem": ${id}}'); + await handler.processBarcode('{"stockitem": ${id}}'); var item = await InvenTreeStockItem().get(id) as InvenTreeStockItem?; @@ -150,12 +150,12 @@ void main() { var handler = ScanParentLocationHandler(location!); // Scan into new parent location - await handler.processBarcode(null, '{"stocklocation": 1}'); + await handler.processBarcode('{"stocklocation": 1}'); await location.reload(); assert(location.parentId == 1); // Scan back into old parent location - await handler.processBarcode(null, '{"stocklocation": 4}'); + await handler.processBarcode('{"stocklocation": 4}'); await location.reload(); assert(location.parentId == 4); From 21ace1ae024934f55a26db97306e82cb44550237 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jun 2023 22:52:07 +1000 Subject: [PATCH 372/746] Package updates (#365) * Update dart version * Update flutter version in workflow * Update packages * Updates to android workflow * Specify dart verrsion in CI * Run flutter upgrade * Helps to check which workflow is actually running I guess * Disable linting check * linting fixes * linting * Bug fix for paginator --- .github/workflows/android.yaml | 9 +-- .github/workflows/ci.yaml | 3 +- analysis_options.yaml | 8 ++- android/build.gradle | 2 +- lib/api.dart | 20 +++++++ lib/api_form.dart | 16 ++---- lib/inventree/model.dart | 4 +- lib/widget/dialogs.dart | 3 +- lib/widget/stock_detail.dart | 3 +- pubspec.lock | 100 ++++++++++++++++----------------- pubspec.yaml | 20 +++---- test/setup.dart | 2 +- 12 files changed, 106 insertions(+), 84 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index abd2b88..f462ba4 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -15,8 +15,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 - with: - submodules: recursive - name: Setup Java uses: actions/setup-java@v3 with: @@ -25,9 +23,11 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.7.3' + flutter-version: '3.10.4' + channel: 'stable' + - run: flutter --version - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v2.4.2 with: gradle-version: 7.6 - name: Collect Translation Files @@ -36,6 +36,7 @@ jobs: python3 collect_translations.py - name: Build for Android run: | + flutter upgrade flutter pub get cp lib/dummy_dsn.dart lib/dsn.dart flutter build apk --debug diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bc3be9c..dc848cd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,13 +39,14 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.7.3' + flutter-version: '3.10.4' - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py - name: Static Analysis Tests run: | + flutter upgrade cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get diff --git a/analysis_options.yaml b/analysis_options.yaml index 5e388c2..217d3d2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -6,8 +6,6 @@ analyzer: - lib/generated/** language: strict-raw-types: true - strong-mode: - implicit-casts: false linter: rules: @@ -21,6 +19,8 @@ linter: prefer_double_quotes: true + unreachable_from_main: false + prefer_final_locals: false prefer_const_constructors: false @@ -76,4 +76,6 @@ linter: avoid_classes_with_only_static_members: false - no_leading_underscores_for_local_identifiers: false \ No newline at end of file + no_leading_underscores_for_local_identifiers: false + + use_super_parameters: false diff --git a/android/build.gradle b/android/build.gradle index a5b4564..5ace051 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -29,6 +29,6 @@ subprojects { } } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/api.dart b/lib/api.dart index fdb1fbc..7a707df 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -80,6 +80,26 @@ class APIResponse { return []; } } + + /* + * Helper function to interpret response, and return a list. + * Handles case where the response is paginated, or a complete set of results + */ + List resultsList() { + + if (isList()) { + return asList(); + } else if (isMap()) { + var response = asMap(); + if (response.containsKey("results")) { + return response["results"] as List; + } else { + return []; + } + } else { + return []; + } + } } diff --git a/lib/api_form.dart b/lib/api_form.dart index f8d82e0..80e20f6 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -538,13 +538,7 @@ class APIFormField { final APIResponse response = await InvenTreeAPI().get(api_url, params: _filters); if (response.isValid()) { - List results = []; - - for (var result in response.data["results"] ?? []) { - results.add(result); - } - - return results; + return response.resultsList(); } else { return []; } @@ -1334,10 +1328,10 @@ class _APIFormWidgetState extends State { // Ensure the response is a valid JSON structure Map json = {}; - if (response.data != null && response.data is Map) { - for (dynamic key in response.data.keys) { - json[key.toString()] = response.data[key]; - } + var data = response.asMap(); + + for (String key in data.keys) { + json[key.toString()] = data[key]; } successFunc(json); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 97b2f16..abb7ec6 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -726,7 +726,9 @@ class InvenTreeModel { page.results = []; - for (var result in response.data["results"]) { + List results = dataMap["results"] as List; + + for (dynamic result in results) { page.addResult(createFromJson(result as Map)); } diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 398dea6..280c0e9 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -79,7 +79,8 @@ Future showErrorDialog(String title, {String description = "", APIResponse switch (response.statusCode) { case 400: // Bad request (typically bad input) if (response.data is Map) { - for (String field in response.data.keys) { + + for (String field in response.asMap().keys) { dynamic error = response.data[field]; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 37077f1..4deeaba 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -280,7 +280,8 @@ class _StockItemDisplayState extends RefreshableState { }, ).then((APIResponse response) { if (response.isValid() && response.statusCode == 200) { - for (var label in response.data) { + + for (var label in response.resultsList()) { if (label is Map) { labels.add(label); } diff --git a/pubspec.lock b/pubspec.lock index d890c9e..8141e71 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: "direct main" description: name: adaptive_theme - sha256: "61bde10390e937d11d05c6cf0d5cf378a73d49f9a442262e43613dae60ed0b3f" + sha256: "2d9bfee4240cdfad1b169cb43ac38fb49487e7fe1cc845e2973d4cef1780c0f6" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.3.0" analyzer: dependency: transitive description: @@ -45,66 +45,66 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" audioplayers: dependency: "direct main" description: name: audioplayers - sha256: "16451eab798b23ad9307aef6f9ca62bb8fb06542af8810eead0d236d3fd40a42" + sha256: "61583554386721772f9309f509e17712865b38565a903c761f96b1115a979282" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.1.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - sha256: b2c833e6f718b6b030454e329931229afafe9327fdb002874dd544dc8bf2484d + sha256: dbdc9b7f2aa2440314c638aa55aadd45c7705e8340d5eddf2e3fb8da32d4ae2c url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.2" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - sha256: e7a3c8759bf11ecfe4b20df338bf9f3d37c7719a5761c46a3833aba0ceeaacff + sha256: "6aea96df1d12f7ad5a71d88c6d1b22a216211a9564219920124c16768e456e9d" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.1.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - sha256: e95b65e1f4d4764601dac5e65f8d8186fc29401043ab020f1dacec483d708707 + sha256: "396b62ac62c92dd26c3bc5106583747f57a8b325ebd2b41e5576f840cfc61338" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.1.0" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - sha256: "178581a44cb685fd798d2108111d2e98cca3400e30b9c3a05546f124fb37f600" + sha256: f7daaed4659143094151ecf6bacd927d29ab8acffba98c110c59f0b81ae51143 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.1" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: "859ba09be2a57e57a787273f18c8cf0d9b61383870c5ee4b5632fe9adbc37edf" + sha256: ec84fd46eed1577148ed4113f5998a36a18da4fce7170c37ce3e21b631393339 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "3.1.0" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: "622e01c4c357c2aaf1b956c3a0f89d97c3cb40315c03f16e3b6c2a31ff9c38bc" + sha256: "1d3aaac98a192b8488167711ba1e67d8b96333e8d0572ede4e2912e5bbce69a3" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "2.0.2" back_button_interceptor: dependency: transitive description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -221,10 +221,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: @@ -269,10 +269,10 @@ packages: dependency: "direct main" description: name: currency_formatter - sha256: "24034a969f21a55071b1cf835655c1fb1fd94e3acd498a77283e945002591fb6" + sha256: "8fc2b612e465a4e886f5d8d3a7cec03cc3cabab617ef96bf54c70886c907f2c3" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" datetime_picker_formfield: dependency: "direct main" description: @@ -529,10 +529,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.0" io: dependency: transitive description: @@ -545,10 +545,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -561,10 +561,10 @@ packages: dependency: "direct dev" description: name: lint - sha256: "3e9343b1cededcfb1e8b40d0dbd3592b7a1c6c0121545663a991433390c2bc97" + sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.2" logging: dependency: transitive description: @@ -585,10 +585,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -601,10 +601,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: @@ -673,10 +673,10 @@ packages: dependency: "direct main" description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: "direct main" description: @@ -817,26 +817,26 @@ packages: dependency: "direct main" description: name: sembast - sha256: "4997717aa84f0622691815d7e2739988b7f7d3a463302fc878f7d5acfa748e96" + sha256: "3875487075df740e3ed0817571c950f015e5f730ff84fa0351849bf002fb4e1b" url: "https://pub.dev" source: hosted - version: "3.4.0+6" + version: "3.4.6+1" sentry: dependency: transitive description: name: sentry - sha256: cce8f5d696c7083e6915477b455de2134b689aff69bc31249844646f91a52ac7 + sha256: "0316390446c6497664379b3d72d1bc1b6e4c5385cf6c1f6a02c5ab5a3ce179ce" url: "https://pub.dev" source: hosted - version: "7.5.0" + version: "7.7.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: a772ad8abafdcf4ac04568bf3469cc541761412fd664a7aa99d9578fd0933a09 + sha256: cca6f3bcfa00d327d85424a42e4cc3b3abe25e6a2d68c4ff64b0e2a606684666 url: "https://pub.dev" source: hosted - version: "7.5.0" + version: "7.7.0" shared_preferences: dependency: transitive description: @@ -1030,26 +1030,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a5fcd2d25eeadbb6589e80198a47d6a464ba3e2049da473943b8af9797900c2d + sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" url: "https://pub.dev" source: hosted - version: "1.22.0" + version: "1.24.1" test_api: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" test_core: dependency: transitive description: name: test_core - sha256: "0ef9755ec6d746951ba0aabe62f874b707690b5ede0fecc818b138fcc9b14888" + sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" url: "https://pub.dev" source: hosted - version: "0.4.20" + version: "0.5.1" typed_data: dependency: transitive description: @@ -1211,5 +1211,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index d004089..cde9b93 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,15 +4,15 @@ description: InvenTree stock management version: 0.12.1+67 environment: - sdk: ">=2.16.0 <3.0.0" + sdk: ">=2.19.5 <3.0.0" dependencies: - adaptive_theme: ^3.2.0 # Theme management (e.g. dark mode) - audioplayers: ^3.0.1 # Play audio files + adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) + audioplayers: ^4.1.0 # Play audio files cached_network_image: ^3.2.3 # Download and cache remote images camera: ^0.10.3 # Camera cupertino_icons: ^1.0.3 - currency_formatter: ^2.0.0 + currency_formatter: ^2.0.1 datetime_picker_formfield: ^2.0.1 # Date / time picker device_info_plus: ^8.2.2 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter flutter_cache_manager: ^3.3.0 - flutter_localizations: + flutter_localizations: sdk: flutter flutter_localized_locales: ^2.0.4 flutter_markdown: ^0.6.13+1 # Rendering markdown @@ -30,22 +30,22 @@ dependencies: http: ^0.13.5 image_picker: ^0.8.7+4 # Select or take photos infinite_scroll_pagination: ^3.2.0 # Let the server do all the work! - intl: ^0.17.0 + intl: ^0.18.0 one_context: ^2.1.0 # Dialogs without requiring context open_filex: ^4.3.2 # Open local files package_info_plus: ^3.0.2 # App information introspection path: ^1.8.2 path_provider: ^2.0.12 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning - sembast: ^3.4.0+6 # NoSQL data storage - sentry_flutter: ^7.5.0 # Error reporting - url_launcher: ^6.1.10 # Open link in system browser + sembast: ^3.4.6+1 # NoSQL data storage + sentry_flutter: ^7.7.0 # Error reporting + url_launcher: ^6.1.10 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.11.0 flutter_test: sdk: flutter - lint: ^2.0.1 + lint: ^2.1.2 test: ^1.22.0 flutter_icons: diff --git a/test/setup.dart b/test/setup.dart index c4b5387..1338f13 100644 --- a/test/setup.dart +++ b/test/setup.dart @@ -15,7 +15,7 @@ void setupTestEnv() { // Mock the path provider const MethodChannel channel = MethodChannel("plugins.flutter.io/path_provider"); - TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall methodCall) async { return "."; }); From 8cebc25beafdc791eaa5f785af649d4e13d6e358 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jun 2023 23:10:19 +1000 Subject: [PATCH 373/746] Fix iOS workflow (#366) --- .github/workflows/android.yaml | 2 +- .github/workflows/ios.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index f462ba4..b08e4b9 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -39,4 +39,4 @@ jobs: flutter upgrade flutter pub get cp lib/dummy_dsn.dart lib/dsn.dart - flutter build apk --debug + flutter build apk --release --no-tree-shake-icons diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 61670f6..32c279b 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -25,13 +25,14 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.7.3' + flutter-version: '3.10.43' - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py - name: Build for iOS run: | + flutter upgrade flutter pub get cd ios pod repo update From ba409660f4145dbf64e788b5ba2b9104ce305e50 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jun 2023 23:29:45 +1000 Subject: [PATCH 374/746] More iOS workflow fixes (#367) * More iOS workflow fixes * revert to building android in debug - Needs signing key otherwise --- .github/workflows/android.yaml | 2 +- .github/workflows/ios.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index b08e4b9..f462ba4 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -39,4 +39,4 @@ jobs: flutter upgrade flutter pub get cp lib/dummy_dsn.dart lib/dsn.dart - flutter build apk --release --no-tree-shake-icons + flutter build apk --debug diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 32c279b..685a3ff 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -25,7 +25,8 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.10.43' + flutter-version: '3.10.4' + channel: 'stable' - name: Collect Translation Files run: | cd lib/l10n From 71bf3ad0490984041db3b34f6d48dc9b6c8501b9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jun 2023 19:53:50 +1000 Subject: [PATCH 375/746] App orientation (#369) * Configurable screen orientation - Follow system (default) - Fixed in portrait - Fixed in landscape * Fix for dialog --- assets/release_notes.md | 2 + lib/l10n/app_en.arb | 15 ++++ lib/main.dart | 26 ++++++- lib/preferences.dart | 7 ++ lib/settings/app_settings.dart | 130 +++++++++++++++++++++++---------- lib/widget/dialogs.dart | 45 ++++++++++++ 6 files changed, 185 insertions(+), 40 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3aa2c2b..2a843ce 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,5 +1,7 @@ ### - --- + +- Adds options for configuring screen orientation - Improvements to barcode scanning - Translation updates diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7116851..bdda8dd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -627,6 +627,21 @@ "onOrderDetails": "Items currently on order", "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", "@outstanding": {}, diff --git a/lib/main.dart b/lib/main.dart index f41357a..08b0a30 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -55,9 +55,29 @@ Future main() async { ); }; - runApp( - InvenTreeApp(savedThemeMode) - ); + final int orientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; + + List orientations = []; + + switch (orientation) { + case SCREEN_ORIENTATION_PORTRAIT: + orientations.add(DeviceOrientation.portraitUp); + break; + case SCREEN_ORIENTATION_LANDSCAPE: + orientations.add(DeviceOrientation.landscapeLeft); + break; + default: + orientations.add(DeviceOrientation.portraitUp); + orientations.add(DeviceOrientation.landscapeLeft); + orientations.add(DeviceOrientation.landscapeRight); + break; + } + + SystemChrome.setPreferredOrientations(orientations).then((_) { + runApp( + InvenTreeApp(savedThemeMode) + ); + }); }, (Object error, StackTrace stackTrace) async { sentryReportError("main.runZonedGuarded", error, stackTrace); diff --git a/lib/preferences.dart b/lib/preferences.dart index 23404df..694ad7c 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -15,6 +15,13 @@ const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; +const String INV_SCREEN_ORIENTATION = "appScreenOrientation"; + +// Available screen orientation values +const int SCREEN_ORIENTATION_SYSTEM = 0; +const int SCREEN_ORIENTATION_PORTRAIT = 1; +const int SCREEN_ORIENTATION_LANDSCAPE = 2; + const String INV_SOUNDS_BARCODE = "barcodeSounds"; const String INV_SOUNDS_SERVER = "serverSounds"; diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 42c94a0..00c27a7 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -3,6 +3,8 @@ import "package:flutter/material.dart"; import "package:adaptive_theme/adaptive_theme.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/widget/dialogs.dart"; import "package:one_context/one_context.dart"; import "package:inventree/api_form.dart"; @@ -34,6 +36,8 @@ class _InvenTreeAppSettingsState extends State { bool darkMode = false; + int screenOrientation = SCREEN_ORIENTATION_SYSTEM; + Locale? locale; @override @@ -51,6 +55,7 @@ class _InvenTreeAppSettingsState extends State { serverSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + screenOrientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; darkMode = AdaptiveTheme.of(context).mode.isDark; @@ -116,9 +121,9 @@ class _InvenTreeAppSettingsState extends State { InvenTreeApp.of(context)?.setLocale(locale); } ); - } + @override Widget build(BuildContext context) { @@ -128,6 +133,21 @@ class _InvenTreeAppSettingsState extends State { languageName = LocaleNames.of(context)!.nameOf(locale.toString()) ?? L10().languageDefault; } + IconData orientationIcon = Icons.screen_rotation; + + switch (screenOrientation) { + case SCREEN_ORIENTATION_PORTRAIT: + orientationIcon = Icons.screen_lock_portrait; + break; + case SCREEN_ORIENTATION_LANDSCAPE: + orientationIcon = Icons.screen_lock_landscape; + break; + case SCREEN_ORIENTATION_SYSTEM: + default: + orientationIcon = Icons.screen_rotation; + break; + } + return Scaffold( key: _settingsKey, appBar: AppBar( @@ -138,42 +158,6 @@ class _InvenTreeAppSettingsState extends State { children: [ /* Sound Settings */ Divider(height: 3), - ListTile( - title: Text( - L10().sounds, - style: TextStyle(fontWeight: FontWeight.bold), - ), - leading: FaIcon(FontAwesomeIcons.volumeHigh), - ), - ListTile( - title: Text(L10().serverError), - subtitle: Text(L10().soundOnServerError), - leading: FaIcon(FontAwesomeIcons.server), - trailing: Switch( - value: serverSounds, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_SOUNDS_SERVER, value); - setState(() { - serverSounds = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().barcodeTones), - subtitle: Text(L10().soundOnBarcodeAction), - leading: Icon(Icons.qr_code), - trailing: Switch( - value: barcodeSounds, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); - setState(() { - barcodeSounds = value; - }); - }, - ), - ), - Divider(height: 1), ListTile( title: Text( L10().appSettings, @@ -199,6 +183,41 @@ class _InvenTreeAppSettingsState extends State { } ) ), + GestureDetector( + child: ListTile( + title: Text(L10().orientation), + subtitle: Text(L10().orientationDetail), + leading: Icon(Icons.screen_rotation_alt), + trailing: Icon(orientationIcon), + ), + onTap: () async { + choiceDialog( + L10().orientation, + [ + ListTile( + leading: Icon(Icons.screen_rotation, color: screenOrientation == SCREEN_ORIENTATION_SYSTEM ? COLOR_ACTION : null), + title: Text(L10().orientationSystem), + ), + ListTile( + leading: Icon(Icons.screen_lock_portrait, color: screenOrientation == SCREEN_ORIENTATION_PORTRAIT ? COLOR_ACTION : null), + title: Text(L10().orientationPortrait), + ), + ListTile( + leading: Icon(Icons.screen_lock_landscape, color: screenOrientation == SCREEN_ORIENTATION_LANDSCAPE ? COLOR_ACTION : null), + title: Text(L10().orientationLandscape), + ) + ], + onSelected: (idx) async { + screenOrientation = idx as int; + + InvenTreeSettingsManager().setValue(INV_SCREEN_ORIENTATION, screenOrientation); + + setState(() { + }); + } + ); + }, + ), ListTile( title: Text(L10().strictHttps), subtitle: Text(L10().strictHttpsDetails), @@ -235,6 +254,43 @@ class _InvenTreeAppSettingsState extends State { }, ), ), + ListTile( + title: Text( + L10().sounds, + style: TextStyle(fontWeight: FontWeight.bold), + ), + leading: FaIcon(FontAwesomeIcons.volumeHigh), + ), + Divider(), + ListTile( + title: Text(L10().serverError), + subtitle: Text(L10().soundOnServerError), + leading: FaIcon(FontAwesomeIcons.server), + trailing: Switch( + value: serverSounds, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_SOUNDS_SERVER, value); + setState(() { + serverSounds = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().barcodeTones), + subtitle: Text(L10().soundOnBarcodeAction), + leading: Icon(Icons.qr_code), + trailing: Switch( + value: barcodeSounds, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); + setState(() { + barcodeSounds = value; + }); + }, + ), + ), + Divider(height: 1), ] ) ) diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 280c0e9..1c86ef2 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -10,6 +10,51 @@ import "package:inventree/preferences.dart"; import "package:inventree/widget/snacks.dart"; +/* + * Launch a dialog allowing the user to select from a list of options + */ +Future choiceDialog(String title, List items, {Function? onSelected}) async { + + List choices = []; + + for (int idx = 0; idx < items.length; idx++) { + choices.add( + GestureDetector( + child: items[idx], + onTap: () { + Navigator.pop(OneContext().context!); + if (onSelected != null) { + onSelected(idx); + } + }, + ) + ); + } + + OneContext().showDialog( + builder: (BuildContext context) { + return AlertDialog( + title: Text(title), + content: SingleChildScrollView( + child: Column( + children: choices, + ) + ), + actions: [ + TextButton( + child: Text(L10().cancel), + onPressed: () { + Navigator.pop(OneContext().context!); + }, + ) + ], + ); + } + ); + +} + + /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ From 9cc666d13e35f25853500c461fed9c5feb2eb22a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jun 2023 19:58:41 +1000 Subject: [PATCH 376/746] Fix bug when list of tiles flows off screen (#370) - Reimplement scrolling behaviour --- assets/release_notes.md | 2 +- lib/widget/refreshable_state.dart | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 2a843ce..2468ee4 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,7 +4,7 @@ - Adds options for configuring screen orientation - Improvements to barcode scanning - Translation updates - +- Bug fix for scrolling long lists ### 0.12.1 - May 2023 diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 7d2eb34..97d42bd 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -39,8 +39,10 @@ mixin BaseWidgetProperties { Widget getBody(BuildContext context) { // Default body calls getTiles() - return Column( - children: getTiles(context) + return SingleChildScrollView( + child: Column( + children: getTiles(context) + ) ); } From 367759e86c030f466d6ac6cf01aaaaebb0b522d5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jun 2023 20:00:59 +1000 Subject: [PATCH 377/746] Ignore barcode resume if not mounted (#371) --- lib/barcode/camera_controller.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index d7147ce..94031e8 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -71,6 +71,12 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future resumeScan() async { + + // Do not attempt to resume if the widget is not mounted + if (!mounted) { + return; + } + try { await _controller?.resumeCamera(); } on CameraException { From ca678c1c6f23f5a7d63a0d06ae4c376ed58630b3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jun 2023 21:28:38 +1000 Subject: [PATCH 378/746] Update version (#372) * Update version - Bump version to 0.12.2 * Tweak unit test --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- test/models_test.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 2468ee4..996ff5a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,4 +1,4 @@ -### - +### 0.12.2 - June 2023 --- - Adds options for configuring screen orientation diff --git a/pubspec.yaml b/pubspec.yaml index cde9b93..2b18b86 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.1+67 +version: 0.12.2+68 environment: sdk: ">=2.19.5 <3.0.0" diff --git a/test/models_test.dart b/test/models_test.dart index 0fe5c74..c44ad5c 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -70,7 +70,7 @@ void main() { // List with active filter results = await InvenTreePart().list(filters: {"active": "true"}); - expect(results.length, equals(13)); + expect(results.length, greaterThanOrEqualTo(13)); for (var result in results) { // results must be InvenTreePart instances From b863bbd5904a6ff8994966c6fe021af7fff2475c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 14 Jun 2023 19:56:17 +1000 Subject: [PATCH 379/746] Update info.plist --- ios/Runner/Info.plist | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index edb4d15..d2611ef 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -20,6 +20,7 @@ es-ES es-MX fa-IR + fi-FI fr-FR he-IL hu-HU From 001450d3bb1b9b1102ccc3e34bb617289767d80d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 18 Jun 2023 00:23:13 +1000 Subject: [PATCH 380/746] New Crowdin updates (#373) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_MX/app_es_MX.arb | 26 ++++++++++++++++++++++---- lib/l10n/id_ID/app_id_ID.arb | 18 +++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index a45a991..1632104 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Inventario Disponible", "@availableStock": {}, + "barcodes": "Códigos de barras", + "@barcodes": {}, + "barcodeSettings": "Ajustes de código de barras", + "@barcodeSettings": {}, "barcodeAssign": "Asignar código de barras", "@barcodeAssign": {}, "barcodeAssignDetail": "Escanear código de barras personalizado para asignar", @@ -74,6 +78,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Retraso de escaneo de código de barras", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Retraso entre escaneos de código de barras", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escanear un código de barras de InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Escanear artículos de inventario en esta ubicación", @@ -154,9 +162,9 @@ "@delete": {}, "deleteFailed": "Operación de borrado fallida", "@deleteFailed": {}, - "deletePart": "Eliminar pieza", + "deletePart": "Eliminar parte", "@deletePart": {}, - "deletePartDetail": "Eliminar esta pieza de la base de datos", + "deletePartDetail": "Eliminar esta parte de la base de datos", "@deletePartDetail": {}, "deleteSuccess": "Operación de borrado exitosa", "@deleteSuccess": {}, @@ -226,7 +234,7 @@ "@feedbackSuccess": {}, "filterActive": "Activo", "@filterActive": {}, - "filterActiveDetail": "Mostrar piezas activas", + "filterActiveDetail": "Mostrar partes activas", "@filterActiveDetail": {}, "filterAssembly": "Ensamblado", "@filterAssembly": {}, @@ -417,6 +425,16 @@ "@onOrder": {}, "onOrderDetails": "Artículos actualmente en pedido", "@onOrderDetails": {}, + "orientation": "Orientación de la pantalla", + "@orientation": {}, + "orientationDetail": "Orientación de la pantalla (requiere reiniciar)", + "@orientationDetail": {}, + "orientationLandscape": "Horizontal", + "@orientationLandscape": {}, + "orientationPortrait": "Vertical", + "@orientationPortrait": {}, + "orientationSystem": "Sistema", + "@orientationSystem": {}, "outstanding": "Pendiente", "@outstanding": {}, "outstandingOrderDetail": "Mostrar artículos pendientes", @@ -787,7 +805,7 @@ "@sublocationNoneDetail": {}, "submitFeedback": "Enviar comentarios", "@submitFeedback": {}, - "suppliedParts": "Piezas suministradas", + "suppliedParts": "Partes suministradas", "@suppliedParts": {}, "supplier": "Proveedor", "@supplier": {}, diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index acc5be8..fa8947a 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,21 @@ { "@@locale": "id", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "imageUploadSuccess": "Gambar telah diunggah", + "@imageUploadSuccess": {}, + "save": "Simpan", + "@save": { + "description": "Save" + }, + "sounds": "Suara", + "@sounds": {}, + "status": "Status", + "@status": {}, + "testResultUploadPass": "Hasil tes telah diunggah", + "@testResultUploadPass": {}, + "uploadSuccess": "Berkas telah diunggah", + "@uploadSuccess": {}, + "website": "Situs", + "@website": {} } \ No newline at end of file From 770d9cddb23d356e13414e87f0be0976e54ae171 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 20 Jun 2023 20:38:07 +1000 Subject: [PATCH 381/746] Add ability to filter stock by "in_stock" (#376) --- assets/release_notes.md | 6 ++++++ lib/inventree/stock.dart | 1 - lib/widget/part_list.dart | 1 + lib/widget/stock_list.dart | 6 ++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 996ff5a..15bc154 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### - +--- + +- Improved filters for stock list + ### 0.12.2 - June 2023 --- @@ -7,6 +12,7 @@ - Bug fix for scrolling long lists ### 0.12.1 - May 2023 +--- - Fixes bug in purchase order form diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index da79778..7d06fa5 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -186,7 +186,6 @@ class InvenTreeStockItem extends InvenTreeModel { "part_detail": "true", "location_detail": "true", "supplier_detail": "true", - "in_stock": "true", }; } diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 0b00bb9..5235e54 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -91,6 +91,7 @@ class _PaginatedPartListState extends PaginatedSearchState { "active": { "label": L10().filterActive, "help_text": L10().filterActiveDetail, + "tristate": true, }, "assembly": { "label": L10().filterAssembly, diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index c1a3232..fee6d11 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -80,6 +80,12 @@ class _PaginatedStockItemListState extends PaginatedSearchState> get filterOptions => { + "in_stock": { + "default": true, + "label": L10().filterInStock, + "help_text": L10().filterInStockDetail, + "tristate": true, + }, "cascade": { "default": false, "label": L10().includeSublocations, From 8076887e393f037f68a6237708b12fa7138e172b Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 22 Jun 2023 20:04:40 +1000 Subject: [PATCH 382/746] New translations app_en.arb (Portuguese, Brazilian) (#377) --- lib/l10n/pt_BR/app_pt_BR.arb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 13a5516..d02fde7 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Estoque Disponível", "@availableStock": {}, + "barcodes": "Códigos de barras", + "@barcodes": {}, + "barcodeSettings": "Definições do código de barras", + "@barcodeSettings": {}, "barcodeAssign": "Atribuir Código de Barras", "@barcodeAssign": {}, "barcodeAssignDetail": "Digitalize o código de barras personalizado para atribuir", @@ -74,6 +78,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Atraso na leitura de Código de Barras", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Atraso entre leituras de código de barras", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Busca de itens de estoque para este local", @@ -417,6 +425,16 @@ "@onOrder": {}, "onOrderDetails": "Itens atualmente com pedidos feitos", "@onOrderDetails": {}, + "orientation": "Orientação da tela", + "@orientation": {}, + "orientationDetail": "Orientação da tela (requer reinicialização)", + "@orientationDetail": {}, + "orientationLandscape": "Paisagem", + "@orientationLandscape": {}, + "orientationPortrait": "Retrato", + "@orientationPortrait": {}, + "orientationSystem": "Sistema", + "@orientationSystem": {}, "outstanding": "Pendente", "@outstanding": {}, "outstandingOrderDetail": "Mostrar itens pendentes", From e9eb84eacebfcd29d2af44993f68d86ed76ae0a6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 24 Jun 2023 11:34:42 +1000 Subject: [PATCH 383/746] Stock display (#379) * Display stock quantity more prominently * Cleanup search widget * Update for stock_detail widget * More tweaks * Change bottom bar icon * Display boolean parameters appropriately * Adds ability to edit part parameters * Bump icon size a bit * Improvements to filter options - Allow filtering by "option" type - To start with, filter stock by status code * Remove debug message * Remove getTriState method - No longer needed - Remove associated unit tests * Adjust filters based on server API version * Muted colors --- .gitignore | 1 + assets/release_notes.md | 2 + ios/Runner.xcodeproj/project.pbxproj | 1 + lib/api.dart | 15 ++++- lib/api_form.dart | 24 +++++++- lib/app_colors.dart | 6 +- lib/inventree/part.dart | 23 +++++++- lib/inventree/status_codes.dart | 20 +++++++ lib/inventree/stock.dart | 10 +++- lib/l10n/app_en.arb | 3 + lib/preferences.dart | 30 +++------- lib/widget/fields.dart | 2 +- lib/widget/paginator.dart | 75 +++++++++++------------ lib/widget/part_detail.dart | 26 ++------ lib/widget/part_list.dart | 8 ++- lib/widget/part_parameter_widget.dart | 42 ++++++++++++- lib/widget/refreshable_state.dart | 4 +- lib/widget/stock_detail.dart | 85 ++++++++++++++++----------- lib/widget/stock_list.dart | 48 +++++++++------ test/preferences_test.dart | 20 ------- 20 files changed, 278 insertions(+), 167 deletions(-) diff --git a/.gitignore b/.gitignore index 07101c9..dd7fc90 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ coverage/* # This file is auto-generated as part of the CI process test/coverage_helper_test.dart +InvenTreeSettings.db # Sentry API key lib/dsn.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 15bc154..edaf6f6 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,8 @@ ### - --- +- Edit part parameters from within the app +- Increase visibility of stock quantity in widgets - Improved filters for stock list ### 0.12.2 - June 2023 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d46f76c..69e5c04 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/lib/api.dart b/lib/api.dart index 7a707df..26cd5b9 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1332,7 +1332,20 @@ class InvenTreeAPI { static String get staticThumb => "/static/img/blank_image.thumbnail.png"; - CachedNetworkImage getThumbnail(String imageUrl, {double size = 40}) => getImage(imageUrl, width: size, height: size); + CachedNetworkImage? getThumbnail(String imageUrl, {double size = 40, bool hideIfNull = false}) { + + if (hideIfNull) { + if (imageUrl.isEmpty) { + return null; + } + } + + return getImage( + imageUrl, + width: size, + height: size + ); + } /* * Load image from the InvenTree server, diff --git a/lib/api_form.dart b/lib/api_form.dart index 80e20f6..19f539d 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -275,6 +275,7 @@ class APIFormField { // Construct a widget for this input Widget constructField(BuildContext context) { + switch (type) { case "string": case "url": @@ -696,6 +697,14 @@ class APIFormField { // Construct a string input element Widget _constructString() { + if (readOnly) { + return ListTile( + title: Text(label), + subtitle: Text(helpText), + trailing: Text(value.toString()), + ); + } + return TextFormField( decoration: InputDecoration( labelText: required ? label + "*" : label, @@ -724,12 +733,21 @@ class APIFormField { // Construct a boolean input element Widget _constructBoolean() { + bool? initial_value; + + if (value is bool || value == null) { + initial_value = value as bool?; + } else { + String vs = value.toString().toLowerCase(); + initial_value = ["1", "true", "yes"].contains(vs); + } + return CheckBoxField( label: label, labelStyle: _labelStyle(), helperText: helpText, helperStyle: _helperStyle(), - initial: value as bool?, + initial: initial_value, tristate: (getParameter("tristate") ?? false) as bool, onSaved: (val) { data["value"] = val; @@ -1262,6 +1280,10 @@ class _APIFormWidgetState extends State { for (var field in widget.fields) { + if (field.readOnly) { + continue; + } + if (field.isSimple) { // Simple top-level field data data[field.name] = field.data["value"]; diff --git a/lib/app_colors.dart b/lib/app_colors.dart index a5556a0..091718b 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -16,6 +16,6 @@ Color get COLOR_ACTION { } const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); -const Color COLOR_DANGER = Color.fromRGBO(250, 50, 50, 1); -const Color COLOR_SUCCESS = Color.fromRGBO(50, 250, 50, 1); -const Color COLOR_PROGRESS = Color.fromRGBO(50, 50, 250, 1); \ No newline at end of file +const Color COLOR_DANGER = Color.fromRGBO(200, 50, 75, 1); +const Color COLOR_SUCCESS = Color.fromRGBO(100, 200, 75, 1); +const Color COLOR_PROGRESS = Color.fromRGBO(50, 100, 200, 1); \ No newline at end of file diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index b476937..e335a11 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -133,12 +133,29 @@ class InvenTreePartParameter extends InvenTreeModel { @override String get URL => "part/parameter/"; + @override + List get rolesRequired => ["part"]; + @override InvenTreeModel createFromJson(Map json) => InvenTreePartParameter.fromJson(json); @override Map formFields() { - return {}; + + Map fields = { + "header": { + "type": "string", + "read_only": true, + "label": name, + "help_text": description, + "value": "", + }, + "data": { + "type": "string", + } + }; + + return fields; } @override @@ -160,7 +177,11 @@ class InvenTreePartParameter extends InvenTreeModel { return v; } + bool get as_bool => value.toLowerCase() == "true"; + String get units => getString("units", subKey: "template_detail"); + + bool get is_checkbox => getBool("checkbox", subKey: "template_detail", backup: false); } /* diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart index 1a563a2..2d9b3c3 100644 --- a/lib/inventree/status_codes.dart +++ b/lib/inventree/status_codes.dart @@ -23,6 +23,26 @@ class InvenTreeStatusCode { // Internal status code data loaded from server Map data = {}; + /* + * Construct a list of "choices" suitable for a form + */ + List get choices { + List _choices = []; + + for (String key in data.keys) { + dynamic _entry = data[key]; + + if (_entry is Map) { + _choices.add({ + "value": _entry["key"], + "display_name": _entry["label"] + }); + } + } + + return _choices; + } + // Load status code information from the server Future load({bool forceReload = false}) async { diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 7d06fa5..f6cca99 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -399,7 +399,7 @@ class InvenTreeStockItem extends InvenTreeModel { double get quantity => getDouble("quantity"); - String quantityString({bool includeUnits = false}){ + String quantityString({bool includeUnits = true}){ String q = ""; @@ -467,7 +467,13 @@ class InvenTreeStockItem extends InvenTreeModel { if (serialNumber.isNotEmpty) { return "SN: $serialNumber"; } else { - return simpleNumberString(quantity); + String q = simpleNumberString(quantity); + + if (units.isNotEmpty) { + q += " ${units}"; + } + + return q; } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bdda8dd..16dae59 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -278,6 +278,9 @@ "editNotes": "Edit Notes", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", "@editPart": { "description": "edit part" diff --git a/lib/preferences.dart b/lib/preferences.dart index 694ad7c..a7e8a30 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -126,7 +126,12 @@ class InvenTreeSettingsManager { Future getValue(String key, dynamic backup) async { - final value = await store.record(key).get(await _db); + dynamic value = await store.record(key).get(await _db); + + // Retrieve value + if (value == "__null__") { + value = null; + } if (value == null) { return backup; @@ -148,32 +153,11 @@ class InvenTreeSettingsManager { } } - // Load a tristate (true / false / null) setting - Future getTriState(String key, dynamic backup) async { - final dynamic value = await getValue(key, backup); - - if (value == null) { - return null; - } else if (value is bool) { - return value; - } else { - String s = value.toString().toLowerCase(); - - if (s.contains("t")) { - return true; - } else if (s.contains("f")) { - return false; - } else { - return null; - } - } - } - // Store a key:value pair in the database Future setValue(String key, dynamic value) async { // Encode null values as strings - value ??= "null"; + value ??= "__null__"; await store.record(key).put(await _db, value); } diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index 16f45e6..bff9cf2 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -154,8 +154,8 @@ class CheckBoxField extends FormField { onSaved: onSaved, initialValue: initial, builder: (FormFieldState state) { + return CheckboxListTile( - //dense: state.hasError, title: label != null ? Text(label, style: labelStyle) : null, value: state.value, tristate: tristate, diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index e9cc4cf..70ef6cb 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -38,44 +38,39 @@ abstract class PaginatedSearchState extends Sta // Override in implementing class String get prefix => "prefix_"; - // Return a map of boolean filtering options available for this list // Should be overridden by an implementing subclass Map> get filterOptions => {}; // Return the boolean value of a particular boolean filter - Future getBooleanFilterValue(String key) async { - key = "${prefix}bool_${key}"; + Future getFilterValue(String key) async { + key = "${prefix}filter_${key}"; Map opts = filterOptions[key] ?? {}; + dynamic backup = opts["default"]; + final result = await InvenTreeSettingsManager().getValue(key, backup); - bool? backup; - dynamic v = opts["default"]; - - if (v is bool) { - backup = v; - } - - final result = await InvenTreeSettingsManager().getTriState(key, backup); return result; } // Set the boolean value of a particular boolean filter - Future setBooleanFilterValue(String key, bool? value) async { - key = "${prefix}bool_${key}"; + Future setFilterValue(String key, dynamic value) async { + key = "${prefix}filter_${key}"; await InvenTreeSettingsManager().setValue(key, value); } // Construct the boolean filter options for this list - Future> constructBooleanFilters() async { + Future> constructFilters() async { Map f = {}; for (String k in filterOptions.keys) { - bool? value = await getBooleanFilterValue(k); + dynamic value = await getFilterValue(k); - if (value is bool) { - f[k] = value ? "true" : "false"; + // Skip null values + if (value == null) { + continue; } + f[k] = value.toString(); } return f; @@ -164,7 +159,7 @@ abstract class PaginatedSearchState extends Sta } }; - // Add in boolean filter options + // Add in selected filter options for (String key in filterOptions.keys) { Map opts = filterOptions[key] ?? {}; @@ -172,17 +167,18 @@ abstract class PaginatedSearchState extends Sta String label = (opts["label"] ?? key) as String; String? help_text = opts["help_text"] as String?; + List choices = (opts["choices"] ?? []) as List; + bool tristate = (opts["tristate"] ?? true) as bool; - bool? v = await getBooleanFilterValue(key); + dynamic v = await getFilterValue(key); // Prevent null value if not tristate if (!tristate && v == null) { v = false; } - // Add in the particular field - fields[key] = { + Map filter = { "type": "boolean", "display_name": label, "label": label, @@ -190,6 +186,16 @@ abstract class PaginatedSearchState extends Sta "value": v, "tristate": (opts["tristate"] ?? true) as bool, }; + + if (choices.isNotEmpty) { + // Configure as a choice input + filter["type"] = "choice"; + filter["choices"] = choices; + + filter.remove("tristate"); + } + + fields[key] = filter; } // Launch an interactive form for the user to select options @@ -211,16 +217,7 @@ abstract class PaginatedSearchState extends Sta // Save boolean fields for (String key in filterOptions.keys) { - - bool? v; - - dynamic value = data[key]; - - if (value is bool) { - v = value; - } - - await setBooleanFilterValue(key, v); + await setFilterValue(key, data[key]); } // Refresh data from the server @@ -293,7 +290,7 @@ abstract class PaginatedSearchState extends Sta params["ordering"] = o; } - Map f = await constructBooleanFilters(); + Map f = await constructFilters(); if (f.isNotEmpty) { params.addAll(f); @@ -348,6 +345,10 @@ abstract class PaginatedSearchState extends Sta void updateSearchTerm() { searchTerm = searchController.text; _pagingController.refresh(); + + if (mounted) { + setState(() {}); + } } // Function to construct a single paginated item @@ -409,19 +410,19 @@ abstract class PaginatedSearchState extends Sta */ Widget buildSearchInput(BuildContext context) { return ListTile( - trailing: orderingOptions.isEmpty ? null : GestureDetector( - child: FaIcon(FontAwesomeIcons.sort, color: COLOR_ACTION), + leading: orderingOptions.isEmpty ? null : GestureDetector( + child: Icon(Icons.filter_list, color: COLOR_ACTION, size: 32), onTap: () async { _saveOrderingOptions(context); }, ), - leading: GestureDetector( + trailing: GestureDetector( child: FaIcon( searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, - color: searchController.text.isNotEmpty ? COLOR_DANGER : null, + color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_ACTION, ), onTap: () { - if (searchController.text.isEmpty) { + if (searchController.text.isNotEmpty) { searchController.clear(); } updateSearchTerm(); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 1932780..9376837 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -228,20 +228,6 @@ class _PartDisplayState extends RefreshableState { }); } - - /* - * Toggle the "star" status of this paricular part - */ - Future _toggleStar(BuildContext context) async { - - if (InvenTreePart().canView) { - showLoadingOverlay(context); - await part.update(values: {"starred": "${!part.starred}"}); - hideLoadingOverlay(); - refresh(context); - } - } - void _editPartDialog(BuildContext context) { part.editForm( @@ -259,13 +245,11 @@ class _PartDisplayState extends RefreshableState { child: ListTile( title: Text("${part.fullname}"), subtitle: Text("${part.description}"), - trailing: IconButton( - icon: FaIcon(part.starred ? FontAwesomeIcons.solidStar : FontAwesomeIcons.star, - color: part.starred ? Colors.yellowAccent : null, - ), - onPressed: () { - _toggleStar(context); - }, + trailing: Text( + part.stockString(), + style: TextStyle( + fontSize: 20, + ) ), leading: GestureDetector( child: api.getImage(part.thumbnail), diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 5235e54..ba7c839 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -133,7 +133,13 @@ class _PaginatedPartListState extends PaginatedSearchState { return ListTile( title: Text(part.fullname), subtitle: Text(part.description), - trailing: Text(part.stockString()), + trailing: Text( + part.stockString(), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold + ) + ), leading: InvenTreeAPI().getThumbnail(part.thumbnail), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); diff --git a/lib/widget/part_parameter_widget.dart b/lib/widget/part_parameter_widget.dart index 1adc523..d889be8 100644 --- a/lib/widget/part_parameter_widget.dart +++ b/lib/widget/part_parameter_widget.dart @@ -4,6 +4,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; /* @@ -75,7 +76,7 @@ class _PaginatedParameterState extends PaginatedSearchState get orderingOptions => { - // TODO + }; @override @@ -91,6 +92,22 @@ class _PaginatedParameterState extends PaginatedSearchState editParameter(InvenTreePartParameter parameter) async { + + // Checkbox values are handled separately + if (parameter.is_checkbox) { + return; + } else { + parameter.editForm( + context, + L10().editParameter, + onSuccess: (data) async { + updateSearchTerm(); + } + ); + } + } + @override Widget buildItem(BuildContext context, InvenTreeModel model) { @@ -99,7 +116,28 @@ class _PaginatedParameterState extends PaginatedSearchState key) { - const double iconSize = 32; + const double iconSize = 40; List icons = [ IconButton( @@ -98,7 +98,7 @@ mixin BaseWidgetProperties { }, ), IconButton( - icon: Icon(Icons.qr_code_scanner, color: COLOR_ACTION), + icon: Icon(Icons.barcode_reader, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 4deeaba..c283077 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -577,8 +577,9 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text("${widget.item.partDescription}"), leading: InvenTreeAPI().getThumbnail(widget.item.partImage), trailing: Text( - api.StockStatus.label(widget.item.status), + widget.item.quantityString(), style: TextStyle( + fontSize: 20, color: api.StockStatus.color(widget.item.status), ) ), @@ -615,6 +616,41 @@ class _StockItemDisplayState extends RefreshableState { return tiles; } + // Location information + if ((widget.item.locationId > 0) && (widget.item.locationName.isNotEmpty)) { + tiles.add( + ListTile( + title: Text(L10().stockLocation), + subtitle: Text("${widget.item.locationPathString}"), + leading: FaIcon( + FontAwesomeIcons.locationDot, + color: COLOR_ACTION, + ), + onTap: () async { + if (widget.item.locationId > 0) { + + showLoadingOverlay(context); + var loc = await InvenTreeStockLocation().get(widget.item.locationId); + hideLoadingOverlay(); + + if (loc is InvenTreeStockLocation) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => LocationDisplayWidget(loc))); + } + } + }, + ), + ); + } else { + tiles.add( + ListTile( + title: Text(L10().stockLocation), + leading: FaIcon(FontAwesomeIcons.locationDot), + subtitle: Text(L10().locationNotSet), + ) + ); + } + // Quantity information if (widget.item.isSerialized()) { tiles.add( @@ -634,40 +670,19 @@ class _StockItemDisplayState extends RefreshableState { ); } - // Location information - if ((widget.item.locationId > 0) && (widget.item.locationName.isNotEmpty)) { - tiles.add( - ListTile( - title: Text(L10().stockLocation), - subtitle: Text("${widget.item.locationPathString}"), - leading: FaIcon( - FontAwesomeIcons.locationDot, - color: COLOR_ACTION, - ), - onTap: () async { - if (widget.item.locationId > 0) { - - showLoadingOverlay(context); - var loc = await InvenTreeStockLocation().get(widget.item.locationId); - hideLoadingOverlay(); - - if (loc is InvenTreeStockLocation) { - Navigator.push(context, MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc))); - } - } - }, - ), - ); - } else { - tiles.add( - ListTile( - title: Text(L10().stockLocation), - leading: FaIcon(FontAwesomeIcons.locationDot), - subtitle: Text(L10().locationNotSet), + // Stock item status information + tiles.add( + ListTile( + title: Text(L10().status), + leading: FaIcon(FontAwesomeIcons.circleInfo), + trailing: Text( + api.StockStatus.label(widget.item.status), + style: TextStyle( + color: api.StockStatus.color(widget.item.status), ) - ); - } + ) + ) + ); // Supplier part information (if available) if (widget.item.supplierPartId > 0) { @@ -676,7 +691,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage), + trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage, hideIfNull: true), onTap: () async { showLoadingOverlay(context); var sp = await InvenTreeSupplierPart().get( diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index fee6d11..dd657a7 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -79,24 +79,37 @@ class _PaginatedStockItemListState extends PaginatedSearchState> get filterOptions => { - "in_stock": { - "default": true, - "label": L10().filterInStock, - "help_text": L10().filterInStockDetail, - "tristate": true, - }, - "cascade": { - "default": false, - "label": L10().includeSublocations, - "help_text": L10().includeSublocationsDetail, - "tristate": false, - }, - "serialized": { - "label": L10().filterSerialized, - "help_text": L10().filterSerializedDetail, + Map> get filterOptions { + Map> filters = { + "in_stock": { + "default": true, + "label": L10().filterInStock, + "help_text": L10().filterInStockDetail, + "tristate": true, + }, + "cascade": { + "default": false, + "label": L10().includeSublocations, + "help_text": L10().includeSublocationsDetail, + "tristate": false, + }, + "serialized": { + "label": L10().filterSerialized, + "help_text": L10().filterSerializedDetail, + }, + "status": { + "label": L10().status, + "help_text": L10().statusCode, + "choices": InvenTreeAPI().StockStatus.choices, + } + }; + + if (!InvenTreeAPI().supportsStatusLabelEndpoints) { + filters.remove("status"); } - }; + + return filters; + } @override Future requestPage(int limit, int offset, Map params) async { @@ -125,6 +138,7 @@ class _PaginatedStockItemListState extends PaginatedSearchState Date: Sat, 24 Jun 2023 21:06:08 +1000 Subject: [PATCH 384/746] Barcode refactor (#381) * Simplify barcode scanning interface * Use consistent colors * Fix notches * Remove old comment --- lib/api_form.dart | 6 +---- lib/app_colors.dart | 2 +- lib/barcode/barcode.dart | 37 ++++++++++++++++--------------- lib/inventree/status_codes.dart | 9 ++++---- lib/widget/home.dart | 3 --- lib/widget/location_display.dart | 16 +++++-------- lib/widget/refreshable_state.dart | 13 ++++++++--- lib/widget/stock_detail.dart | 9 +++----- 8 files changed, 45 insertions(+), 50 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 19f539d..982039a 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -349,11 +349,7 @@ class APIFormField { ); }); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => barcodeController(handler) - ) - ); + scanBarcode(context, handler: handler); }, ), ) diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 091718b..feba6c0 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -18,4 +18,4 @@ Color get COLOR_ACTION { const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); const Color COLOR_DANGER = Color.fromRGBO(200, 50, 75, 1); const Color COLOR_SUCCESS = Color.fromRGBO(100, 200, 75, 1); -const Color COLOR_PROGRESS = Color.fromRGBO(50, 100, 200, 1); \ No newline at end of file +const Color COLOR_PROGRESS = Color.fromRGBO(50, 100, 200, 1); diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 6c3c592..d87f34c 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -30,11 +30,25 @@ import "package:inventree/widget/supplier_part_detail.dart"; /* - * Return a new BarcodeController instance + * Launch a barcode scanner with a particular context and handler. + * + * - Can be called with a custom BarcodeHandler instance, or use the default handler + * - Returns a Future which resolves when the scanner is dismissed + * - The provided BarcodeHandler instance is used to handle the scanned barcode */ -InvenTreeBarcodeController barcodeController(BarcodeHandler handler) { - // TODO: Make this configurable - return CameraBarcodeController(handler); +Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) async { + + // Default to generic scan handler + handler ??= BarcodeScanHandler(); + + InvenTreeBarcodeController controller = CameraBarcodeController(handler); + + return Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (context, _, __) => controller, + opaque: false, + ) + ); } @@ -525,13 +539,6 @@ class UniqueBarcodeHandler extends BarcodeHandler { } -Future scanQrCode(BuildContext context) async { - Navigator.push(context, MaterialPageRoute(builder: (context) => barcodeController(BarcodeScanHandler()))); - - return; -} - - SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, String barcode, String model, int pk) { if (barcode.isEmpty) { @@ -552,13 +559,7 @@ SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, state.refresh(context); }); }); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => barcodeController(handler) - ) - ); + scanBarcode(context, handler: handler); } ); } else { diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart index 2d9b3c3..8edb4ea 100644 --- a/lib/inventree/status_codes.dart +++ b/lib/inventree/status_codes.dart @@ -8,6 +8,7 @@ import "package:flutter/material.dart"; import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; @@ -112,17 +113,17 @@ class InvenTreeStatusCode { switch (color_name.toLowerCase()) { case "success": - return Colors.green; + return COLOR_SUCCESS; case "primary": - return Colors.blue; + return COLOR_PROGRESS; case "secondary": return Colors.grey; case "dark": return Colors.black; case "danger": - return Colors.red; + return COLOR_DANGER; case "warning": - return Colors.orange; + return COLOR_WARNING; case "info": return Colors.lightBlue; default: diff --git a/lib/widget/home.dart b/lib/widget/home.dart index bd5701c..cb15711 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -181,21 +181,18 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr ), ), onTap: () { - if (!allowed) { showSnackIcon( L10().permissionRequired, icon: FontAwesomeIcons.circleExclamation, success: false, ); - return; } if (callback != null) { callback(); } - }, ); } diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index bd43ab4..b76586d 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -91,11 +91,9 @@ class _LocationDisplayState extends RefreshableState { child: FaIcon(FontAwesomeIcons.qrcode), label: L10().barcodeScanItem, onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - barcodeController( - StockLocationScanInItemsHandler(location!))) + scanBarcode( + context, + handler: StockLocationScanInItemsHandler(location!), ).then((value) { refresh(context); }); @@ -111,11 +109,9 @@ class _LocationDisplayState extends RefreshableState { child: FaIcon(FontAwesomeIcons.qrcode), label: L10().transferStockLocation, onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - barcodeController(ScanParentLocationHandler(location!)) - ) + scanBarcode( + context, + handler: ScanParentLocationHandler(location!), ).then((value) { refresh(context); }); diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 462dda3..e484265 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -102,15 +102,22 @@ mixin BaseWidgetProperties { iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { - scanQrCode(context); + scanBarcode(context); } }, ) ]; return BottomAppBar( - shape: CircularNotchedRectangle(), - notchMargin: 20, + shape: AutomaticNotchedShape( + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), + ), + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(40)), + ), + ), + notchMargin: 10, child: IconTheme( data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary), child: Row( diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index c283077..903d626 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -165,12 +165,9 @@ class _StockItemDisplayState extends RefreshableState { child: Icon(Icons.qr_code_scanner), label: L10().scanIntoLocation, onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - barcodeController( - StockItemScanIntoLocationHandler(widget.item)) - ) + scanBarcode( + context, + handler: StockItemScanIntoLocationHandler(widget.item) ).then((ctx) { refresh(context); }); From 08ebc34730ea0d9a1f725afb08246dbaf658e188 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 26 Jun 2023 20:53:09 +1000 Subject: [PATCH 385/746] Bump version to 0.12.3 (#382) * Bump version to 0.12.3 * Updates for ios * Fix for float / decimal field * Cleanup simpleNumberString * Increment build number --- assets/release_notes.md | 3 ++- ios/Runner.xcodeproj/project.pbxproj | 33 +++++++++++++++++++--------- lib/api_form.dart | 4 +++- lib/helpers.dart | 11 ++++++++-- pubspec.yaml | 2 +- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index edaf6f6..eaa3c33 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,9 +1,10 @@ -### - +### - 0.12.3 - June 2023 --- - Edit part parameters from within the app - Increase visibility of stock quantity in widgets - Improved filters for stock list +- Bug fix for editing stock item purchase price ### 0.12.2 - June 2023 --- diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 69e5c04..e19424e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -167,22 +167,21 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1300; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = A5RYN267BH; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); @@ -203,7 +202,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -362,6 +360,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -371,14 +370,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -397,7 +399,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -409,6 +411,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -421,7 +424,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -441,6 +444,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -450,14 +454,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -482,7 +489,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -494,6 +501,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -503,14 +511,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -529,7 +540,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -541,6 +552,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -553,7 +565,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -573,6 +585,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -585,7 +598,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/lib/api_form.dart b/lib/api_form.dart index 982039a..c64ec57 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -476,6 +476,8 @@ class APIFormField { // Construct a floating point numerical input field Widget _constructFloatField() { + double initial = double.tryParse(value.toString()) ?? 0; + return TextFormField( decoration: InputDecoration( labelText: required ? label + "*" : label, @@ -484,7 +486,7 @@ class APIFormField { helperStyle: _helperStyle(), hintText: placeholderText, ), - initialValue: simpleNumberString(double.tryParse(value.toString()) ?? 0), + initialValue: simpleNumberString(initial), keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), validator: (value) { diff --git a/lib/helpers.dart b/lib/helpers.dart index 404e6ea..f958e6a 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -58,10 +58,17 @@ void debug(dynamic msg) { } +/* + * Simplify string representation of a floating point value + * Basically, don't display fractional component if it is an integer + */ String simpleNumberString(double number) { - // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart - return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1); + if (number.toInt() == number) { + return number.toInt().toString(); + } else { + return number.toString(); + } } /* diff --git a/pubspec.yaml b/pubspec.yaml index 2b18b86..9feed50 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.2+68 +version: 0.12.3+70 environment: sdk: ">=2.19.5 <3.0.0" From d0d96166c4ecbd17a51fb24a6ba652dd19714267 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 28 Jun 2023 21:10:09 +1000 Subject: [PATCH 386/746] New translations app_en.arb (Dutch) (#383) --- lib/l10n/nl_NL/app_nl_NL.arb | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 1afd385..6d20a3d 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Beschikbare Voorraad", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode instellingen", + "@barcodeSettings": {}, "barcodeAssign": "Streepjescode toewijzen", "@barcodeAssign": {}, "barcodeAssignDetail": "Scan aangepaste streepjescode om toe te wijzen", @@ -74,6 +78,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Barcode Scan vertraging", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Vertraging tussen barcode scannen", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Scan een InvenTree streepjescode", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scan voorraadartikelen naar deze locatie", @@ -108,6 +116,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Bestelling annuleren", + "@cancelOrder": {}, "category": "Categorie", "@category": {}, "categoryCreate": "Nieuwe Categorie", @@ -144,6 +154,10 @@ "@customers": {}, "damaged": "Beschadigd", "@damaged": {}, + "darkMode": "Donkere Modus", + "@darkMode": {}, + "darkModeEnable": "Donkere modus inschakelen", + "@darkModeEnable": {}, "delete": "Verwijderen", "@delete": {}, "deleteFailed": "Verwijderen mislukt", @@ -178,12 +192,16 @@ "@editLocation": {}, "editNotes": "Bewerk Notities", "@editNotes": {}, + "editParameter": "Parameter bewerken", + "@editParameter": {}, "editPart": "Bewerk onderdeel", "@editPart": { "description": "edit part" }, "editItem": "Bewerk Voorraadartikel", "@editItem": {}, + "editLineItem": "Voorraadartikel bewerken", + "@editLineItem": {}, "enterPassword": "Wachtwoord invoeren", "@enterPassword": {}, "enterUsername": "Gebruikersnaam invoeren", @@ -200,6 +218,10 @@ "@errorDetails": {}, "errorFetch": "Fout bij het ophalen van gegevens van server", "@errorFetch": {}, + "errorUserRoles": "Fout bij het aanvragen van de gebruikersrollen op de server", + "@errorUserRoles": {}, + "errorPluginInfo": "Fout bij het aanvragen van plugin gegevens van de server", + "@errorPluginInfo": {}, "errorReporting": "Fout bij Rapportage", "@errorReporting": {}, "errorReportUpload": "Foutrapporten Uploaden", @@ -230,6 +252,8 @@ "@filterInStockDetail": {}, "filterSerialized": "Geserialiseerd", "@filterSerialized": {}, + "filterSerializedDetail": "Toon geserialiseerde voorraad items", + "@filterSerializedDetail": {}, "filterTemplate": "Sjabloon", "@filterTemplate": {}, "filterTemplateDetail": "Sjabloononderdelen weergeven", @@ -305,6 +329,8 @@ "@inProduction": {}, "inProductionDetail": "Dit voorraadartikel is in productie", "@inProductionDetail": {}, + "internalPart": "Intern onderdeel", + "@internalPart": {}, "invalidHost": "Ongeldige hostnaam", "@invalidHost": {}, "invalidHostDetails": "Opgegeven hostnaam is ongeldig", @@ -321,8 +347,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", "@invalidUsernamePassword": {}, + "issue": "Probleem", + "@issue": {}, "issueDate": "Uitgiftedatum", "@issueDate": {}, + "issueOrder": "Plaats bestelling", + "@issueOrder": {}, "itemInLocation": "Artikel al op locatie", "@itemInLocation": {}, "keywords": "Trefwoorden", @@ -345,6 +375,8 @@ "@lineItem": {}, "lineItems": "Regelartikelen", "@lineItems": {}, + "lineItemUpdated": "Voorraadartikel bijgewerkt", + "@lineItemUpdated": {}, "locateItem": "Zoek voorraad item", "@locateItem": {}, "locateLocation": "Zoek voorraad locatie", @@ -361,6 +393,10 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturerPartNumber": "Onderdeelnummer fabrikant", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabrikant", + "@manufacturer": {}, "manufacturers": "Fabrikanten", "@manufacturers": {}, "missingData": "Ontbrekende gegevens", @@ -391,6 +427,20 @@ "@onOrder": {}, "onOrderDetails": "Items momenteel in bestelling", "@onOrderDetails": {}, + "orientation": "Schermoriëntatie", + "@orientation": {}, + "orientationDetail": "Schermoriëntatie (vereist herstart)", + "@orientationDetail": {}, + "orientationLandscape": "Liggend", + "@orientationLandscape": {}, + "orientationPortrait": "Staand", + "@orientationPortrait": {}, + "orientationSystem": "Systeem", + "@orientationSystem": {}, + "outstanding": "Openstaand", + "@outstanding": {}, + "outstandingOrderDetail": "Openstaande items tonen", + "@outstandingOrderDetail": {}, "packaging": "Verpakkingen", "@packaging": {}, "packageName": "Pakketnaam", @@ -489,8 +539,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Tik om een profiel aan te maken of te selecteren", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, "purchaseOrder": "Inkooporder", "@purchaseOrder": {}, + "purchaseOrderCreate": "Nieuwe Inkooporder", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Bewerk Inkooporder", "@purchaseOrderEdit": {}, "purchaseOrders": "Inkooporders", @@ -517,6 +571,8 @@ "@queryNoResults": {}, "received": "Ontvangen", "@received": {}, + "receivedFilterDetail": "Toon ontvangen artikelen", + "@receivedFilterDetail": {}, "receiveItem": "Ontvang Artikel", "@receiveItem": {}, "receivedItem": "Ontvangen Voorraad Artikelen", @@ -629,6 +685,8 @@ "@send": {}, "serialNumber": "Serienummer", "@serialNumber": {}, + "serialNumbers": "Serienummers", + "@serialNumbers": {}, "server": "Server", "@server": {}, "serverAddress": "Server Adres", @@ -671,6 +729,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server niet geselecteerd", "@serverNotSelected": {}, + "sku": "Artikelnummer", + "@sku": {}, "sounds": "Geluid", "@sounds": {}, "soundOnBarcodeAction": "Speel hoorbare toon bij streepjescode actie", @@ -727,6 +787,8 @@ }, "stockLocations": "Voorraadlocaties", "@stockLocations": {}, + "stockTopLevel": "Hoogste niveau voorraadlocatie", + "@stockTopLevel": {}, "strictHttps": "Gebruik Strict HTTPS", "@strictHttps": {}, "strictHttpsDetails": "Forceer een strikte controle van HTTPS certificaat", @@ -753,6 +815,8 @@ "@supplierPart": {}, "supplierPartEdit": "Bewerk Leveranciersonderdeel", "@supplierPartEdit": {}, + "supplierPartNumber": "Onderdeelnummer leverancier", + "@supplierPartNumber": {}, "supplierPartUpdated": "Leveranciersonderdeel bijgewerkt", "@supplierPartUpdated": {}, "supplierParts": "Leveranciersonderdeel", @@ -777,6 +841,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Toon voorraadartikel test resultaat", + "@testResultsDetail": {}, "testResultAdd": "Voeg Testresultaat Toe", "@testResultAdd": {}, "testResultNone": "Geen Testresultaten", @@ -817,6 +883,8 @@ "@translate": {}, "translateHelp": "Help de InvenTree app te vertalen", "@translateHelp": {}, + "unitPrice": "Stukprijs", + "@unitPrice": {}, "units": "Eenheden", "@units": {}, "unknownResponse": "Onbekende Reactie", @@ -829,6 +897,8 @@ "@uploadSuccess": {}, "usedIn": "Wordt Gebruikt In", "@usedIn": {}, + "usedInDetails": "Dit product heeft het volgende onderdeel nodig", + "@usedInDetails": {}, "username": "Gebruikersnaam", "@username": {}, "usernameEmpty": "Gebruikersnaam mag niet leeg zijn", From 279c15509c867f3369d7656a1e77c0e0e43cb519 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 28 Jun 2023 21:25:15 +1000 Subject: [PATCH 387/746] Pre fill location (#384) * Pre-fill the location when transferring stock * Update release notes --- assets/release_notes.md | 6 ++++++ lib/widget/stock_detail.dart | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index eaa3c33..b1155f0 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.12.4 - +--- + +- Pre-fill stock location when transferring stock amount + + ### - 0.12.3 - June 2023 --- diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 903d626..c33c957 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -544,7 +544,9 @@ class _StockItemDisplayState extends RefreshableState { "nested": true, "value": widget.item.quantity, }, - "location": {}, + "location": { + "value": widget.item.locationId, + }, "notes": {}, }; From 320b16f86e24f6a6809dd89f85b634754618c913 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 29 Jun 2023 22:48:14 +1000 Subject: [PATCH 388/746] Specify batch code for incoming items (#386) When receiving against purchase order --- lib/widget/po_line_detail.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/widget/po_line_detail.dart b/lib/widget/po_line_detail.dart index 9391cdf..b8ac8aa 100644 --- a/lib/widget/po_line_detail.dart +++ b/lib/widget/po_line_detail.dart @@ -121,7 +121,10 @@ class _POLineDetailWidgetState extends RefreshableState { "parent": "items", "nested": true, }, - "location": { + "location": {}, + "batch_code": { + "parent": "items", + "nested": true, }, "barcode": { "parent": "items", From 23abcb48f2b206dfe6db046bb9d2d9cafc26e670 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 30 Jun 2023 22:30:51 +1000 Subject: [PATCH 389/746] New Crowdin updates (#387) * New translations app_en.arb (Russian) * New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 272 +++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index c33b930..7302a0b 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -1,5 +1,9 @@ { "@@locale": "ru", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, "ok": "ОК", "@ok": { "description": "OK" @@ -34,6 +38,8 @@ "@appReleaseNotes": {}, "appSettings": "Настройки приложения", "@appSettings": {}, + "appSettingsDetails": "Изменить настройки приложения", + "@appSettingsDetails": {}, "attachments": "Вложения", "@attachments": {}, "attachImage": "Прикрепить изображение", @@ -46,6 +52,14 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "Выбрать вложение", "@attachmentSelect": {}, + "attention": "Внимание", + "@attention": {}, + "availableStock": "Доступный запас", + "@availableStock": {}, + "barcodes": "Штрих-коды", + "@barcodes": {}, + "barcodeSettings": "Настройки штрих-кодов", + "@barcodeSettings": {}, "barcodeAssign": "Прикрепить штрих-код", "@barcodeAssign": {}, "barcodeAssignDetail": "Сканируйте пользовательский штрих-код для назначения", @@ -56,8 +70,108 @@ "@barcodeError": {}, "barcodeInUse": "Штрих-код уже был назначен", "@barcodeInUse": {}, + "barcodeMissingHash": "Данные хэша штрих-кода отсутствуют в ответе", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Нет совпадений для штрих-кода", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Штрих-код не назначен", + "@barcodeNotAssigned": {}, + "barcodeScanAssign": "Сканировать для присвоения штрих-кода", + "@barcodeScanAssign": {}, + "barcodeScanDelay": "Задержка сканирования штрих-кода", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Задержка между сканированием штрих-кодов", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Сканировать штрих-код InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanLocation": "Сканировать местоположение склада", + "@barcodeScanLocation": {}, + "barcodeScanIntoLocationSuccess": "Сканировано в местоположение", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Элемент не просканирован в", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Сканировать товар в наличии", + "@barcodeScanItem": {}, + "barcodeTones": "Сигналы штрих-кода", + "@barcodeTones": {}, + "barcodeUnassign": "Отменить назначение штрих-кода", + "@barcodeUnassign": {}, + "barcodeUnknown": "Штрихкод не распознан", + "@barcodeUnknown": {}, + "batchCode": "Код партии", + "@batchCode": {}, + "billOfMaterials": "Спецификации материалов", + "@billOfMaterials": {}, + "bom": "Спецификация", + "@bom": {}, + "bomEnable": "Отображать спецификации материалов", + "@bomEnable": {}, + "build": "Сборка", + "@build": {}, + "building": "Здание", + "@building": {}, + "cancel": "Отменить", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Отменить заказ", + "@cancelOrder": {}, + "category": "Категория", + "@category": {}, + "categoryCreate": "Новая категория", + "@categoryCreate": {}, + "categoryCreateDetail": "Создать новую категорию деталей", + "@categoryCreateDetail": {}, + "categoryUpdated": "Категория деталей обновлена", + "@categoryUpdated": {}, + "company": "Компания", + "@company": {}, + "companyEdit": "Редактировать компанию", + "@companyEdit": {}, "companyNoResults": "Нет организаций, соответствующих запросу", "@companyNoResults": {}, + "companyUpdated": "Информация о компании обновлена", + "@companyUpdated": {}, + "companies": "Компании", + "@companies": {}, + "configureServer": "Настройка параметров сервера", + "@configureServer": {}, + "connectionRefused": "В соединении отказано", + "@connectionRefused": {}, + "count": "Количество", + "@count": { + "description": "Count" + }, + "countStock": "Количество на складе", + "@countStock": { + "description": "Count Stock" + }, + "customers": "Покупатели", + "@customers": {}, + "damaged": "Поврежденный", + "@damaged": {}, + "darkMode": "Тёмная тема", + "@darkMode": {}, + "darkModeEnable": "Включить тёмную тему", + "@darkModeEnable": {}, + "delete": "Удалить", + "@delete": {}, + "deleteFailed": "Ошибка удаления", + "@deleteFailed": {}, + "deletePart": "Удалить деталь", + "@deletePart": {}, + "deletePartDetail": "Удалить эту деталь из базы данных", + "@deletePartDetail": {}, + "deleteSuccess": "Удаление успешно завершено", + "@deleteSuccess": {}, + "description": "Описание", + "@description": {}, + "destroyed": "Разрушено", + "@destroyed": {}, + "details": "Подробности", + "@details": { + "description": "details" + }, "downloading": "Загрузка файла", "@downloading": {}, "downloadError": "Ошибка загрузки", @@ -148,10 +262,18 @@ "@itemInLocation": {}, "keywords": "Ключевые слова", "@keywords": {}, + "language": "Язык", + "@language": {}, + "languageDefault": "Язык системы по умолчанию", + "@languageDefault": {}, + "languageSelect": "Выберите язык", + "@languageSelect": {}, "lastStocktake": "Последняя инвентаризация", "@lastStocktake": {}, "lastUpdated": "Последние обновлённые", "@lastUpdated": {}, + "level": "Уровень", + "@level": {}, "lineItem": "Элемент строки", "@lineItem": {}, "lineItems": "Элементы строки", @@ -166,6 +288,10 @@ "@link": {}, "lost": "Потерян", "@lost": {}, + "manufacturerPartNumber": "Код производителя", + "@manufacturerPartNumber": {}, + "manufacturer": "Производитель", + "@manufacturer": {}, "manufacturers": "Производители", "@manufacturers": {}, "missingData": "Отсутствующие данные", @@ -178,6 +304,10 @@ "@notes": { "description": "Notes" }, + "notifications": "Уведомления", + "@notifications": {}, + "notificationsEmpty": "Нет непрочитанных уведомлений", + "@notificationsEmpty": {}, "noResponse": "Нет ответа от сервера", "@noResponse": {}, "noResults": "Нет результатов", @@ -192,10 +322,24 @@ "@onOrder": {}, "onOrderDetails": "Заказаные элементы", "@onOrderDetails": {}, + "orientation": "Ориентация экрана", + "@orientation": {}, + "orientationDetail": "Ориентация экрана (требуется перезапуск)", + "@orientationDetail": {}, + "orientationLandscape": "Альбомная", + "@orientationLandscape": {}, + "orientationPortrait": "Портретная", + "@orientationPortrait": {}, + "orientationSystem": "Система", + "@orientationSystem": {}, "packaging": "Упаковка", "@packaging": {}, "packageName": "Название упаковки", "@packageName": {}, + "parameters": "Параметры", + "@parameters": {}, + "parametersSettingDetail": "Отображение параметров детали", + "@parametersSettingDetail": {}, "parent": "Родитель", "@parent": {}, "parentCategory": "Родительская категория", @@ -210,6 +354,8 @@ "@partCreate": {}, "partCreateDetail": "Создать компонент в данной категории", "@partCreateDetail": {}, + "partEdited": "Деталь обновлена", + "@partEdited": {}, "parts": "Номенклатура", "@parts": { "description": "Part (multiple)" @@ -218,6 +364,56 @@ "@partsNone": {}, "partNoResults": "Нет компонентов, соответствующих запросу", "@partNoResults": {}, + "partSettings": "Настройки деталей", + "@partSettings": {}, + "partsStarred": "Детали с включёнными уведомлениями", + "@partsStarred": {}, + "partCategoryTopLevel": "Категория детали верхнего уровня", + "@partCategoryTopLevel": {}, + "password": "Пароль", + "@password": {}, + "passwordEmpty": "Пароль не может быть пустым", + "@passwordEmpty": {}, + "permissionAccountDenied": "Ваш аккаунт не имеет разрешения на выполнение этого действия", + "@permissionAccountDenied": {}, + "permissionRequired": "Требуется разрешение", + "@permissionRequired": {}, + "printLabel": "Печать этикетки", + "@printLabel": {}, + "plugin": "Плагин", + "@plugin": {}, + "pluginPrinter": "Принтер", + "@pluginPrinter": {}, + "pluginSupport": "Поддержка плагинов включена", + "@pluginSupport": {}, + "pluginSupportDetail": "Сервер поддерживает пользовательские плагины", + "@pluginSupportDetail": {}, + "printLabelFailure": "Ошибка печати этикеток", + "@printLabelFailure": {}, + "printLabelSuccess": "Этикетка отправлена на печать", + "@printLabelSuccess": {}, + "profile": "Профиль", + "@profile": {}, + "profileAdd": "Добавить профиль сервера", + "@profileAdd": {}, + "profileConnect": "Подключение к серверу", + "@profileConnect": {}, + "profileEdit": "Редактировать профиль сервера", + "@profileEdit": {}, + "profileDelete": "Удалить профиль сервера", + "@profileDelete": {}, + "profileName": "Имя профиля", + "@profileName": {}, + "profileNone": "Нет доступных профилей", + "@profileNone": {}, + "profileNotSelected": "Профиль не выбран", + "@profileNotSelected": {}, + "profileSelect": "Выбрать сервер InvenTree", + "@profileSelect": {}, + "response403": "Доступ запрещён", + "@response403": {}, + "response404": "Ресурс не найден", + "@response404": {}, "response405": "405 Метод не разрешен", "@response405": {}, "response429": "Слишком много запросов", @@ -260,6 +456,8 @@ "@search": { "description": "search" }, + "searching": "Поиск", + "@searching": {}, "searchLocation": "Искать по месту", "@searchLocation": {}, "searchParts": "Найти номенклатуру", @@ -272,6 +470,80 @@ "@selectFile": {}, "selectImage": "Выбрать изображение", "@selectImage": {}, + "selectLocation": "Выберите место", + "@selectLocation": {}, + "send": "Отправить", + "@send": {}, + "serialNumber": "Серийный номер", + "@serialNumber": {}, + "serialNumbers": "Серийные номера", + "@serialNumbers": {}, + "server": "Сервер", + "@server": {}, + "serverAddress": "Адрес сервера", + "@serverAddress": {}, + "serverApiRequired": "Требуемая версия API", + "@serverApiRequired": {}, + "serverApiVersion": "Версия API сервера", + "@serverApiVersion": {}, + "serverAuthenticationError": "Ошибка аутентификации", + "@serverAuthenticationError": {}, + "serverCertificateError": "Ошибка сертификата", + "@serverCertificateError": {}, + "serverCertificateInvalid": "HTTPS сертификат сервера недействителен", + "@serverCertificateInvalid": {}, + "serverConnected": "Подключён к серверу", + "@serverConnected": {}, + "serverConnecting": "Подключение к серверу", + "@serverConnecting": {}, + "serverCouldNotConnect": "Не удалось подключиться к серверу", + "@serverCouldNotConnect": {}, + "serverEmpty": "Поле сервера не может быть пустым", + "@serverEmpty": {}, + "serverError": "Ошибка сервера", + "@serverError": {}, + "serverDetails": "Подробнее о сервере", + "@serverDetails": {}, + "serverMissingData": "Отсутствуют обязательные поля ответа сервера", + "@serverMissingData": {}, + "serverOld": "Старая версия сервера", + "@serverOld": {}, + "serverSettings": "Настройки сервера", + "@serverSettings": {}, + "serverStart": "Сервер должен начинаться с http[s]", + "@serverStart": {}, + "settings": "Настройки", + "@settings": {}, + "serverInstance": "Экземпляр сервера", + "@serverInstance": {}, + "serverNotConnected": "Сервер не подключен", + "@serverNotConnected": {}, + "serverNotSelected": "Сервер не выбран", + "@serverNotSelected": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Звуки", + "@sounds": {}, + "soundOnBarcodeAction": "Воспроизвести звук при штрих-коде", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Воспроизвести звук при ошибке сервера", + "@soundOnServerError": {}, + "status": "Статус", + "@status": {}, + "statusCode": "Код статуса", + "@statusCode": {}, + "stock": "Склад", + "@stock": { + "description": "stock" + }, + "stockDetails": "Текущее количество на складе", + "@stockDetails": {}, + "stockItems": "Детали на складе", + "@stockItems": {}, + "stockItemCreate": "Новая деталь на складе", + "@stockItemCreate": {}, + "stockTopLevel": "Склад верхнего уровня", + "@stockTopLevel": {}, "website": "Сайт", "@website": {} } \ No newline at end of file From 138cae2da077c31945a1a78ed7ceba5bf3431e63 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 30 Jun 2023 22:42:59 +1000 Subject: [PATCH 390/746] Search improvements (#388) * Refactor search widget - visual improvements - Simplifications - Add refresh button - Improve search button * Track original search * fix BOM widget * Update release notes --- assets/release_notes.md | 2 +- lib/inventree/stock.dart | 11 +++- lib/widget/bom_list.dart | 6 +- lib/widget/category_display.dart | 43 ++---------- lib/widget/category_list.dart | 22 ++----- lib/widget/company_list.dart | 9 ++- lib/widget/location_display.dart | 37 +---------- lib/widget/location_list.dart | 22 ++----- lib/widget/paginator.dart | 94 ++++++++++++++++++++++----- lib/widget/part_detail.dart | 4 +- lib/widget/part_list.dart | 20 ++---- lib/widget/part_parameter_widget.dart | 10 +-- lib/widget/po_line_list.dart | 5 +- lib/widget/purchase_order_detail.dart | 4 +- lib/widget/purchase_order_list.dart | 21 ++---- lib/widget/refreshable_state.dart | 3 +- lib/widget/stock_item_history.dart | 10 +-- lib/widget/stock_list.dart | 22 ++----- lib/widget/supplier_part_list.dart | 24 ++----- 19 files changed, 158 insertions(+), 211 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index b1155f0..e709bd9 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,7 +2,7 @@ --- - Pre-fill stock location when transferring stock amount - +- UX improvements for searching data ### - 0.12.3 - June 2023 --- diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index f6cca99..22113d4 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -117,7 +117,16 @@ class InvenTreeStockItemHistory extends InvenTreeModel { } } - String get userString => getString("username", subKey: "user_detail"); + int? get user => getValue("user") as int?; + + String get userString { + + if (user != null) { + return getString("username", subKey: "user_detail"); + } else { + return ""; + } + } } diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index f1d867d..a39b277 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -80,7 +80,6 @@ class _BillOfMaterialsState extends RefreshableState { Expanded( child: PaginatedBomList( filters, - showSearch: showFilterOptions, isParentPart: widget.isParentComponent, ), ), @@ -95,10 +94,13 @@ class _BillOfMaterialsState extends RefreshableState { */ class PaginatedBomList extends PaginatedSearchWidget { - const PaginatedBomList(Map filters, {bool showSearch = false, this.isParentPart = true}) : super(filters: filters, showSearch: showSearch); + const PaginatedBomList(Map filters, {this.isParentPart = true}) : super(filters: filters); final bool isParentPart; + @override + String get searchTitle => L10().parts; + @override _PaginatedBomListState createState() => _PaginatedBomListState(); } diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 31ead03..261840a 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -30,8 +30,6 @@ class _CategoryDisplayState extends RefreshableState { _CategoryDisplayState(); - bool showFilterOptions = false; - @override String getAppBarTitle() => L10().partCategory; @@ -204,26 +202,12 @@ class _CategoryDisplayState extends RefreshableState { List tiles = [ getCategoryDescriptionCard(), - ListTile( - title: Text( - L10().subcategories, - style: TextStyle(fontWeight: FontWeight.bold) - ), - trailing: GestureDetector( - child: FaIcon(FontAwesomeIcons.filter), - onTap: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ), Expanded( child: PaginatedPartCategoryList( - { - "parent": widget.category?.pk.toString() ?? "null" - }, - showFilterOptions, + { + "parent": widget.category?.pk.toString() ?? "null" + }, + title: L10().subcategories, ), flex: 10, ) @@ -240,25 +224,8 @@ class _CategoryDisplayState extends RefreshableState { }; return [ - ListTile( - title: Text( - L10().parts, - style: TextStyle(fontWeight: FontWeight.bold), - ), - trailing: GestureDetector( - child: FaIcon(FontAwesomeIcons.filter), - onTap: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ), - ), Expanded( - child: PaginatedPartList( - filters, - showFilterOptions, - ), + child: PaginatedPartList(filters), flex: 10, ) ]; diff --git a/lib/widget/category_list.dart b/lib/widget/category_list.dart index 0686faf..c1c9551 100644 --- a/lib/widget/category_list.dart +++ b/lib/widget/category_list.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; @@ -26,32 +25,21 @@ class _PartCategoryListState extends RefreshableState { _PartCategoryListState(); - bool showFilterOptions = false; - - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - @override String getAppBarTitle() => L10().partCategories; @override Widget getBody(BuildContext context) { - return PaginatedPartCategoryList(widget.filters, showFilterOptions); + return PaginatedPartCategoryList(widget.filters); } } class PaginatedPartCategoryList extends PaginatedSearchWidget { - const PaginatedPartCategoryList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedPartCategoryList(Map filters, {String title = ""}) : super(filters: filters, title: title); + + @override + String get searchTitle => title.isNotEmpty ? title : L10().partCategories; @override _PaginatedPartCategoryListState createState() => _PaginatedPartCategoryListState(); diff --git a/lib/widget/company_list.dart b/lib/widget/company_list.dart index fe6ecca..a19762c 100644 --- a/lib/widget/company_list.dart +++ b/lib/widget/company_list.dart @@ -36,14 +36,19 @@ class _CompanyListWidgetState extends RefreshableState { @override Widget getBody(BuildContext context) { - return PaginatedCompanyList(widget.filters, true); + return PaginatedCompanyList(widget.title, widget.filters); } } class PaginatedCompanyList extends PaginatedSearchWidget { - const PaginatedCompanyList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedCompanyList(this.companyTitle, Map filters) : super(filters: filters); + + final String companyTitle; + + @override + String get searchTitle => companyTitle; @override _CompanyListState createState() => _CompanyListState(); diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index b76586d..f1da729 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -38,8 +38,6 @@ class _LocationDisplayState extends RefreshableState { final InvenTreeStockLocation? location; - bool showFilterOptions = false; - @override String getAppBarTitle() { return L10().stockLocation; @@ -345,26 +343,12 @@ class _LocationDisplayState extends RefreshableState { List detailTiles() { List tiles = [ locationDescriptionCard(), - ListTile( - title: Text( - L10().sublocations, - style: TextStyle(fontWeight: FontWeight.bold), - ), - trailing: GestureDetector( - child: FaIcon(FontAwesomeIcons.filter), - onTap: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ), Expanded( child: PaginatedStockLocationList( { "parent": location?.pk.toString() ?? "null", }, - showFilterOptions, + title: L10().sublocations, ), flex: 10, ) @@ -380,25 +364,8 @@ class _LocationDisplayState extends RefreshableState { }; return [ - ListTile( - title: Text( - L10().stock, - style: TextStyle(fontWeight: FontWeight.bold), - ), - trailing: GestureDetector( - child: FaIcon(FontAwesomeIcons.filter), - onTap: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ), - ), Expanded( - child: PaginatedStockItemList( - filters, - showFilterOptions, - ), + child: PaginatedStockItemList(filters), flex: 10, ) ]; diff --git a/lib/widget/location_list.dart b/lib/widget/location_list.dart index 73c992e..fe39659 100644 --- a/lib/widget/location_list.dart +++ b/lib/widget/location_list.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; @@ -27,33 +26,22 @@ class _StockLocationListState extends RefreshableState { final Map filters; - bool showFilterOptions = false; - - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - @override String getAppBarTitle() => L10().stockLocations; @override Widget getBody(BuildContext context) { - return PaginatedStockLocationList(filters, showFilterOptions); + return PaginatedStockLocationList(filters); } } class PaginatedStockLocationList extends PaginatedSearchWidget { - const PaginatedStockLocationList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedStockLocationList(Map filters, {String title = ""}) : super(filters: filters, title: title); + + @override + String get searchTitle => title.isNotEmpty ? title : L10().stockLocations; @override _PaginatedStockLocationListState createState() => _PaginatedStockLocationListState(); diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 70ef6cb..a08b749 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -19,11 +19,13 @@ import "package:inventree/widget/refreshable_state.dart"; */ abstract class PaginatedSearchWidget extends StatefulWidget { - const PaginatedSearchWidget({this.filters = const {}, this.showSearch = false}); + const PaginatedSearchWidget({this.filters = const {}, this.title = ""}); + + final String title; + + String get searchTitle => title; final Map filters; - - final bool showSearch; } @@ -34,6 +36,8 @@ abstract class PaginatedSearchState extends Sta static const _pageSize = 25; + bool showSearchWidget = false; + // Prefix for storing and loading pagination options // Override in implementing class String get prefix => "prefix_"; @@ -116,7 +120,7 @@ abstract class PaginatedSearchState extends Sta } // Update the (configurable) filters for this paginated list - Future _saveOrderingOptions(BuildContext context) async { + Future _setOrderingOptions(BuildContext context) async { // Retrieve stored setting dynamic _field = await orderingField(); dynamic _order = await orderingOrder(); @@ -281,7 +285,17 @@ abstract class PaginatedSearchState extends Sta // Include user search term if (searchTerm.isNotEmpty) { - params["search"] = "${searchTerm}"; + + String _search = searchTerm; + + // Include original search in search test + String original = params["original_search"] ?? ""; + + if (original.isNotEmpty) { + _search = "${original} ${_search}"; + } + + params["search"] = "${_search}"; } // Use custom query ordering if available @@ -369,9 +383,12 @@ abstract class PaginatedSearchState extends Sta @override Widget build (BuildContext context) { - List children = []; + List children = [ + buildTitleWidget(context), + Divider(), + ]; - if (widget.showSearch) { + if (showSearchWidget) { children.add(buildSearchInput(context)); } @@ -392,7 +409,7 @@ abstract class PaginatedSearchState extends Sta return NoResultsWidget(noResultsText); } ), - separatorBuilder: (context, item) => const Divider(height: 1), + separatorBuilder: (context, item) => const Divider(height: .1), ) ] ) @@ -405,17 +422,65 @@ abstract class PaginatedSearchState extends Sta ); } + /* + * Build the title widget for this list + */ + Widget buildTitleWidget(BuildContext context) { + + const double icon_size = 32; + + List _icons = []; + + if (filterOptions.isNotEmpty || orderingOptions.isNotEmpty) { + _icons.add(IconButton( + onPressed: () async { + _setOrderingOptions(context); + }, + icon: Icon(Icons.filter_alt, size: icon_size) + )); + } + + _icons.add(IconButton( + onPressed: () { + setState(() { + showSearchWidget = !showSearchWidget; + }); + }, + icon: Icon(showSearchWidget ? Icons.zoom_out : Icons.search, size: icon_size) + )); + + _icons.add(IconButton( + onPressed: () async { + updateSearchTerm(); + }, + icon: Icon(Icons.refresh, size: icon_size), + )); + + return ListTile( + title: Text( + widget.searchTitle, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text( + "${L10().results}: ${resultCount}", + style: TextStyle( + fontStyle: FontStyle.italic + ), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: _icons, + ), + ); + } + /* * Construct a search input text field for the user to enter a search term */ Widget buildSearchInput(BuildContext context) { return ListTile( - leading: orderingOptions.isEmpty ? null : GestureDetector( - child: Icon(Icons.filter_list, color: COLOR_ACTION, size: 32), - onTap: () async { - _saveOrderingOptions(context); - }, - ), trailing: GestureDetector( child: FaIcon( searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, @@ -435,7 +500,6 @@ abstract class PaginatedSearchState extends Sta }, decoration: InputDecoration( hintText: L10().search, - helperText: resultsString(), ), ) ); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 9376837..4943410 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -681,11 +681,11 @@ class _PartDisplayState extends RefreshableState { ).toList() ) ), - PaginatedStockItemList({"part": part.pk.toString()}, true) + PaginatedStockItemList({"part": part.pk.toString()}) ]; if (showParameters) { - tabs.add(PaginatedParameterList({"part": part.pk.toString()}, true)); + tabs.add(PaginatedParameterList({"part": part.pk.toString()})); } return tabs; diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index ba7c839..6def9b1 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/l10.dart"; @@ -38,21 +37,9 @@ class _PartListState extends RefreshableState { @override String getAppBarTitle() => title.isNotEmpty ? title : L10().parts; - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - @override Widget getBody(BuildContext context) { - return PaginatedPartList(filters, showFilterOptions); + return PaginatedPartList(filters); } } @@ -60,7 +47,10 @@ class _PartListState extends RefreshableState { class PaginatedPartList extends PaginatedSearchWidget { - const PaginatedPartList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedPartList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().parts; @override _PaginatedPartListState createState() => _PaginatedPartListState(); diff --git a/lib/widget/part_parameter_widget.dart b/lib/widget/part_parameter_widget.dart index d889be8..1196a4c 100644 --- a/lib/widget/part_parameter_widget.dart +++ b/lib/widget/part_parameter_widget.dart @@ -44,10 +44,7 @@ class _ParameterWidgetState extends RefreshableState { return Column( children: [ Expanded( - child: PaginatedParameterList( - filters, - false, - ) + child: PaginatedParameterList(filters) ) ], ); @@ -60,7 +57,10 @@ class _ParameterWidgetState extends RefreshableState { */ class PaginatedParameterList extends PaginatedSearchWidget { - const PaginatedParameterList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedParameterList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().parts; @override _PaginatedParameterState createState() => _PaginatedParameterState(); diff --git a/lib/widget/po_line_list.dart b/lib/widget/po_line_list.dart index 13946a1..27827f8 100644 --- a/lib/widget/po_line_list.dart +++ b/lib/widget/po_line_list.dart @@ -17,7 +17,10 @@ import "package:inventree/widget/progress.dart"; */ class PaginatedPOLineList extends PaginatedSearchWidget { - const PaginatedPOLineList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedPOLineList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().lineItems; @override _PaginatedPOLineListState createState() => _PaginatedPOLineListState(); diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 8b2b650..ba870a4 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -331,9 +331,9 @@ class _PurchaseOrderDetailState extends RefreshableState getTabs(BuildContext context) { return [ ListView(children: orderTiles(context)), - PaginatedPOLineList({"order": order.pk.toString()}, true), + PaginatedPOLineList({"order": order.pk.toString()}), // ListView(children: lineTiles(context)), - PaginatedStockItemList({"purchase_order": order.pk.toString()}, true), + PaginatedStockItemList({"purchase_order": order.pk.toString()}), ]; } diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index 913a7e2..cdb8b8b 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -31,23 +31,9 @@ class _PurchaseOrderListWidgetState extends RefreshableState filters; - bool showFilterOptions = false; - @override String getAppBarTitle() => L10().purchaseOrders; - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - @override List actionButtons(BuildContext context) { List actions = []; @@ -95,14 +81,17 @@ class _PurchaseOrderListWidgetState extends RefreshableState filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedPurchaseOrderList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().purchaseOrders; @override _PaginatedPurchaseOrderListState createState() => _PaginatedPurchaseOrderListState(); diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index e484265..2bfc573 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -270,8 +270,7 @@ abstract class RefreshableState extends State with appBar: buildAppBar(context, refreshableKey), drawer: getDrawer(context), floatingActionButton: buildSpeedDial(context), - floatingActionButtonLocation: FloatingActionButtonLocation - .miniEndDocked, + floatingActionButtonLocation: FloatingActionButtonLocation.miniEndDocked, body: RefreshIndicator( onRefresh: () async { refresh(context); diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index 3c3771e..b2829fd 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -22,8 +22,6 @@ class _StockItemHistoryDisplayState extends RefreshableState L10().stockItemHistory; @@ -36,7 +34,7 @@ class _StockItemHistoryDisplayState extends RefreshableState filters, bool showSearch) - : super(filters: filters, showSearch: showSearch); + const PaginatedStockHistoryList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().stockItemHistory; @override _PaginatedStockHistoryState createState() => _PaginatedStockHistoryState(); diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index dd657a7..b260b24 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; @@ -27,32 +26,21 @@ class _StockListState extends RefreshableState { final Map filters; - bool showFilterOptions = false; - @override String getAppBarTitle() => L10().stockItems; - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - @override Widget getBody(BuildContext context) { - return PaginatedStockItemList(filters, showFilterOptions); + return PaginatedStockItemList(filters); } } class PaginatedStockItemList extends PaginatedSearchWidget { - const PaginatedStockItemList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedStockItemList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().stockItems; @override _PaginatedStockItemListState createState() => _PaginatedStockItemListState(); diff --git a/lib/widget/supplier_part_list.dart b/lib/widget/supplier_part_list.dart index 4b9c18f..3674f66 100644 --- a/lib/widget/supplier_part_list.dart +++ b/lib/widget/supplier_part_list.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/l10.dart"; @@ -31,23 +30,9 @@ class _SupplierPartListState extends RefreshableState { @override String getAppBarTitle() => L10().supplierParts; - bool showFilterOptions = false; - @override - List appBarActions(BuildContext context) => [ - IconButton( - icon: FaIcon(FontAwesomeIcons.filter), - onPressed: () async { - setState(() { - showFilterOptions = !showFilterOptions; - }); - }, - ) - ]; - - @override - Widget getBody(BuildContext context) { - return PaginatedSupplierPartList(widget.filters, showFilterOptions); + Widget getBody(BuildContext context) { + return PaginatedSupplierPartList(widget.filters); } } @@ -55,7 +40,10 @@ class _SupplierPartListState extends RefreshableState { class PaginatedSupplierPartList extends PaginatedSearchWidget { - const PaginatedSupplierPartList(Map filters, bool showSearch) : super(filters: filters, showSearch: showSearch); + const PaginatedSupplierPartList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().supplierParts; @override _PaginatedSupplierPartListState createState() => _PaginatedSupplierPartListState(); From 036555747554f3f123906447b017570b3f4d727d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 2 Jul 2023 20:24:07 +1000 Subject: [PATCH 391/746] Tweaks for home page widget (#389) --- lib/widget/home.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/widget/home.dart b/lib/widget/home.dart index cb15711..5fa8a2e 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -320,9 +320,10 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr return Center( child: Column( children: [ + Spacer(), Image.asset( "assets/image/logo_transparent.png", - color: Colors.white.withOpacity(0.2), + color: Colors.white.withOpacity(0.05), colorBlendMode: BlendMode.modulate, scale: 0.5, ), @@ -340,8 +341,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } /* - * Return the main body widget for display. - * This depends on the current value of _tabIndex + * Return the main body widget for display */ @override Widget getBody(BuildContext context) { From 9277e18028f70afdad880fdf7179f98d71316c08 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Jul 2023 19:27:45 +1000 Subject: [PATCH 392/746] New Crowdin updates (#390) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Russian) * New translations app_en.arb (French) * New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/fr_FR/app_fr_FR.arb | 18 ++++++++++++++++++ lib/l10n/hu_HU/app_hu_HU.arb | 22 ++++++++++++++++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++++ 4 files changed, 46 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 0dca298..ed4598b 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Stock disponible", "@availableStock": {}, + "barcodes": "Codes-barres", + "@barcodes": {}, + "barcodeSettings": "Paramètres des Codes-barres", + "@barcodeSettings": {}, "barcodeAssign": "Affecter un code-barres", "@barcodeAssign": {}, "barcodeAssignDetail": "Scannez le code-barres personnalisé pour l'attribuer", @@ -74,6 +78,8 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Scanner pour attribuer un code-barres", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Délai de Numérisation des Codes-barres", + "@barcodeScanDelay": {}, "barcodeScanGeneral": "Scanner un code-barres InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scannez les éléments de stock dans cet l'emplacement", @@ -407,6 +413,14 @@ "@onOrder": {}, "onOrderDetails": "Articles en cours de commande", "@onOrderDetails": {}, + "orientation": "Orientation de l'Écran", + "@orientation": {}, + "orientationDetail": "Orientation de l'écran (nécessite un redémarrage)", + "@orientationDetail": {}, + "orientationLandscape": "Paysage", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -689,6 +703,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Serveur non sélectionné", "@serverNotSelected": {}, + "sku": "UGS", + "@sku": {}, "sounds": "Sons", "@sounds": {}, "soundOnBarcodeAction": "Jouer la tonalité sonore lors du scan du code-barres", @@ -837,6 +853,8 @@ "@translate": {}, "translateHelp": "Aidez à traduire l'application InvenTree", "@translateHelp": {}, + "unitPrice": "Prix unitaire", + "@unitPrice": {}, "units": "Unités", "@units": {}, "unknownResponse": "Réponse inconnue", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 924022c..1527f7b 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Elérhető készlet", "@availableStock": {}, + "barcodes": "Vonalkódok", + "@barcodes": {}, + "barcodeSettings": "Vonalkód beállítások", + "@barcodeSettings": {}, "barcodeAssign": "Vonalkód hozzárendelése", "@barcodeAssign": {}, "barcodeAssignDetail": "Egyedi vonalkód hozzárendelése", @@ -74,6 +78,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Vonalkód olvasási késleltetés", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Vonalkód olvasások közti késleltetés", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Készlet bevételezése erre a helyre", @@ -184,6 +192,8 @@ "@editLocation": {}, "editNotes": "Megjegyzések szerkesztése", "@editNotes": {}, + "editParameter": "Paraméter szerkesztése", + "@editParameter": {}, "editPart": "Alkatrész szerkesztése", "@editPart": { "description": "edit part" @@ -417,6 +427,16 @@ "@onOrder": {}, "onOrderDetails": "Alaktrészek beszállítás alatt", "@onOrderDetails": {}, + "orientation": "Képernyő tájolása", + "@orientation": {}, + "orientationDetail": "Képernyő tájolása, elforgatása (újraindítás szükséges)", + "@orientationDetail": {}, + "orientationLandscape": "Fekvő", + "@orientationLandscape": {}, + "orientationPortrait": "Álló", + "@orientationPortrait": {}, + "orientationSystem": "Rendszer", + "@orientationSystem": {}, "outstanding": "Kintlévő", "@outstanding": {}, "outstandingOrderDetail": "Hiányzó tételek megjelenítése", @@ -821,6 +841,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Készlet tétel teszt eredmények megjelenítése", + "@testResultsDetail": {}, "testResultAdd": "Teszt eredmény hozzáadása", "@testResultAdd": {}, "testResultNone": "Nincsenek teszt eredmények", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index d02fde7..1d61537 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -192,6 +192,8 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, + "editParameter": "Editar Parâmetro", + "@editParameter": {}, "editPart": "Editar a peça", "@editPart": { "description": "edit part" diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 7302a0b..08e959a 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -368,6 +368,8 @@ "@partSettings": {}, "partsStarred": "Детали с включёнными уведомлениями", "@partsStarred": {}, + "partCategory": "Категория детали", + "@partCategory": {}, "partCategoryTopLevel": "Категория детали верхнего уровня", "@partCategoryTopLevel": {}, "password": "Пароль", @@ -544,6 +546,8 @@ "@stockItemCreate": {}, "stockTopLevel": "Склад верхнего уровня", "@stockTopLevel": {}, + "subcategory": "Подкатегория:", + "@subcategory": {}, "website": "Сайт", "@website": {} } \ No newline at end of file From e39ab9ad78b03dc2b881c834e51b109dca435b49 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 5 Jul 2023 09:35:56 +1000 Subject: [PATCH 393/746] New Crowdin updates (#391) * New translations app_en.arb (German) * New translations app_en.arb (French) --- lib/l10n/de_DE/app_de_DE.arb | 40 ++++++++++++++++++++++++++++++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 16 +++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 32fdd56..9b3bae1 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -56,6 +56,10 @@ "@attention": {}, "availableStock": "Verfügbarer Lagerbestand", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode-Einstellungen", + "@barcodeSettings": {}, "barcodeAssign": "Barcode zuweisen", "@barcodeAssign": {}, "barcodeAssignDetail": "Eigenen Barcode scannen zum Zuweisen", @@ -108,6 +112,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Bestellung stornieren", + "@cancelOrder": {}, "category": "Kategorie", "@category": {}, "categoryCreate": "Neue Kategorie", @@ -144,6 +150,10 @@ "@customers": {}, "damaged": "Beschädigt", "@damaged": {}, + "darkMode": "Dunkles Design", + "@darkMode": {}, + "darkModeEnable": "Dunkles Design aktivieren", + "@darkModeEnable": {}, "delete": "Löschen", "@delete": {}, "deleteFailed": "Löschvorgang fehlgeschlagen", @@ -178,12 +188,16 @@ "@editLocation": {}, "editNotes": "Notizen bearbeiten", "@editNotes": {}, + "editParameter": "Parameter bearbeiten", + "@editParameter": {}, "editPart": "Teil bearbeiten", "@editPart": { "description": "edit part" }, "editItem": "Artikel bearbeiten", "@editItem": {}, + "editLineItem": "Position bearbeiten", + "@editLineItem": {}, "enterPassword": "Passwort eingeben", "@enterPassword": {}, "enterUsername": "Benutzername eingeben", @@ -200,6 +214,10 @@ "@errorDetails": {}, "errorFetch": "Fehler beim Abrufen der Daten vom Server", "@errorFetch": {}, + "errorUserRoles": "Fehler beim Abfragen der Benutzerrollen vom Server", + "@errorUserRoles": {}, + "errorPluginInfo": "Fehler beim Abfragen der Plugin-Daten vom Server", + "@errorPluginInfo": {}, "errorReporting": "Fehlerberichterstattung", "@errorReporting": {}, "errorReportUpload": "Fehlerberichte hochladen", @@ -307,6 +325,8 @@ "@inProduction": {}, "inProductionDetail": "Dieser Lagerbestand ist in der Produktion", "@inProductionDetail": {}, + "internalPart": "Internes Teil", + "@internalPart": {}, "invalidHost": "Ungültiger Hostname", "@invalidHost": {}, "invalidHostDetails": "Der angegebener Hostname ist ungültig", @@ -323,8 +343,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", "@invalidUsernamePassword": {}, + "issue": "Aufgeben", + "@issue": {}, "issueDate": "Ausstellungsdatum", "@issueDate": {}, + "issueOrder": "Bestellung aufgeben", + "@issueOrder": {}, "itemInLocation": "Artikel ist bereits in diesem Lagerort", "@itemInLocation": {}, "keywords": "Schlüsselwörter", @@ -363,6 +387,8 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturer": "Hersteller", + "@manufacturer": {}, "manufacturers": "Hersteller", "@manufacturers": {}, "missingData": "Fehlende Daten", @@ -393,6 +419,12 @@ "@onOrder": {}, "onOrderDetails": "Artikel wurde bestellt", "@onOrderDetails": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Ausstehend", + "@outstanding": {}, + "outstandingOrderDetail": "Ausstehende Artikel anzeigen", + "@outstandingOrderDetail": {}, "packaging": "Paket", "@packaging": {}, "packageName": "Paket-Name", @@ -491,8 +523,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Zum Erstellen oder Auswählen eines Profils tippen", "@profileTapToCreate": {}, + "projectCode": "Projektcode", + "@projectCode": {}, "purchaseOrder": "Bestellung", "@purchaseOrder": {}, + "purchaseOrderCreate": "Neue Bestellung", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Bestellung bearbeiten", "@purchaseOrderEdit": {}, "purchaseOrders": "Bestellungen", @@ -519,6 +555,8 @@ "@queryNoResults": {}, "received": "Empfangen", "@received": {}, + "receivedFilterDetail": "Empfangene Artikel anzeigen", + "@receivedFilterDetail": {}, "receiveItem": "Artikel erhalten", "@receiveItem": {}, "receivedItem": "Artikel wurde erhalten", @@ -631,6 +669,8 @@ "@send": {}, "serialNumber": "Seriennummer", "@serialNumber": {}, + "serialNumbers": "Seriennummern", + "@serialNumbers": {}, "server": "Server", "@server": {}, "serverAddress": "Serveradresse", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index ed4598b..1462207 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -80,6 +80,8 @@ "@barcodeScanAssign": {}, "barcodeScanDelay": "Délai de Numérisation des Codes-barres", "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Délai entre deux scans de code-barres", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Scanner un code-barres InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scannez les éléments de stock dans cet l'emplacement", @@ -190,6 +192,8 @@ "@editLocation": {}, "editNotes": "Modifier les notes", "@editNotes": {}, + "editParameter": "Modifier les Paramètres", + "@editParameter": {}, "editPart": "Modifier la pièce", "@editPart": { "description": "edit part" @@ -383,6 +387,8 @@ "@link": {}, "lost": "Perdu", "@lost": {}, + "manufacturer": "Fabricant", + "@manufacturer": {}, "manufacturers": "Fabricants", "@manufacturers": {}, "missingData": "Données manquantes", @@ -421,6 +427,10 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, + "outstanding": "En attente", + "@outstanding": {}, + "outstandingOrderDetail": "Afficher les commandes en attente", + "@outstandingOrderDetail": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -519,6 +529,8 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Appuyer pour créer ou sélectionner un profil", "@profileTapToCreate": {}, + "projectCode": "Code Projet", + "@projectCode": {}, "purchaseOrder": "Commande d’achat", "@purchaseOrder": {}, "purchaseOrderCreate": "Nouveau Bon de Commande", @@ -549,6 +561,8 @@ "@queryNoResults": {}, "received": "Reçu", "@received": {}, + "receivedFilterDetail": "Afficher les articles reçus", + "@receivedFilterDetail": {}, "receiveItem": "Articles reçus", "@receiveItem": {}, "receivedItem": "Article de stock reçu", @@ -661,6 +675,8 @@ "@send": {}, "serialNumber": "Numéro de série", "@serialNumber": {}, + "serialNumbers": "Numéros de Série", + "@serialNumbers": {}, "server": "Serveur", "@server": {}, "serverAddress": "Adresse du serveur", From 6fe23fa8469acdd5fd707bfaba0426331ee28e0a Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 5 Jul 2023 22:21:12 +1000 Subject: [PATCH 394/746] Update release notes (#392) * Update release notes * Fix typo --- assets/release_notes.md | 4 ++-- lib/widget/part_parameter_widget.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e709bd9..c830e57 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,9 +1,9 @@ -### 0.12.4 - +### 0.12.4 - July 2023 --- - Pre-fill stock location when transferring stock amount - UX improvements for searching data - +- Updated translations ### - 0.12.3 - June 2023 --- diff --git a/lib/widget/part_parameter_widget.dart b/lib/widget/part_parameter_widget.dart index 1196a4c..d2f19d5 100644 --- a/lib/widget/part_parameter_widget.dart +++ b/lib/widget/part_parameter_widget.dart @@ -60,7 +60,7 @@ class PaginatedParameterList extends PaginatedSearchWidget { const PaginatedParameterList(Map filters) : super(filters: filters); @override - String get searchTitle => L10().parts; + String get searchTitle => L10().parameters; @override _PaginatedParameterState createState() => _PaginatedParameterState(); diff --git a/pubspec.yaml b/pubspec.yaml index 9feed50..5e36065 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.3+70 +version: 0.12.4+71 environment: sdk: ">=2.19.5 <3.0.0" From 2babf27db5e2f4c339525e7808ff83d0524a0e23 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 7 Jul 2023 21:38:04 +1000 Subject: [PATCH 395/746] Sentry fix (#395) * Extra sentry diagnostics * Fix unit test * Unit test updates * More unit test updates --- lib/api_form.dart | 2 +- lib/inventree/sentry.dart | 12 +++++++++++- lib/main.dart | 2 ++ lib/user_profile.dart | 4 +++- test/barcode_test.dart | 2 +- test/user_profile_test.dart | 2 +- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index c64ec57..47640ad 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -586,8 +586,8 @@ class APIFormField { }); } + // Render a "related field" based on the "model" type Widget _renderRelatedField(dynamic item, bool selected, bool extended) { - // Render a "related field" based on the "model" type // Convert to JSON var data = Map.from((item ?? {}) as Map); diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index d8becd8..1d82ff0 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,6 +1,7 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; +import "package:one_context/one_context.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; @@ -148,7 +149,7 @@ Future sentryReportMessage(String message, {Map? context}) /* * Report an error message to sentry.io */ -Future sentryReportError(String source, dynamic error, dynamic stackTrace, {Map context = const {}}) async { +Future sentryReportError(String source, dynamic error, StackTrace? stackTrace, {Map context = const {}}) async { print("----- Sentry Intercepted error: $error -----"); print(stackTrace); @@ -192,6 +193,15 @@ Future sentryReportError(String source, dynamic error, dynamic stackTrace, // Ensure we pass the 'source' of the error context["source"] = source; + if (OneContext.hasContext) { + final ctx = OneContext().context; + + if (ctx != null) { + context["widget"] = ctx.widget.toString(); + context["widgetType"] = ctx.widget.runtimeType.toString(); + } + } + Sentry.configureScope((scope) { scope.setExtra("server", server_info); scope.setExtra("app", app_info); diff --git a/lib/main.dart b/lib/main.dart index 08b0a30..aa2adb6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -38,6 +38,8 @@ Future main() async { options.dsn = SENTRY_DSN_KEY; options.release = release; options.environment = isInDebugMode() ? "debug" : "release"; + options.diagnosticLevel = SentryLevel.debug; + options.attachStacktrace = true; }); // Pass any flutter errors off to the Sentry reporting context! diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 53d7c0d..e1b5446 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -98,7 +98,7 @@ class UserProfileDBManager { if (exists) { debug("addProfile() : UserProfile '${profile.name}' already exists"); - return false; + return true; } else { debug("Adding new profile: '${profile.name}'"); } @@ -137,6 +137,8 @@ class UserProfileDBManager { * Remove a user profile from the database */ Future deleteProfile(UserProfile profile) async { + debug("deleteProfile: ${profile.name}"); + await store.record(profile.key).delete(await _db); } diff --git a/test/barcode_test.dart b/test/barcode_test.dart index e896f44..e28715b 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -26,7 +26,7 @@ void main() { final prf = await UserProfileDBManager().getProfileByName("Test Profile"); if (prf != null) { - UserProfileDBManager().deleteProfile(prf); + await UserProfileDBManager().deleteProfile(prf); } bool result = await UserProfileDBManager().addProfile( diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 144a146..1da201f 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -79,7 +79,7 @@ void main() { ) ); - expect(result, equals(false)); + expect(result, equals(true)); // Check that the number of protocols available is still the same var profiles = await UserProfileDBManager().getAllProfiles(); From 637b058a8a0b4771ed007300a92653bdab7eff88 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 7 Jul 2023 21:47:15 +1000 Subject: [PATCH 396/746] New Crowdin updates (#393) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 94 ++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index af53074..b543606 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -56,8 +56,14 @@ "@attention": {}, "availableStock": "Stokta hazır", "@availableStock": {}, + "barcodes": "Barkod *", + "@barcodes": {}, + "barcodeSettings": "Barkod Ayarları", + "@barcodeSettings": {}, "barcodeAssign": "Barkod Ata", "@barcodeAssign": {}, + "barcodeAssignDetail": "Atamak için özel barkodu tarayın", + "@barcodeAssignDetail": {}, "barcodeAssigned": "Barkod atandı", "@barcodeAssigned": {}, "barcodeError": "Barkod tarama hatası", @@ -72,6 +78,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Barkod Tarama Gecikmesi", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Barkod taramaları arasındaki gecikme", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Bir Iventree barkodu tara", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Stok öğelerini konum içine tara", @@ -94,6 +104,10 @@ "@batchCode": {}, "billOfMaterials": "Fatura materyalleri", "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Malzeme Lisitesini Görüntüle", + "@bomEnable": {}, "build": "Oluştur", "@build": {}, "building": "Oluşturma", @@ -102,6 +116,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Siparişi İptal Et", + "@cancelOrder": {}, "category": "Kategori", "@category": {}, "categoryCreate": "Yeni Kategori", @@ -138,12 +154,20 @@ "@customers": {}, "damaged": "Hasarlı", "@damaged": {}, + "darkMode": "Koyu Mod", + "@darkMode": {}, + "darkModeEnable": "Karanlık modu etkinleştir", + "@darkModeEnable": {}, "delete": "Sil", "@delete": {}, + "deleteFailed": "Silme işlemi başarısız", + "@deleteFailed": {}, "deletePart": "Parça Sil", "@deletePart": {}, "deletePartDetail": "Bu parçayı veritabanından kaldır", "@deletePartDetail": {}, + "deleteSuccess": "Silme işlemi başarılı", + "@deleteSuccess": {}, "description": "Açıklama", "@description": {}, "destroyed": "Yok edildi", @@ -168,12 +192,16 @@ "@editLocation": {}, "editNotes": "Notları Düzenle", "@editNotes": {}, + "editParameter": "Parametre Düzenle", + "@editParameter": {}, "editPart": "Parçayı Düzenle", "@editPart": { "description": "edit part" }, "editItem": "Parçayı Düzenle", "@editItem": {}, + "editLineItem": "Satır Öğesini Düzenle", + "@editLineItem": {}, "enterPassword": "Şifrenizi girin", "@enterPassword": {}, "enterUsername": "Kullanıcı adını girin", @@ -190,6 +218,10 @@ "@errorDetails": {}, "errorFetch": "Sunucudan veri alınırken hata oluştu", "@errorFetch": {}, + "errorUserRoles": "Sunucudan kullanıcı rolleri istenirken hata oluştu", + "@errorUserRoles": {}, + "errorPluginInfo": "Sunucudan eklenti verileri istenirken hata oluştu", + "@errorPluginInfo": {}, "errorReporting": "Hata Raporlama", "@errorReporting": {}, "errorReportUpload": "Hata raporu yükle", @@ -206,12 +238,18 @@ "@filterActive": {}, "filterActiveDetail": "Aktif öğeleri göster", "@filterActiveDetail": {}, + "filterAssembly": "Birleştirilmiş", + "@filterAssembly": {}, + "filterAssemblyDetail": "Birleştirilmiş parçaları göster", + "@filterAssemblyDetail": {}, "filterComponent": "Bileşen", "@filterComponent": {}, "filterComponentDetail": "Bileşen parçalarını göster", "@filterComponentDetail": {}, "filterInStock": "Stokta mevcut", "@filterInStock": {}, + "filterInStockDetail": "Stoğu olan parçaları göster", + "@filterInStockDetail": {}, "filterSerialized": "Sıralandırılmış", "@filterSerialized": {}, "filterSerializedDetail": "Sıralandırılmış stok ürünkerini göster", @@ -275,8 +313,12 @@ "@inactiveDetail": {}, "includeSubcategories": "Alt kategorileri dahil et", "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Alt kategorideki sonuçları göster", + "@includeSubcategoriesDetail": {}, "includeSublocations": "Alt konumları dahil et", "@includeSublocations": {}, + "includeSublocationsDetail": "Alt konumdaki sonuçları göster", + "@includeSublocationsDetail": {}, "incompleteDetails": "Tamamlanmamış profil detayları", "@incompleteDetails": {}, "internalPartNumber": "İç Parça Numarası", @@ -287,6 +329,8 @@ "@inProduction": {}, "inProductionDetail": "Bu ürün üretim aşamasında", "@inProductionDetail": {}, + "internalPart": "İç Parça", + "@internalPart": {}, "invalidHost": "Geçersiz alan adı", "@invalidHost": {}, "invalidHostDetails": "Bu ana bilgisayar adı (hostname) geçerli değil", @@ -299,6 +343,8 @@ "@invalidStockLocation": {}, "invalidStockItem": "Geçersiz Stok Parçası", "@invalidStockItem": {}, + "invalidSupplierPart": "Geçersiz Tedarikçi Parçası", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", "@invalidUsernamePassword": {}, "issueDate": "Sorun Tarihi", @@ -307,6 +353,8 @@ "@itemInLocation": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, + "labelTemplate": "Etiket Şablonu", + "@labelTemplate": {}, "language": "Dil", "@language": {}, "languageDefault": "Varsayılan sistem dili", @@ -335,6 +383,8 @@ "@link": {}, "lost": "Kayıp", "@lost": {}, + "manufacturer": "Üretici", + "@manufacturer": {}, "manufacturers": "Üreticiler", "@manufacturers": {}, "missingData": "Eksik Veri", @@ -349,6 +399,8 @@ }, "notifications": "Bildirimler", "@notifications": {}, + "notificationsEmpty": "Okunmamış bildirim yok", + "@notificationsEmpty": {}, "noResponse": "Sunucudan yanıt yok", "@noResponse": {}, "noResults": "Sonuç Yok", @@ -363,10 +415,24 @@ "@onOrder": {}, "onOrderDetails": "Parça şuan siparişte", "@onOrderDetails": {}, + "orientation": "Ekran Yönü", + "@orientation": {}, + "orientationDetail": "Ekran yönü(Yeniden başlatma gerekir)", + "@orientationDetail": {}, + "orientationLandscape": "Yatay", + "@orientationLandscape": {}, + "orientationPortrait": "Dikey", + "@orientationPortrait": {}, + "orientationSystem": "Sistem", + "@orientationSystem": {}, "packaging": "Paketleme", "@packaging": {}, "packageName": "Paket İsmi", "@packageName": {}, + "parameters": "Parametreler", + "@parameters": {}, + "parametersSettingDetail": "Parça parametrelerini göster", + "@parametersSettingDetail": {}, "parent": "Üst", "@parent": {}, "parentCategory": "Üst Kategori", @@ -391,6 +457,8 @@ "@partsNone": {}, "partNoResults": "Sorguyla eşleşen parça yok", "@partNoResults": {}, + "partSettings": "Parça Ayarları", + "@partSettings": {}, "partsStarred": "Sürekli Gelen parçalar", "@partsStarred": {}, "partsStarredNone": "Yıldızlı parça yok", @@ -449,10 +517,16 @@ "@profileNotSelected": {}, "profileSelect": "InvenTree sunucusu seç", "@profileSelect": {}, + "profileSelectOrCreate": "Sunucu seçin veya yeni bir profil oluşturun", + "@profileSelectOrCreate": {}, "profileTapToCreate": "Yeni bir profil oluşturmak için tıklayın yada seçin", "@profileTapToCreate": {}, + "projectCode": "Proje Kodu", + "@projectCode": {}, "purchaseOrder": "Satınalma Siparişi", "@purchaseOrder": {}, + "purchaseOrderCreate": "Yeni Satınalma Emri", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Satın Alma siparişini düzenle", "@purchaseOrderEdit": {}, "purchaseOrders": "Satınalma Siparişleri", @@ -479,6 +553,8 @@ "@queryNoResults": {}, "received": "Alınan", "@received": {}, + "receivedFilterDetail": "Alınan öğeleri göster", + "@receivedFilterDetail": {}, "receiveItem": "Alınan Öğeler", "@receiveItem": {}, "receivedItem": "Alınan stok parçaları", @@ -509,6 +585,8 @@ "@results": {}, "request": "Talep", "@request": {}, + "requestFailed": "İstek Başarısız", + "@requestFailed": {}, "requestSuccessful": "İstek başarılı", "@requestSuccessful": {}, "requestingData": "Veri Talep Ediliyor", @@ -587,6 +665,8 @@ "@send": {}, "serialNumber": "Seri Numara", "@serialNumber": {}, + "serialNumbers": "Seri Numaraları", + "@serialNumbers": {}, "server": "Sunucu", "@server": {}, "serverAddress": "Sunucu Adresi", @@ -629,6 +709,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Sunucu bulunamadı", "@serverNotSelected": {}, + "sku": "Stok No", + "@sku": {}, "sounds": "Sesler", "@sounds": {}, "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", @@ -703,6 +785,10 @@ "@suppliedParts": {}, "supplier": "Tedarikçi", "@supplier": {}, + "supplierPart": "Tedarikçi Parçası", + "@supplierPart": {}, + "supplierParts": "Tedarikçi Parçaları", + "@supplierParts": {}, "suppliers": "Tedarikçiler", "@suppliers": {}, "supplierReference": "Tedarikçi Referansı", @@ -711,6 +797,8 @@ "@takePicture": {}, "targetDate": "Hedeflenen Tarih", "@targetDate": {}, + "templatePart": "Üst Şablon Parçası", + "@templatePart": {}, "testName": "Test Adı", "@testName": {}, "testPassedOrFailed": "Test başarılı veya hatalı", @@ -741,6 +829,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", "@tokenMissingFromResponse": {}, + "totalPrice": "Toplam Fiyat", + "@totalPrice": {}, "transfer": "Aktarım", "@transfer": { "description": "transfer" @@ -749,10 +839,14 @@ "@transferStock": { "description": "transfer stock" }, + "transferStockDetail": "Öğeyi farklı bir lokasyona aktarın", + "@transferStockDetail": {}, "translate": "Çeviri", "@translate": {}, "translateHelp": "Çeviriye yardım et", "@translateHelp": {}, + "unitPrice": "Birim Fiyat", + "@unitPrice": {}, "units": "Birim", "@units": {}, "unknownResponse": "Bilinmeyen Yanıt", From 7ef6da4b2aa6951074a3ef3398e2e2ec524e658d Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 7 Jul 2023 21:47:27 +1000 Subject: [PATCH 397/746] Add extra filtering options for stock items (#394) --- assets/release_notes.md | 7 +++++++ lib/l10n/app_en.arb | 9 +++++++++ lib/widget/stock_list.dart | 12 ++++++++++++ 3 files changed, 28 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index c830e57..9babb13 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,9 +1,16 @@ +### 0.12.5 - July 2023 +--- + +- Adds extra filtering options for stock items +- Updated translations + ### 0.12.4 - July 2023 --- - Pre-fill stock location when transferring stock amount - UX improvements for searching data - Updated translations + ### - 0.12.3 - June 2023 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 16dae59..3bef736 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -76,6 +76,9 @@ "attention": "Attention", "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", "@availableStock": {}, @@ -357,6 +360,12 @@ "filterComponentDetail": "Show component parts", "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", "@filterInStock": {}, diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart index b260b24..3fa474a 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock_list.dart @@ -69,6 +69,12 @@ class _PaginatedStockItemListState extends PaginatedSearchState> get filterOptions { Map> filters = { + "available": { + "default": null, + "label": L10().available, + "help_text": L10().availableStock, + "tristate": true, + }, "in_stock": { "default": true, "label": L10().filterInStock, @@ -81,6 +87,12 @@ class _PaginatedStockItemListState extends PaginatedSearchState Date: Fri, 7 Jul 2023 22:04:21 +1000 Subject: [PATCH 398/746] Bump version to 0.12.5 (#396) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 5e36065..256dd17 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.4+71 +version: 0.12.5+72 environment: sdk: ">=2.19.5 <3.0.0" From d78affc1cb86ddbbaa7c4feef7c97c0eccd615ec Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Jul 2023 22:05:10 +1000 Subject: [PATCH 399/746] New Crowdin updates (#397) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 +- lib/l10n/pt_BR/app_pt_BR.arb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 1462207..86e9d12 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -56,7 +56,7 @@ "@attention": {}, "availableStock": "Stock disponible", "@availableStock": {}, - "barcodes": "Codes-barres", + "barcodes": "Code-barres", "@barcodes": {}, "barcodeSettings": "Paramètres des Codes-barres", "@barcodeSettings": {}, diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 1d61537..db2fe7a 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Atenção", "@attention": {}, + "available": "Disponível", + "@available": {}, "availableStock": "Estoque Disponível", "@availableStock": {}, "barcodes": "Códigos de barras", @@ -246,6 +248,10 @@ "@filterComponent": {}, "filterComponentDetail": "Exibir peças componentes", "@filterComponentDetail": {}, + "filterExternal": "Externo", + "@filterExternal": {}, + "filterExternalDetail": "Mostrar estoque em locais externos", + "@filterExternalDetail": {}, "filterInStock": "Em Estoque", "@filterInStock": {}, "filterInStockDetail": "Exibir peças com estoque", From 443e6e856c8d8c2696c9d0d3102afb2f4bcc1372 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 16 Jul 2023 00:51:11 +1000 Subject: [PATCH 400/746] Label print updates (#399) * Allow download of printed label * Add setting for controlling label printing * Control display of label printing via setting * Refactor label printing functionality - Move to helpers.dart - Will be used for other label types also * Factor out request for label templates * Add label printing support for part * Support label printing for stock location * update release notes --- assets/release_notes.md | 6 ++ lib/helpers.dart | 4 +- lib/l10n/app_en.arb | 6 ++ lib/labels.dart | 155 +++++++++++++++++++++++++++++++ lib/preferences.dart | 2 + lib/settings/app_settings.dart | 23 ++++- lib/settings/settings.dart | 2 +- lib/widget/location_display.dart | 36 +++++++ lib/widget/part_detail.dart | 43 +++++++-- lib/widget/stock_detail.dart | 141 +++++----------------------- 10 files changed, 284 insertions(+), 134 deletions(-) create mode 100644 lib/labels.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 9babb13..ddf90a1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.12.6 - July 2023 +--- + +- Enable label printing for stock locations +- Enable label printing for parts + ### 0.12.5 - July 2023 --- diff --git a/lib/helpers.dart b/lib/helpers.dart index f958e6a..49a880d 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -9,6 +9,7 @@ import "dart:io"; import "package:currency_formatter/currency_formatter.dart"; + import "package:one_context/one_context.dart"; import "package:url_launcher/url_launcher.dart"; import "package:audioplayers/audioplayers.dart"; @@ -132,4 +133,5 @@ String renderCurrency(double? amount, String currency, {int decimals = 2}) { } return value; -} \ No newline at end of file +} + diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3bef736..9589f9b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -533,6 +533,12 @@ "keywords": "Keywords", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", "@labelTemplate": {}, diff --git a/lib/labels.dart b/lib/labels.dart new file mode 100644 index 0000000..ca4f8ad --- /dev/null +++ b/lib/labels.dart @@ -0,0 +1,155 @@ +import "package:flutter/cupertino.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api.dart"; +import "package:inventree/widget/progress.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/snacks.dart"; + +/* + * Discover which label templates are available for a given item + */ +Future>> getLabelTemplates( + String labelType, + Map data, +) async { + + if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) { + return []; + } + + // Filter by active plugins + data["enabled"] = "true"; + + List> labels = []; + + await InvenTreeAPI().get( + "/label/${labelType}/", + params: data, + ).then((APIResponse response) { + if (response.isValid() && response.statusCode == 200) { + for (var label in response.resultsList()) { + if (label is Map) { + labels.add(label); + } + } + } + }); + + return labels; +} + + +/* + * Select a particular label, from a provided list of options, + * and print against the selected instances. + */ +Future selectAndPrintLabel( + BuildContext context, + List> labels, + String labelType, + String labelQuery, + ) async { + + if (!InvenTreeAPI().isConnected()) { + return; + } + + // Find a list of available plugins which support label printing + var plugins = InvenTreeAPI().getPlugins(mixin: "labels"); + + dynamic initial_label; + dynamic initial_plugin; + + List> label_options = []; + List> plugin_options = []; + + // Construct list of available label templates + for (var label in labels) { + String display_name = (label["description"] ?? "").toString(); + int pk = (label["pk"] ?? -1) as int; + + if (display_name.isNotEmpty && pk > 0) { + label_options.add({ + "display_name": display_name, + "value": pk, + }); + } + } + + if (label_options.length == 1) { + initial_label = label_options.first["value"]; + } + + // Construct list of available plugins + for (var plugin in plugins) { + plugin_options.add({ + "display_name": plugin.humanName, + "value": plugin.key + }); + } + + if (plugin_options.length == 1) { + initial_plugin = plugin_options.first["value"]; + } + + Map fields = { + "label": { + "label": L10().labelTemplate, + "type": "choice", + "value": initial_label, + "choices": label_options, + "required": true, + }, + "plugin": { + "label": L10().pluginPrinter, + "type": "choice", + "value": initial_plugin, + "choices": plugin_options, + "required": true, + } + }; + + launchApiForm( + context, + L10().printLabel, + "", + fields, + icon: FontAwesomeIcons.print, + onSuccess: (Map data) async { + int labelId = (data["label"] ?? -1) as int; + String pluginKey = (data["plugin"] ?? "") as String; + + if (labelId != -1 && pluginKey.isNotEmpty) { + String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; + + showLoadingOverlay(context); + + InvenTreeAPI().get(url).then((APIResponse response) { + hideLoadingOverlay(); + if (response.isValid() && response.statusCode == 200) { + + var data = response.asMap(); + + if (data.containsKey("file")) { + var label_file = (data["file"] ?? "") as String; + + // Attempt to open remote file + InvenTreeAPI().downloadFile(label_file); + } else { + showSnackIcon( + L10().printLabelSuccess, + success: true + ); + } + } else { + showSnackIcon( + L10().printLabelFailure, + success: false, + ); + } + }); + } + }, + ); +} \ No newline at end of file diff --git a/lib/preferences.dart b/lib/preferences.dart index a7e8a30..5180152 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -25,6 +25,8 @@ const int SCREEN_ORIENTATION_LANDSCAPE = 2; const String INV_SOUNDS_BARCODE = "barcodeSounds"; const String INV_SOUNDS_SERVER = "serverSounds"; +const String INV_ENABLE_LABEL_PRINTING = "enableLabelPrinting"; + // Part settings const String INV_PART_SHOW_PARAMETERS = "partShowParameters"; const String INV_PART_SHOW_BOM = "partShowBom"; diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 00c27a7..1937ff5 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -1,18 +1,18 @@ import "package:flutter/material.dart"; +import "package:one_context/one_context.dart"; import "package:adaptive_theme/adaptive_theme.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; -import "package:inventree/app_colors.dart"; -import "package:inventree/widget/dialogs.dart"; -import "package:one_context/one_context.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/api_form.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/widget/dialogs.dart"; import "package:inventree/widget/progress.dart"; @@ -33,7 +33,7 @@ class _InvenTreeAppSettingsState extends State { bool reportErrors = true; bool strictHttps = false; - + bool enableLabelPrinting = true; bool darkMode = false; int screenOrientation = SCREEN_ORIENTATION_SYSTEM; @@ -56,6 +56,7 @@ class _InvenTreeAppSettingsState extends State { reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; screenOrientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; + enableLabelPrinting = await InvenTreeSettingsManager().getValue(INV_ENABLE_LABEL_PRINTING, true) as bool; darkMode = AdaptiveTheme.of(context).mode.isDark; @@ -218,6 +219,20 @@ class _InvenTreeAppSettingsState extends State { ); }, ), + ListTile( + title: Text(L10().labelPrinting), + subtitle: Text(L10().labelPrintingDetail), + leading: FaIcon(FontAwesomeIcons.print), + trailing: Switch( + value: enableLabelPrinting, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_ENABLE_LABEL_PRINTING, value); + setState(() { + enableLabelPrinting = value; + }); + } + ), + ), ListTile( title: Text(L10().strictHttps), subtitle: Text(L10().strictHttpsDetails), diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index f5b8e2d..8c42071 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -13,8 +13,8 @@ import "package:inventree/settings/login.dart"; import "package:inventree/settings/part_settings.dart"; +// InvenTree settings view class InvenTreeSettingsWidget extends StatefulWidget { - // InvenTree settings view @override _InvenTreeSettingsState createState() => _InvenTreeSettingsState(); diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index f1da729..a26ddc9 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -8,6 +8,7 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/location_list.dart"; import "package:inventree/widget/progress.dart"; @@ -15,6 +16,7 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_detail.dart"; import "package:inventree/widget/stock_list.dart"; +import "package:inventree/labels.dart"; /* @@ -38,6 +40,10 @@ class _LocationDisplayState extends RefreshableState { final InvenTreeStockLocation? location; + bool allowLabelPrinting = true; + + List> labels = []; + @override String getAppBarTitle() { return L10().stockLocation; @@ -163,6 +169,23 @@ class _LocationDisplayState extends RefreshableState { ); } + if (widget.location != null && allowLabelPrinting && labels.isNotEmpty) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.print), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel( + context, + labels, + "location", + "location=${widget.location!.pk}" + ); + } + ) + ); + } + return actions; } @@ -202,6 +225,19 @@ class _LocationDisplayState extends RefreshableState { } } + allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + + if (allowLabelPrinting) { + labels.clear(); + + if (widget.location != null) { + labels = await getLabelTemplates("location", { + "location": widget.location!.pk.toString() + }); + } + } + if (mounted) { setState(() {}); } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 4943410..d8a81b9 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -11,6 +11,7 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/bom.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/labels.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/attachment_widget.dart"; @@ -54,17 +55,16 @@ class _PartDisplayState extends RefreshableState { int parameterCount = 0; bool showParameters = false; - bool showBom = false; + bool allowLabelPrinting = true; int attachmentCount = 0; - int bomCount = 0; - int usedInCount = 0; - int variantCount = 0; + List> labels = []; + @override String getAppBarTitle() => L10().partDetails; @@ -110,12 +110,29 @@ class _PartDisplayState extends RefreshableState { List actions = []; if (InvenTreeStockItem().canCreate) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.box), + label: L10().stockItemCreate, + onTap: () { + _newStockItem(context); + } + ) + ); + } + + if (allowLabelPrinting && labels.isNotEmpty) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.box), - label: L10().stockItemCreate, - onTap: () { - _newStockItem(context); + child: FaIcon(FontAwesomeIcons.print), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel( + context, + labels, + "part", + "part=${widget.part.pk}" + ); } ) ); @@ -226,6 +243,16 @@ class _PartDisplayState extends RefreshableState { }); } }); + + allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + + if (allowLabelPrinting) { + labels.clear(); + labels = await getLabelTemplates("part", { + "part": widget.part.pk.toString(), + }); + } } void _editPartDialog(BuildContext context) { diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index c33c957..2b6f983 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -9,6 +9,7 @@ import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; +import "package:inventree/labels.dart"; import "package:inventree/preferences.dart"; import "package:inventree/inventree/company.dart"; @@ -127,13 +128,18 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (labels.isNotEmpty) { + if (allowLabelPrinting && labels.isNotEmpty) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.print), label: L10().printLabel, - onTap: () { - _printLabel(context); + onTap: () async { + selectAndPrintLabel( + context, + labels, + "stock", + "item=${widget.item.pk}" + ); } ) ); @@ -198,9 +204,10 @@ class _StockItemDisplayState extends RefreshableState { int attachmentCount = 0; + bool allowLabelPrinting = true; + @override Future onBuild(BuildContext context) async { - // Load part data if not already loaded if (part == null) { refresh(context); @@ -209,9 +216,7 @@ class _StockItemDisplayState extends RefreshableState { @override Future request(BuildContext context) async { - await api.StockStatus.load(); - stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; @@ -254,43 +259,20 @@ class _StockItemDisplayState extends RefreshableState { } }); + // Determine if label printing is supported + allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + // Request information on labels available for this stock item - if (InvenTreeAPI().pluginsEnabled()) { - _getLabels(); + if (allowLabelPrinting) { + // Clear the existing labels list + labels.clear(); + labels = await getLabelTemplates("stock", { + "item": widget.item.pk.toString() + }); } } - Future _getLabels() async { - // Clear the existing labels list - labels.clear(); - - // If the server does not support label printing, don't bother! - if (!InvenTreeAPI().supportsMixin("labels")) { - return; - } - - InvenTreeAPI().get( - "/label/stock/", - params: { - "enabled": "true", - "item": "${widget.item.pk}", - }, - ).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - - for (var label in response.resultsList()) { - if (label is Map) { - labels.add(label); - } - } - - if (mounted) { - setState(() {}); - } - } - }); - } - /// Delete the stock item from the database Future _deleteItem(BuildContext context) async { @@ -314,87 +296,6 @@ class _StockItemDisplayState extends RefreshableState { } - /// Opens a popup dialog allowing user to select a label for printing - Future _printLabel(BuildContext context) async { - - var plugins = InvenTreeAPI().getPlugins(mixin: "labels"); - - dynamic initial_label; - dynamic initial_plugin; - - List> label_options = []; - List> plugin_options = []; - - for (var label in labels) { - label_options.add({ - "display_name": label["description"], - "value": label["pk"], - }); - } - - for (var plugin in plugins) { - plugin_options.add({ - "display_name": plugin.humanName, - "value": plugin.key, - }); - } - - if (labels.length == 1) { - initial_label = labels.first["pk"]; - } - - if (plugins.length == 1) { - initial_plugin = plugins.first.key; - } - - Map fields = { - "label": { - "label": L10().labelTemplate, - "type": "choice", - "value": initial_label, - "choices": label_options, - "required": true, - }, - "plugin": { - "label": L10().pluginPrinter, - "type": "choice", - "value": initial_plugin, - "choices": plugin_options, - "required": true, - } - }; - - launchApiForm( - context, - L10().printLabel, - "", - fields, - icon: FontAwesomeIcons.print, - onSuccess: (Map data) async { - int labelId = (data["label"] ?? -1) as int; - String pluginKey = (data["plugin"] ?? "") as String; - - if (labelId != -1 && pluginKey.isNotEmpty) { - String url = "/label/stock/${labelId}/print/?item=${widget.item.pk}&plugin=${pluginKey}"; - - InvenTreeAPI().get(url).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - showSnackIcon( - L10().printLabelSuccess, - success: true - ); - } else { - showSnackIcon( - L10().printLabelFailure, - success: false, - ); - } - }); - } - }, - ); - } - Future _editStockItem(BuildContext context) async { var fields = InvenTreeStockItem().formFields(); From 3085d98ce1f904c90ac6ad43d5d44311948f8819 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 17 Jul 2023 20:59:39 +1000 Subject: [PATCH 401/746] New translations app_en.arb (Chinese Traditional) (#400) --- lib/l10n/zh_TW/app_zh_TW.arb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/l10n/zh_TW/app_zh_TW.arb diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb new file mode 100644 index 0000000..8d2f577 --- /dev/null +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "zh-TW", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file From 7a11fdead8c3492873fd5034eb85b9026c97c9c0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 17 Jul 2023 21:17:23 +1000 Subject: [PATCH 402/746] Tweaks (#401) * Improve collect_translations.py * Cleanup * Update translation support * Update release notes --- assets/release_notes.md | 1 + ios/Runner/Info.plist | 2 ++ lib/l10n/collect_translations.py | 8 ++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ddf90a1..300f7a2 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Enable label printing for stock locations - Enable label printing for parts +- Updated translation support ### 0.12.5 - July 2023 --- diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index d2611ef..5cd05c6 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -34,11 +34,13 @@ pt-BR pt-PT ru-RU + sl_SI sv-SE th-TH tr-TR vi-VN zh-CN + zh-TW CFBundleName InvenTree diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index 4f0182a..03148a6 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -91,12 +91,16 @@ def generate_locale_list(locales): with open("supported_locales.dart", "w") as output: output.write("// This file is auto-generated by the 'collect_translations.py' script - do not edit it directly!\n\n") - output.write('import "package:flutter/material.dart";\n\n') + output.write("const List supported_locales = [\n") - output.write("const List supported_locales = [\n"); + locales = sorted(locales) for locale in locales: + + if locale.startswith('.'): + continue + splt = locale.split("_") if len(splt) == 2: From 174f1b2f2dd3ddcad3f135407a465b40fa4929ac Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 21 Jul 2023 22:28:43 +1000 Subject: [PATCH 403/746] New Crowdin updates (#402) * New translations app_en.arb (Dutch) * New translations app_en.arb (Chinese Traditional) --- lib/l10n/nl_NL/app_nl_NL.arb | 10 ++ lib/l10n/zh_TW/app_zh_TW.arb | 191 ++++++++++++++++++++++++++++++++++- 2 files changed, 200 insertions(+), 1 deletion(-) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 6d20a3d..de53bff 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Let op", "@attention": {}, + "available": "Beschikbaar", + "@available": {}, "availableStock": "Beschikbare Voorraad", "@availableStock": {}, "barcodes": "Barcodes", @@ -246,6 +248,10 @@ "@filterComponent": {}, "filterComponentDetail": "Componentonderdelen weergeven", "@filterComponentDetail": {}, + "filterExternal": "Extern", + "@filterExternal": {}, + "filterExternalDetail": "Voorraad op externe locaties tonen", + "@filterExternalDetail": {}, "filterInStock": "Op voorraad", "@filterInStock": {}, "filterInStockDetail": "Toon onderdelen op voorraad", @@ -357,6 +363,10 @@ "@itemInLocation": {}, "keywords": "Trefwoorden", "@keywords": {}, + "labelPrinting": "Label afdrukken", + "@labelPrinting": {}, + "labelPrintingDetail": "Label afdrukken inschakelen", + "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, "language": "Taal", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 8d2f577..25fbb16 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -1,5 +1,194 @@ { "@@locale": "zh-TW", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "確認", + "@ok": { + "description": "OK" + }, + "about": "關於", + "@about": {}, + "accountDetails": "帳號詳情", + "@accountDetails": {}, + "actions": "操作", + "@actions": { + "description": "" + }, + "actionsNone": "沒有可用的操作", + "@actionsNone": {}, + "add": "新增", + "@add": { + "description": "add" + }, + "addStock": "新增庫存", + "@addStock": { + "description": "add stock" + }, + "address": "地址", + "@address": {}, + "appAbout": "關於InvenTree", + "@appAbout": {}, + "appCredits": "開發團隊", + "@appCredits": {}, + "appDetails": "應用程式詳情", + "@appDetails": {}, + "appReleaseNotes": "顯示應用程式發布說明", + "@appReleaseNotes": {}, + "appSettings": "程式設定", + "@appSettings": {}, + "attachments": "附件", + "@attachments": {}, + "attachImage": "附加影像", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "找不到附件", + "@attachmentNone": {}, + "attachmentNoneDetail": "找不到附件", + "@attachmentNoneDetail": {}, + "attachmentSelect": "選取附件", + "@attachmentSelect": {}, + "available": "可用", + "@available": {}, + "barcodes": "條碼", + "@barcodes": {}, + "billOfMaterials": "材料清單", + "@billOfMaterials": {}, + "bom": "材料清單", + "@bom": {}, + "bomEnable": "顯示材料清單", + "@bomEnable": {}, + "build": "生產", + "@build": {}, + "building": "生產中", + "@building": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "取消訂單", + "@cancelOrder": {}, + "category": "類別", + "@category": {}, + "categoryCreate": "新增類別", + "@categoryCreate": {}, + "company": "公司", + "@company": {}, + "companyEdit": "編輯公司", + "@companyEdit": {}, + "companies": "公司", + "@companies": {}, + "count": "數量", + "@count": { + "description": "Count" + }, + "countStock": "庫存數量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "感謝", + "@credits": {}, + "customers": "客戶", + "@customers": {}, + "darkMode": "暗黑模式", + "@darkMode": {}, + "darkModeEnable": "啟用夜間模式", + "@darkModeEnable": {}, + "delete": "刪除", + "@delete": {}, + "deletePart": "刪除零件", + "@deletePart": {}, + "description": "敘述", + "@description": {}, + "details": "詳細資訊", + "@details": { + "description": "details" + }, + "documentation": "文件", + "@documentation": {}, + "downloading": "下載檔案", + "@downloading": {}, + "downloadError": "下載錯誤", + "@downloadError": {}, + "edit": "編輯", + "@edit": { + "description": "edit" + }, + "editCategory": "編輯類別", + "@editCategory": {}, + "enterPassword": "輸入密碼", + "@enterPassword": {}, + "enterUsername": "輸入使用者名稱", + "@enterUsername": {}, + "error": "錯誤", + "@error": { + "description": "Error" + }, + "feedback": "回饋", + "@feedback": {}, + "filterActive": "啟用", + "@filterActive": {}, + "filterActiveDetail": "顯示可用的零件", + "@filterActiveDetail": {}, + "filterAssembly": "已組裝", + "@filterAssembly": {}, + "filterAssemblyDetail": "顯示已組裝的零件", + "@filterAssemblyDetail": {}, + "filterExternal": "外部", + "@filterExternal": {}, + "filterInStock": "有貨", + "@filterInStock": {}, + "filterTemplate": "範本", + "@filterTemplate": {}, + "filterTrackable": "可追蹤", + "@filterTrackable": {}, + "filterVirtual": "虛擬", + "@filterVirtual": {}, + "history": "歷史", + "@history": { + "description": "history" + }, + "home": "首頁", + "@homeScreen": {}, + "homeScreen": "主畫面", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowSuppliers": "顯示供應商", + "@homeShowSuppliers": {}, + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "顯示生產商", + "@homeShowManufacturers": {}, + "homeShowCustomers": "顯示客戶", + "@homeShowCustomers": {}, + "imageUploadFailure": "圖片上傳失敗", + "@imageUploadFailure": {}, + "imageUploadSuccess": "圖片上傳", + "@imageUploadSuccess": {}, + "inactive": "未啟用", + "@inactive": {}, + "info": "資訊", + "@info": {}, + "keywords": "關鍵字", + "@keywords": {}, + "labelPrinting": "標籤印製", + "@labelPrinting": {}, + "language": "語言", + "@language": {}, + "languageSelect": "選擇語言", + "@languageSelect": {}, + "notes": "備註", + "@notes": { + "description": "Notes" + }, + "notifications": "通知", + "@notifications": {}, + "parts": "零件", + "@parts": { + "description": "Part (multiple)" + }, + "stock": "庫存", + "@stock": { + "description": "stock" + } } \ No newline at end of file From 2e2e9640d4924269df366399fbe736c9e0f666b6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 22 Jul 2023 22:17:54 +1000 Subject: [PATCH 404/746] New translations app_en.arb (Hungarian) (#404) --- lib/l10n/hu_HU/app_hu_HU.arb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 1527f7b..46a2814 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Figyelem", "@attention": {}, + "available": "Elérhető", + "@available": {}, "availableStock": "Elérhető készlet", "@availableStock": {}, "barcodes": "Vonalkódok", @@ -246,6 +248,10 @@ "@filterComponent": {}, "filterComponentDetail": "Az összetevő alkatrészek megjelenítése", "@filterComponentDetail": {}, + "filterExternal": "Külső", + "@filterExternal": {}, + "filterExternalDetail": "Külső helyeken lévő készlet megjelenítése", + "@filterExternalDetail": {}, "filterInStock": "Készleten", "@filterInStock": {}, "filterInStockDetail": "Készleten lévő alkatrészek megjelenítése", @@ -357,6 +363,10 @@ "@itemInLocation": {}, "keywords": "Kulcsszavak", "@keywords": {}, + "labelPrinting": "Címke nyomtatás", + "@labelPrinting": {}, + "labelPrintingDetail": "Címke nyomtatás engedélyezése", + "@labelPrintingDetail": {}, "labelTemplate": "Címke sablon", "@labelTemplate": {}, "language": "Nyelv", From b044c53d91583d03b495d87a6637a0d5820230fd Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 23 Jul 2023 09:55:08 +1000 Subject: [PATCH 405/746] More debug (#405) * Extra options for sentry * Use string comparison * Catch error when constructing related field * Include field name in debug --- assets/release_notes.md | 1 + lib/api_form.dart | 57 ++++++++++++++++++++++++++--------------- pubspec.yaml | 4 +++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 300f7a2..5d6bb71 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ - Enable label printing for stock locations - Enable label printing for parts - Updated translation support +- Bug files ### 0.12.5 - July 2023 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index 47640ad..fb058a8 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -513,7 +513,7 @@ class APIFormField { isFilterOnline: true, showSearchBox: true, itemBuilder: (context, item, isSelected) { - return _renderRelatedField(item, isSelected, true); + return _renderRelatedField(name, item, isSelected, true); }, emptyBuilder: (context, item) { return _renderEmptyResult(); @@ -566,7 +566,7 @@ class APIFormField { } }, dropdownBuilder: (context, item) { - return _renderRelatedField(item, true, false); + return _renderRelatedField(name, item, true, false); }, onSaved: (item) { if (item != null) { @@ -582,15 +582,32 @@ class APIFormField { return false; } - return item["pk"] == selectedItem["pk"]; + return item["pk"].toString() == selectedItem["pk"].toString(); }); } // Render a "related field" based on the "model" type - Widget _renderRelatedField(dynamic item, bool selected, bool extended) { + Widget _renderRelatedField(String fieldName, dynamic item, bool selected, bool extended) { // Convert to JSON - var data = Map.from((item ?? {}) as Map); + Map data = {}; + + try { + data = Map.from((item ?? {}) as Map); + } catch (error, stackTrace) { + data = {}; + + sentryReportError( + "_renderRelatedField", error, stackTrace, + context: { + "method": "_renderRelateField", + "field_name": fieldName, + "item": item.toString(), + "selected": selected.toString(), + "extended": extended.toString(), + } + ); + } switch (model) { case "part": @@ -599,7 +616,7 @@ class APIFormField { return ListTile( title: Text( - part.fullname, + part.fullname, style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) ), subtitle: extended ? Text( @@ -615,8 +632,8 @@ class APIFormField { return ListTile( title: Text( - cat.pathstring, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + cat.pathstring, + style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) ), subtitle: extended ? Text( cat.description, @@ -629,7 +646,7 @@ class APIFormField { return ListTile( title: Text( - loc.pathstring, + loc.pathstring, style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) ), subtitle: extended ? Text( @@ -654,25 +671,25 @@ class APIFormField { case "company": var company = InvenTreeCompany.fromJson(data); return ListTile( - title: Text(company.name), - subtitle: extended ? Text(company.description) : null, - leading: InvenTreeAPI().getThumbnail(company.thumbnail) + title: Text(company.name), + subtitle: extended ? Text(company.description) : null, + leading: InvenTreeAPI().getThumbnail(company.thumbnail) ); case "projectcode": var project_code = InvenTreeProjectCode.fromJson(data); return ListTile( - title: Text(project_code.code), - subtitle: Text(project_code.description), - leading: FaIcon(FontAwesomeIcons.list) + title: Text(project_code.code), + subtitle: Text(project_code.description), + leading: FaIcon(FontAwesomeIcons.list) ); default: return ListTile( title: Text( - "Unsupported model", - style: TextStyle( - fontWeight: FontWeight.bold, - color: COLOR_DANGER - ) + "Unsupported model", + style: TextStyle( + fontWeight: FontWeight.bold, + color: COLOR_DANGER + ) ), subtitle: Text("Model '${model}' rendering not supported"), ); diff --git a/pubspec.yaml b/pubspec.yaml index 256dd17..754eac5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,3 +70,7 @@ flutter: - assets/sounds/barcode_scan.mp3 - assets/sounds/barcode_error.mp3 - assets/sounds/server_error.mp3 + +sentry: + upload_debug_symbols: true + upload_source_maps: true \ No newline at end of file From e549968d58b37b720b1bda6792cc2a6d8cf1f2f6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Jul 2023 12:43:34 +1000 Subject: [PATCH 406/746] Missed update to pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 754eac5..1fb2f36 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.5+72 +version: 0.12.6+73 environment: sdk: ">=2.19.5 <3.0.0" From d6460d58aa8aa3cafeff31f054caf2cd706cef42 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 27 Jul 2023 09:50:19 +1000 Subject: [PATCH 407/746] New Crowdin updates (#407) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_MX/app_es_MX.arb | 10 ++++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 1632104..1e0bd1a 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Atención", "@attention": {}, + "available": "Disponible", + "@available": {}, "availableStock": "Inventario Disponible", "@availableStock": {}, "barcodes": "Códigos de barras", @@ -192,6 +194,8 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, + "editParameter": "Editar parámetro", + "@editParameter": {}, "editPart": "Editar Parte", "@editPart": { "description": "edit part" @@ -244,6 +248,8 @@ "@filterComponent": {}, "filterComponentDetail": "Mostrar partes del componente", "@filterComponentDetail": {}, + "filterExternal": "Externo", + "@filterExternal": {}, "filterInStock": "En Existencia", "@filterInStock": {}, "filterInStockDetail": "Mostrar partes que tienen existencias", @@ -355,6 +361,10 @@ "@itemInLocation": {}, "keywords": "Palabras claves", "@keywords": {}, + "labelPrinting": "Impresión de etiquetas", + "@labelPrinting": {}, + "labelPrintingDetail": "Habilitar impresión de etiquetas", + "@labelPrintingDetail": {}, "labelTemplate": "Plantilla de etiqueta", "@labelTemplate": {}, "language": "Idioma", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index db2fe7a..4d8028a 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -363,6 +363,10 @@ "@itemInLocation": {}, "keywords": "Palavras chave", "@keywords": {}, + "labelPrinting": "Impressão de Etiqueta", + "@labelPrinting": {}, + "labelPrintingDetail": "Habilitar Impressão de Etiqueta", + "@labelPrintingDetail": {}, "labelTemplate": "Modelo de descricao", "@labelTemplate": {}, "language": "Idioma", From d2a01a0286960adf2d09afbb3dbdb38e660ef781 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 27 Jul 2023 10:16:36 +1000 Subject: [PATCH 408/746] Supplier part fix (#408) * Change supplier part fields based on API version * Display packaging info on supplier part page * Icon consolidation * Bump version number --- assets/release_notes.md | 5 +++++ lib/api_form.dart | 2 +- lib/inventree/company.dart | 22 ++++++++++++++++++++-- lib/widget/stock_detail.dart | 2 +- lib/widget/supplier_part_detail.dart | 12 ++++++++++++ pubspec.yaml | 2 +- 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 5d6bb71..99fc78f 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.12.7 - July 2023 +--- + +- Bug fix for Supplier Part editing page + ### 0.12.6 - July 2023 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index fb058a8..237b1d5 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -299,7 +299,7 @@ class APIFormField { default: return ListTile( title: Text( - "Unsupported field type: '${type}'", + "Unsupported field type: '${type}' for field '${name}'", style: TextStyle( color: COLOR_DANGER, fontStyle: FontStyle.italic), diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 78f83d3..032ee41 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -122,14 +122,22 @@ class InvenTreeSupplierPart extends InvenTreeModel { @override Map formFields() { - return { + Map fields = { "supplier": {}, "SKU": {}, "link": {}, "note": {}, "packaging": {}, - "pack_size": {}, }; + + // At some point, pack_size was changed to pack_quantity + if (InvenTreeAPI().apiVersion < 117) { + fields["pack_size"] = {}; + } else { + fields["pack_quantity"] = {}; + } + + return fields; } Map _filters() { @@ -178,6 +186,16 @@ class InvenTreeSupplierPart extends InvenTreeModel { String get note => getString("note"); + String get packaging => getString("packaging"); + + String get pack_quantity { + if (InvenTreeAPI().apiVersion < 117) { + return getString("pack_size"); + } else { + return getString("pack_quantity"); + } + } + @override InvenTreeModel createFromJson(Map json) => InvenTreeSupplierPart.fromJson(json); } diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 2b6f983..9e2f517 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -636,7 +636,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().packaging), subtitle: Text(widget.item.packaging), - leading: FaIcon(FontAwesomeIcons.box), + leading: FaIcon(FontAwesomeIcons.boxesPacking), ) ); } diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index 9821bfb..fe39c80 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -192,6 +192,18 @@ class _SupplierPartDisplayState extends RefreshableState=2.19.5 <3.0.0" From 72f243e1a51c31cef027af5bade0fd5f7f6805a4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 8 Aug 2023 20:30:44 +1000 Subject: [PATCH 409/746] New Crowdin updates (#409) * New translations app_en.arb (Swedish) * New translations app_en.arb (Hindi) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Russian) * New translations app_en.arb (Russian) * New translations app_en.arb (Russian) * New translations app_en.arb (Russian) * New translations app_en.arb (Vietnamese) --- lib/l10n/hi_IN/app_hi_IN.arb | 5 + lib/l10n/ru_RU/app_ru_RU.arb | 221 +++++++++++++++++++++++++- lib/l10n/sv_SE/app_sv_SE.arb | 110 +++++++++++++ lib/l10n/vi_VN/app_vi_VN.arb | 300 ++++++++++++++++++++++++++++++++++- 4 files changed, 629 insertions(+), 7 deletions(-) create mode 100644 lib/l10n/hi_IN/app_hi_IN.arb diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb new file mode 100644 index 0000000..213d5df --- /dev/null +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "hi", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 08e959a..16a5473 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -54,21 +54,23 @@ "@attachmentSelect": {}, "attention": "Внимание", "@attention": {}, + "available": "Доступно", + "@available": {}, "availableStock": "Доступный запас", "@availableStock": {}, "barcodes": "Штрих-коды", "@barcodes": {}, "barcodeSettings": "Настройки штрих-кодов", "@barcodeSettings": {}, - "barcodeAssign": "Прикрепить штрих-код", + "barcodeAssign": "Назначить штрих-код", "@barcodeAssign": {}, - "barcodeAssignDetail": "Сканируйте пользовательский штрих-код для назначения", + "barcodeAssignDetail": "Просканировать пользовательский штрих-код для назначения", "@barcodeAssignDetail": {}, "barcodeAssigned": "Штрих-код назначен", "@barcodeAssigned": {}, "barcodeError": "Ошибка сканирования штрих-кода", "@barcodeError": {}, - "barcodeInUse": "Штрих-код уже был назначен", + "barcodeInUse": "Штрих-код уже назначен", "@barcodeInUse": {}, "barcodeMissingHash": "Данные хэша штрих-кода отсутствуют в ответе", "@barcodeMissingHash": {}, @@ -96,7 +98,7 @@ "@barcodeTones": {}, "barcodeUnassign": "Отменить назначение штрих-кода", "@barcodeUnassign": {}, - "barcodeUnknown": "Штрихкод не распознан", + "barcodeUnknown": "Штрих-код не распознан", "@barcodeUnknown": {}, "batchCode": "Код партии", "@batchCode": {}, @@ -146,6 +148,8 @@ "@countStock": { "description": "Count Stock" }, + "credits": "Авторы", + "@credits": {}, "customers": "Покупатели", "@customers": {}, "damaged": "Поврежденный", @@ -172,6 +176,8 @@ "@details": { "description": "details" }, + "documentation": "Документация", + "@documentation": {}, "downloading": "Загрузка файла", "@downloading": {}, "downloadError": "Ошибка загрузки", @@ -186,6 +192,8 @@ "@editLocation": {}, "editNotes": "Редактировать примечания", "@editNotes": {}, + "editParameter": "Редактировать параметр", + "@editParameter": {}, "editPart": "Ред. эту часть", "@editPart": { "description": "edit part" @@ -202,16 +210,64 @@ }, "errorCreate": "Ошибка создания записи базы данных", "@errorCreate": {}, + "errorDelete": "Ошибка удаления записи базы данных", + "@errorDelete": {}, "errorDetails": "Подробнее об ошибке", "@errorDetails": {}, "errorFetch": "Ошибка при получении данных с сервера", "@errorFetch": {}, + "errorUserRoles": "Ошибка запроса ролей пользователя с сервера", + "@errorUserRoles": {}, + "errorPluginInfo": "Ошибка при получении данных плагина с сервера", + "@errorPluginInfo": {}, + "errorReporting": "Уведомление об ошибках", + "@errorReporting": {}, + "errorReportUpload": "Отправка отчётов об ошибках", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Загружать анонимные отчеты об ошибках и журналы сбоев", + "@errorReportUploadDetails": {}, "feedback": "Обратная Связь", "@feedback": {}, "feedbackError": "Ошибка отправки отзыва", "@feedbackError": {}, "feedbackSuccess": "Отзыв отправлен", "@feedbackSuccess": {}, + "filterActive": "Активный", + "@filterActive": {}, + "filterActiveDetail": "Показать активные элементы", + "@filterActiveDetail": {}, + "filterAssembly": "Собрано", + "@filterAssembly": {}, + "filterAssemblyDetail": "Показать собранные детали", + "@filterAssemblyDetail": {}, + "filterComponent": "Компонент", + "@filterComponent": {}, + "filterComponentDetail": "Показывать части компонента", + "@filterComponentDetail": {}, + "filterExternal": "Внешний", + "@filterExternal": {}, + "filterExternalDetail": "Показывать запасы во внешних местах", + "@filterExternalDetail": {}, + "filterInStock": "В наличии", + "@filterInStock": {}, + "filterInStockDetail": "Показать запасы на складе", + "@filterInStockDetail": {}, + "filterSerialized": "Упорядочено", + "@filterSerialized": {}, + "filterTemplate": "Шаблон", + "@filterTemplate": {}, + "filterTemplateDetail": "Показать шаблоны компонентов", + "@filterTemplateDetail": {}, + "filterTrackable": "Отслеживаемый", + "@filterTrackable": {}, + "filterTrackableDetail": "Показать отслеживаемые компоненты", + "@filterTrackableDetail": {}, + "filterVirtual": "Виртуальный", + "@filterVirtual": {}, + "filterVirtualDetail": "Показать виртуальные компоненты", + "@filterVirtualDetail": {}, + "filteringOptions": "Настройки фильтрации", + "@filteringOptions": {}, "formatException": "Формат исключения", "@formatException": {}, "formatExceptionJson": "Ошибка формата JSON", @@ -222,8 +278,31 @@ "@history": { "description": "history" }, + "home": "Главная", + "@homeScreen": {}, + "homeScreen": "Начальный экран", + "homeScreenSettings": "Настройка главной страницы", + "@homeScreenSettings": {}, + "homeShowPo": "Показать заказы на поставку", + "@homeShowPo": {}, + "homeShowSubscribed": "Детали с включёнными уведомлениями", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Показывать детали, на которые включены уведомления, на главной странице", "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Показать кнопку заказа заказа на главной станице", + "@homeShowPoDescription": {}, + "homeShowSuppliers": "Показать поставщиков", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Отображение кнопки поставщиков на главном экране", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Показать производителей", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Показывать кнопку производителей на главном экране", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Показать заказчиков", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Показывать кнопку покупателя на главном экране", + "@homeShowCustomersDescription": {}, "imageUploadFailure": "Не удалось загрузить изображение", "@imageUploadFailure": {}, "imageUploadSuccess": "Изображение загружено", @@ -234,14 +313,24 @@ "@inactiveDetail": {}, "includeSubcategories": "Включить подкатегории", "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Показать результаты из подкатегорий", + "@includeSubcategoriesDetail": {}, "includeSublocations": "Добавить доп. местоположения", "@includeSublocations": {}, + "includeSublocationsDetail": "Показывать результаты по подпунктам", + "@includeSublocationsDetail": {}, "incompleteDetails": "Неполные данные профиля", "@incompleteDetails": {}, "internalPartNumber": "Внутренний номер", "@internalPartNumber": {}, "info": "Информация", "@info": {}, + "inProduction": "В процессе производства", + "@inProduction": {}, + "inProductionDetail": "Данный объект находится в производстве", + "@inProductionDetail": {}, + "internalPart": "Внутренний компонент", + "@internalPart": {}, "invalidHost": "Неверное имя хоста", "@invalidHost": {}, "invalidHostDetails": "Недопустимый пароль", @@ -254,6 +343,8 @@ "@invalidStockLocation": {}, "invalidStockItem": "Недопустимый товарный пункт", "@invalidStockItem": {}, + "invalidSupplierPart": "Неверная деталь поставщика", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", "@invalidUsernamePassword": {}, "issueDate": "Дата проблемы", @@ -262,6 +353,12 @@ "@itemInLocation": {}, "keywords": "Ключевые слова", "@keywords": {}, + "labelPrinting": "Печать этикеток", + "@labelPrinting": {}, + "labelPrintingDetail": "Включить печать этикеток", + "@labelPrintingDetail": {}, + "labelTemplate": "Шаблон этикетки", + "@labelTemplate": {}, "language": "Язык", "@language": {}, "languageDefault": "Язык системы по умолчанию", @@ -372,6 +469,10 @@ "@partCategory": {}, "partCategoryTopLevel": "Категория детали верхнего уровня", "@partCategoryTopLevel": {}, + "partCategories": "Категории деталей", + "@partCategories": {}, + "partDetails": "Информация о детали", + "@partDetails": {}, "password": "Пароль", "@password": {}, "passwordEmpty": "Пароль не может быть пустым", @@ -412,6 +513,56 @@ "@profileNotSelected": {}, "profileSelect": "Выбрать сервер InvenTree", "@profileSelect": {}, + "profileSelectOrCreate": "Выбрать сервер или создать новый профиль", + "@profileSelectOrCreate": {}, + "purchasePrice": "Закупочная цена", + "@purchasePrice": {}, + "quantity": "Количество", + "@quantity": { + "description": "Quantity" + }, + "queryEmpty": "Введите поисковой запрос", + "@queryEmpty": {}, + "queryNoResults": "Нет результатов по запросу", + "@queryNoResults": {}, + "refresh": "Обновить", + "@refresh": {}, + "refreshing": "Обновление…", + "@refreshing": {}, + "rejected": "Отклонено", + "@rejected": {}, + "releaseNotes": "Заметки о выпуске", + "@releaseNotes": {}, + "remove": "Удалить", + "@remove": { + "description": "remove" + }, + "removeStock": "Удалить запасы", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Сообщить об ошибке", + "@reportBug": {}, + "reportBugDescription": "Отправить сообщение об ошибке (требуется учетная запись GitHub)", + "@reportBugDescription": {}, + "results": "Результатов", + "@results": {}, + "request": "Запрос", + "@request": {}, + "requestFailed": "Ошибка запроса", + "@requestFailed": {}, + "requestSuccessful": "Запрос выполнен успешно", + "@requestSuccessful": {}, + "requestingData": "Запрос данных", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Некорректный запрос", + "@response400": {}, + "response401": "Неавторизован", + "@response401": {}, "response403": "Доступ запрещён", "@response403": {}, "response404": "Ресурс не найден", @@ -454,6 +605,8 @@ "@scanBarcode": {}, "scanIntoLocation": "Сканировать в местоположение", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Отсканировать этот компонент в местоположение", + "@scanIntoLocationDetail": {}, "search": "Поиск", "@search": { "description": "search" @@ -526,9 +679,9 @@ "@sku": {}, "sounds": "Звуки", "@sounds": {}, - "soundOnBarcodeAction": "Воспроизвести звук при штрих-коде", + "soundOnBarcodeAction": "Воспроизводить звуковой сигнал при действиях со штрих-кодом", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Воспроизвести звук при ошибке сервера", + "soundOnServerError": "Воспроизводить звуковой сигнал при ошибке сервера", "@soundOnServerError": {}, "status": "Статус", "@status": {}, @@ -540,14 +693,70 @@ }, "stockDetails": "Текущее количество на складе", "@stockDetails": {}, + "stockItem": "Компонент на складе", + "@stockItem": { + "description": "stock item title" + }, "stockItems": "Детали на складе", "@stockItems": {}, "stockItemCreate": "Новая деталь на складе", "@stockItemCreate": {}, + "stockItemCreateDetail": "Создать новый компонент в этом месте", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Удалить складскую позицию", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Вы уверены, что хотите удалить этот элемент Bom?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Не удалось удалить позицию", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Компонент на складе удален", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "История запасов", + "@stockItemHistory": {}, "stockTopLevel": "Склад верхнего уровня", "@stockTopLevel": {}, + "strictHttpsDetails": "Принудительная проверка HTTPs сертификатов", + "@strictHttpsDetails": {}, "subcategory": "Подкатегория:", "@subcategory": {}, + "subcategories": "Подкатегории", + "@subcategories": {}, + "tokenError": "Ошибка токена", + "@tokenError": {}, + "tokenMissing": "Отсутствует токен", + "@tokenMissing": {}, + "tokenMissingFromResponse": "В ответе отсутствует токен доступа", + "@tokenMissingFromResponse": {}, + "totalPrice": "Общая стоимость", + "@totalPrice": {}, + "transferStockLocation": "Изменить местоположение склада", + "@transferStockLocation": {}, + "translate": "Перевод", + "@translate": {}, + "translateHelp": "Помочь перевести приложение InvenTree", + "@translateHelp": {}, + "unitPrice": "Цена за ед.", + "@unitPrice": {}, + "units": "Единицы измерения", + "@units": {}, + "unknownResponse": "Неизвестный ответ", + "@unknownResponse": {}, + "upload": "Загрузить", + "@upload": {}, + "uploadFailed": "Не удалось загрузить файл", + "@uploadFailed": {}, + "uploadSuccess": "Файл загружен", + "@uploadSuccess": {}, + "usedIn": "Используется в", + "@usedIn": {}, + "usedInDetails": "Сборки, для которых требуется эта часть", + "@usedInDetails": {}, + "username": "Имя пользователя", + "@username": {}, + "usernameEmpty": "Имя пользователя не может быть пустым", + "@usernameEmpty": {}, + "version": "Версия", + "@version": {}, "website": "Сайт", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 80e8669..865f222 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -1,5 +1,115 @@ { "@@locale": "sv-SE", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Om", + "@about": {}, + "accountDetails": "Kontouppgifter", + "@accountDetails": {}, + "actions": "Åtgärder", + "@actions": { + "description": "" + }, + "actionsNone": "Inga åtgärder tillgängliga", + "@actionsNone": {}, + "add": "Lägg till", + "@add": { + "description": "add" + }, + "addStock": "Lägg till i lager", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "Om InvenTree", + "@appAbout": {}, + "appCredits": "Ytterligare appkrediter", + "@appCredits": {}, + "appDetails": "Appdetaljer", + "@appDetails": {}, + "appReleaseNotes": "Visa versionsinfo för app", + "@appReleaseNotes": {}, + "appSettings": "Appinställningar", + "@appSettings": {}, + "appSettingsDetails": "Konfigurera inställningar för InvenTree app", + "@appSettingsDetails": {}, + "attachments": "Bilagor", + "@attachments": {}, + "attachImage": "Bifoga bild", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Inga bilagor hittades", + "@attachmentNone": {}, + "attachmentNoneDetail": "Inga bilagor hittades", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Välj bilagor", + "@attachmentSelect": {}, + "attention": "Obs!", + "@attention": {}, + "available": "Tillgänglig", + "@available": {}, + "availableStock": "Tillgängligt lager", + "@availableStock": {}, + "barcodes": "Streckkoder", + "@barcodes": {}, + "barcodeSettings": "Streckkods-inställningar", + "@barcodeSettings": {}, + "barcodeAssign": "Tilldela streckkod", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Skanna anpassad streckkod för att tilldela", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Streckkod tilldelad!", + "@barcodeAssigned": {}, + "barcodeError": "Fel vid skanning av streckkod", + "@barcodeError": {}, + "barcodeInUse": "Streckkoden används redan", + "@barcodeInUse": {}, + "build": "Bygg", + "@build": {}, + "downloadError": "Nedladdningsfel", + "@downloadError": {}, + "edit": "Ändra", + "@edit": { + "description": "edit" + }, + "editCategory": "Ändra Kategori", + "@editCategory": {}, + "editLocation": "Ändra plats", + "@editLocation": {}, + "editNotes": "Redigera anteckningar", + "@editNotes": {}, + "editParameter": "Editera parametrar", + "@editParameter": {}, + "editPart": "Redigera artikel", + "@editPart": { + "description": "edit part" + }, + "editItem": "Ändra lagerartikel", + "@editItem": {}, + "editLineItem": "Redigera radobjekt", + "@editLineItem": {}, + "enterPassword": "Ange lösenord", + "@enterPassword": {}, + "enterUsername": "Ange användarnamn", + "@enterUsername": {}, + "error": "Fel", + "@error": { + "description": "Error" + }, + "errorCreate": "Fel vid skapande av databaspost", + "@errorCreate": {}, + "errorDelete": "Fel vid radering av databaspost", + "@errorDelete": {}, + "errorDetails": "Felinformation", + "@errorDetails": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 802d954..f158eaf 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -54,8 +54,14 @@ "@attachmentSelect": {}, "attention": "Chú ý", "@attention": {}, + "available": "Sẵn có", + "@available": {}, "availableStock": "Số lượng có sẵn", "@availableStock": {}, + "barcodes": "Mã vạch", + "@barcodes": {}, + "barcodeSettings": "Cài đặt mã vạch", + "@barcodeSettings": {}, "barcodeAssign": "Gán mã vạch", "@barcodeAssign": {}, "barcodeAssignDetail": "Quét mã vạch tùy chỉnh để gán", @@ -74,6 +80,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Quét để gán mã vạch", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Độ trễ quét mã vạch", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Thời gian trễ giữa lần quét mã vạch", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Quét mã vạch InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Quét các mặt hàng trong kho vào vị trí này", @@ -86,6 +96,8 @@ "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "Quét mặt hàng tồn kho", "@barcodeScanItem": {}, + "barcodeTones": "Âm mã mạch", + "@barcodeTones": {}, "barcodeUnassign": "Gỡ mã vạch", "@barcodeUnassign": {}, "barcodeUnknown": "Mã vạch không xác định", @@ -100,6 +112,8 @@ "@bomEnable": {}, "build": "Nhiệm vụ", "@build": {}, + "building": "Tòa nhà", + "@building": {}, "cancel": "Hủy bỏ", "@cancel": { "description": "Cancel" @@ -150,6 +164,12 @@ "@delete": {}, "deleteFailed": "Thao tác xóa đã thất bại", "@deleteFailed": {}, + "deletePart": "Xóa phần", + "@deletePart": {}, + "deletePartDetail": "Xóa một phần ra khỏi cơ sở dữ liệu", + "@deletePartDetail": {}, + "deleteSuccess": "Thao tác xóa thành công", + "@deleteSuccess": {}, "description": "Mô tả", "@description": {}, "details": "Chi tiết", @@ -158,8 +178,64 @@ }, "documentation": "Tài liệu", "@documentation": {}, + "downloading": "Tập tin đang tải xuống", + "@downloading": {}, + "downloadError": "Tải xuống lỗi", + "@downloadError": {}, + "edit": "Sửa", + "@edit": { + "description": "edit" + }, + "editCategory": "Sửa Danh mục", + "@editCategory": {}, + "editLocation": "Sửa địa điểm", + "@editLocation": {}, + "editNotes": "Sửa ghi chú", + "@editNotes": {}, + "editParameter": "Sửa đổi tham số", + "@editParameter": {}, + "editPart": "Chỉnh sửa phần", + "@editPart": { + "description": "edit part" + }, + "editItem": "Chỉnh sửa tình trạng kho hàng", + "@editItem": {}, + "editLineItem": "Sửa dòng sản phẩm", + "@editLineItem": {}, + "enterPassword": "Nhập mật khẩu", + "@enterPassword": {}, + "enterUsername": "Nhập tên người dùng", + "@enterUsername": {}, + "error": "Lỗi", + "@error": { + "description": "Error" + }, + "errorDetails": "Chi tiết lỗi", + "@errorDetails": {}, + "errorReporting": "Báo cáo lỗi", + "@errorReporting": {}, + "errorReportUpload": "Tải lên các báo cáo lỗi", + "@errorReportUpload": {}, + "feedback": "Phản hồi", + "@feedback": {}, + "feedbackError": "Lỗi gửi phản hồi", + "@feedbackError": {}, + "feedbackSuccess": "Gửi phản hồi", + "@feedbackSuccess": {}, + "filterActive": "Hoạt động", + "@filterActive": {}, + "filterInStock": "Còn hàng", + "@filterInStock": {}, + "filterTemplate": "Mẫu", + "@filterTemplate": {}, "filterVirtual": "Ảo", "@filterVirtual": {}, + "filteringOptions": "Tùy chọn bộ lọc", + "@filteringOptions": {}, + "history": "Lịch sử", + "@history": { + "description": "history" + }, "home": "Trang chủ", "@homeScreen": {}, "homeScreen": "Màn hình chính", @@ -174,8 +250,16 @@ "@homeShowCustomers": {}, "inactive": "Không hoạt động", "@inactive": {}, + "invalidHost": "Tên máy chủ không hợp lệ", + "@invalidHost": {}, + "issue": "Vấn đề", + "@issue": {}, "keywords": "Từ khóa", "@keywords": {}, + "labelPrinting": "In nhãn mã vạch", + "@labelPrinting": {}, + "labelTemplate": "Khuôn mẫu nhãn tem", + "@labelTemplate": {}, "language": "Ngôn ngữ", "@language": {}, "languageDefault": "Ngôn ngữ hệ thống mặc định", @@ -184,16 +268,230 @@ "@languageSelect": {}, "level": "Cấp độ", "@level": {}, + "locationCreate": "Vị trí mới", + "@locationCreate": {}, + "link": "Liên kết", + "@link": {}, + "manufacturerPartNumber": "Mã số nhà sản xuất", + "@manufacturerPartNumber": {}, + "manufacturer": "Nhà sản xuất", + "@manufacturer": {}, + "manufacturers": "Nhà sản xuất", + "@manufacturers": {}, + "missingData": "Dữ liệu còn thiếu", + "@missingData": {}, + "name": "Tên", + "@name": {}, + "notConnected": "Không được kết nối", + "@notConnected": {}, + "notes": "Ghi chú", + "@notes": { + "description": "Notes" + }, + "notifications": "Thông báo", + "@notifications": {}, + "notificationsEmpty": "Không có thông báo chưa đọc", + "@notificationsEmpty": {}, + "noResponse": "Không có phản hồi từ máy chủ", + "@noResponse": {}, + "noResults": "Không có kết quả", + "@noResults": {}, + "noSubcategories": "Không có danh mục con", + "@noSubcategories": {}, + "numberInvalid": "Số không hợp lệ", + "@numberInvalid": {}, + "orientationSystem": "Hệ thống", + "@orientationSystem": {}, + "packageName": "Tên gói", + "@packageName": {}, "parameters": "Thông số", "@parameters": {}, "parametersSettingDetail": "Hiển thị các thông số", "@parametersSettingDetail": {}, + "parentCategory": "Danh mục cha", + "@parentCategory": {}, "parts": "Phụ tùng", "@parts": { "description": "Part (multiple)" }, "partsNone": "Không có phụ tùng", "@partsNone": {}, + "password": "Mật khẩu", + "@password": {}, + "passwordEmpty": "Mật khẩu không được để trống", + "@passwordEmpty": {}, + "permissionRequired": "Yêu cầu quyền truy cập", + "@permissionRequired": {}, + "pluginPrinter": "Máy in", + "@pluginPrinter": {}, + "profile": "Hồ sơ", + "@profile": {}, + "profileAdd": "Thêm mới cấu hình máy chủ", + "@profileAdd": {}, + "profileConnect": "Kết nối tới máy chủ", + "@profileConnect": {}, + "profileEdit": "Chỉnh sửa cấu hình máy chủ", + "@profileEdit": {}, + "profileDelete": "Xóa cấu hình máy chủ", + "@profileDelete": {}, + "purchaseOrder": "Đơn hàng", + "@purchaseOrder": {}, + "quantity": "Số lượng", + "@quantity": { + "description": "Quantity" + }, + "queryEmpty": "Nhập nội dung cần tìm", + "@queryEmpty": {}, + "queryNoResults": "Không có kết quả nào", + "@queryNoResults": {}, + "refresh": "Làm mới", + "@refresh": {}, + "refreshing": "Đang làm mới", + "@refreshing": {}, + "remove": "Xóa", + "@remove": { + "description": "remove" + }, + "results": "Kết quả", + "@results": {}, + "request": "Yêu cầu", + "@request": {}, + "requestFailed": "Yêu cầu không được hoàn thành", + "@requestFailed": {}, + "requestSuccessful": "Yêu cầu thành công", + "@requestSuccessful": {}, + "requestingData": "Đang yêu cầu dữ liệu", + "@requestingData": {}, + "required": "Bắt buộc", + "@required": { + "description": "This field is required" + }, + "response400": "Yêu cầu không hợp lệ", + "@response400": {}, + "response403": "Quyền truy cập bị từ chối", + "@response403": {}, + "response404": "Tài nguyên không tìm thấy", + "@response404": {}, + "response405": "Phương thức không được phép", + "@response405": {}, + "response500": "Lỗi máy chủ nội bộ", + "@response500": {}, + "response501": "Không được thực hiện", + "@response501": {}, + "response502": "Cổng không hợp lệ", + "@response502": {}, + "response504": "Gateway quá hạn", + "@response504": {}, + "response505": "Phiên bản của HTTP không được hỗ trợ", + "@response505": {}, + "result": "Kết quả", + "@result": { + "description": "" + }, + "returned": "Trả lại", + "@returned": {}, + "save": "Lưu lại", + "@save": { + "description": "Save" + }, + "scanBarcode": "Quét mã vạch", + "@scanBarcode": {}, + "search": "Tìm kiếm", + "@search": { + "description": "search" + }, + "searching": "Đang tìm kiếm", + "@searching": {}, + "searchLocation": "Vị trí tìm kiếm", + "@searchLocation": {}, "searchParts": "Tìm kiếm phụ tùng", - "@searchParts": {} + "@searchParts": {}, + "searchStock": "Tìm kiếm có sẵn", + "@searchStock": {}, + "select": "Chọn", + "@select": {}, + "selectFile": "Chọn file", + "@selectFile": {}, + "selectImage": "Chọn ảnh", + "@selectImage": {}, + "send": "Gửi", + "@send": {}, + "serialNumber": "Số sê-ri", + "@serialNumber": {}, + "serialNumbers": "Số sê-ri", + "@serialNumbers": {}, + "server": "Máy chủ", + "@server": {}, + "serverAddress": "Địa chỉ máy chủ", + "@serverAddress": {}, + "serverApiRequired": "Yêu cầu phiên bản máy chủ API", + "@serverApiRequired": {}, + "serverApiVersion": "Phiên bản máy chủ API", + "@serverApiVersion": {}, + "serverAuthenticationError": "Lỗi xác thực", + "@serverAuthenticationError": {}, + "serverCertificateInvalid": "Chứng chỉ máy chủ HTTPS không hợp lệ", + "@serverCertificateInvalid": {}, + "serverConnected": "Đã kết nối với máy chủ", + "@serverConnected": {}, + "serverConnecting": "Đang kết nối tới máy chủ", + "@serverConnecting": {}, + "serverCouldNotConnect": "Không thể kết nối đến máy chủ", + "@serverCouldNotConnect": {}, + "serverEmpty": "Máy chủ không thể để trống", + "@serverEmpty": {}, + "serverError": "Lỗi máy chủ", + "@serverError": {}, + "serverDetails": "Thông tin máy chủ", + "@serverDetails": {}, + "serverOld": "Phiên bản máy chủ cũ", + "@serverOld": {}, + "serverSettings": "Cài đặt máy chủ", + "@serverSettings": {}, + "settings": "Cài đặt", + "@settings": {}, + "sku": "Mã sản phẩm", + "@sku": {}, + "sounds": "Âm thanh", + "@sounds": {}, + "status": "Trạng thái", + "@status": {}, + "stock": "Kho hàng", + "@stock": { + "description": "stock" + }, + "strictHttps": "Sử dụng HTTPS nghiêm ngặt", + "@strictHttps": {}, + "submitFeedback": "Gửi phản hồi", + "@submitFeedback": {}, + "takePicture": "Chụp ảnh", + "@takePicture": {}, + "tokenError": "Lỗi Token", + "@tokenError": {}, + "totalPrice": "Tổng tiền", + "@totalPrice": {}, + "translate": "Dịch", + "@translate": {}, + "units": "Đơn vị", + "@units": {}, + "upload": "Tải lên", + "@upload": {}, + "uploadFailed": "Tập tin tải lên không thành công", + "@uploadFailed": {}, + "username": "Tên người dùng", + "@username": {}, + "usernameEmpty": "Tên người dùng không được để trống", + "@usernameEmpty": {}, + "value": "Giá trị", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Giá trị không thể để trống", + "@valueCannotBeEmpty": {}, + "valueRequired": "Giá trị là bắt buộc", + "@valueRequired": {}, + "version": "Phiên bản", + "@version": {}, + "website": "Trang web", + "@website": {} } \ No newline at end of file From 75c4e038f4674808eee8a02b59ccab71ac5f581d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 9 Aug 2023 21:57:41 +1000 Subject: [PATCH 410/746] New translations app_en.arb (Vietnamese) (#410) --- lib/l10n/vi_VN/app_vi_VN.arb | 421 ++++++++++++++++++++++++++++++++++- 1 file changed, 417 insertions(+), 4 deletions(-) diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index f158eaf..245014c 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -4,7 +4,7 @@ "@appTitle": { "description": "InvenTree application title string" }, - "ok": "Đồng Ý", + "ok": "Đồng ý", "@ok": { "description": "OK" }, @@ -12,7 +12,7 @@ "@about": {}, "accountDetails": "Thông tin tài khoản", "@accountDetails": {}, - "actions": "Hành động", + "actions": "Chức năng", "@actions": { "description": "" }, @@ -22,7 +22,7 @@ "@add": { "description": "add" }, - "addStock": "Thêm tồn kho", + "addStock": "Thêm kho", "@addStock": { "description": "add stock" }, @@ -120,7 +120,7 @@ }, "cancelOrder": "Hủy đơn hàng", "@cancelOrder": {}, - "category": "Thể loại", + "category": "Danh mục", "@category": {}, "categoryCreate": "Danh mục mới", "@categoryCreate": {}, @@ -172,6 +172,8 @@ "@deleteSuccess": {}, "description": "Mô tả", "@description": {}, + "destroyed": "Đã hủy", + "@destroyed": {}, "details": "Chi tiết", "@details": { "description": "details" @@ -210,12 +212,24 @@ "@error": { "description": "Error" }, + "errorCreate": "Lỗi tạo mục cơ sở dữ liệu", + "@errorCreate": {}, + "errorDelete": "Lỗi xóa mục cơ sở dữ liệu", + "@errorDelete": {}, "errorDetails": "Chi tiết lỗi", "@errorDetails": {}, + "errorFetch": "Lỗi gọi dữ liệu từ máy chủ", + "@errorFetch": {}, + "errorUserRoles": "Lỗi yêu cầu vai trò người dùng từ máy chủ", + "@errorUserRoles": {}, + "errorPluginInfo": "Lỗi yêu cầu thông tin plugin từ máy chủ", + "@errorPluginInfo": {}, "errorReporting": "Báo cáo lỗi", "@errorReporting": {}, "errorReportUpload": "Tải lên các báo cáo lỗi", "@errorReportUpload": {}, + "errorReportUploadDetails": "Tải lên nhật ký bị treo hệ thống và báo cáo lỗi nặc danh", + "@errorReportUploadDetails": {}, "feedback": "Phản hồi", "@feedback": {}, "feedbackError": "Lỗi gửi phản hồi", @@ -224,14 +238,42 @@ "@feedbackSuccess": {}, "filterActive": "Hoạt động", "@filterActive": {}, + "filterActiveDetail": "Hiển thị phụ kiện đang hoạt động", + "@filterActiveDetail": {}, + "filterAssembly": "Đã lắp ráp", + "@filterAssembly": {}, + "filterAssemblyDetail": "Hiện các phụ kiện đã lắp ráp", + "@filterAssemblyDetail": {}, + "filterComponent": "Thành phần", + "@filterComponent": {}, + "filterComponentDetail": "Hiện phụ kiện thành phần", + "@filterComponentDetail": {}, + "filterExternal": "Bên ngoài", + "@filterExternal": {}, + "filterExternalDetail": "Hiện kho hàng tại điểm bán bên ngoài", + "@filterExternalDetail": {}, "filterInStock": "Còn hàng", "@filterInStock": {}, + "filterInStockDetail": "Hiển thị các mặt hàng có trong kho", + "@filterInStockDetail": {}, "filterTemplate": "Mẫu", "@filterTemplate": {}, + "filterTemplateDetail": "Hiển thị các phần template", + "@filterTemplateDetail": {}, + "filterTrackable": "Có thể theo dõi", + "@filterTrackable": {}, + "filterTrackableDetail": "Hiển thị phụ kiện đang theo dõi", + "@filterTrackableDetail": {}, "filterVirtual": "Ảo", "@filterVirtual": {}, "filteringOptions": "Tùy chọn bộ lọc", "@filteringOptions": {}, + "formatException": "Định dạng ngoại lệ", + "@formatException": {}, + "formatExceptionJson": "Định dạng dữ liệu Json ngoại lệ", + "@formatExceptionJson": {}, + "formError": "Lỗi form", + "@formError": {}, "history": "Lịch sử", "@history": { "description": "history" @@ -239,25 +281,80 @@ "home": "Trang chủ", "@homeScreen": {}, "homeScreen": "Màn hình chính", + "homeScreenSettings": "Cấu hình thiết lập màn hình chính", + "@homeScreenSettings": {}, + "homeShowPo": "Hiển thị đơn đặt hàng mới", + "@homeShowPo": {}, + "homeShowSubscribed": "Đăng kí phụ kiện", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Hiển thị các phần đã đăng kí trên màn hình chính", "@homeShowSubscsribedDescription": {}, + "homeShowPoDescription": "Hiển thị đơn hàng mới tại màn hình chính", + "@homeShowPoDescription": {}, "homeShowSuppliers": "Hiện nhà cung cấp", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Hiện nút nhà cung cấp tại màn hình chính", "@homeShowSupplierDescription": {}, "homeShowManufacturers": "Hiện nhà sản xuất", "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Hiển thị nhà sản xuất tại màn hình chính", + "@homeShowManufacturersDescription": {}, "homeShowCustomers": "Hiện khách hàng", "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Hiển thị khách hàng tại màn hình chính", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Tải ảnh không thành công", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Tải ảnh lên", + "@imageUploadSuccess": {}, "inactive": "Không hoạt động", "@inactive": {}, + "inactiveDetail": "Phần này được đánh dấu là không hoạt động", + "@inactiveDetail": {}, + "includeSubcategories": "Bao gồm danh mục con", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Hiển thị kết quả trong danh mục", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Bao gồm kho phụ", + "@includeSublocations": {}, + "includeSublocationsDetail": "Hiển thị kết quả trong kho phụ", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Chi tiết profile không đầy đủ", + "@incompleteDetails": {}, + "internalPartNumber": "Số thứ tự phụ kiện nội bộ", + "@internalPartNumber": {}, + "info": "Thông tin", + "@info": {}, + "inProduction": "Đang sản xuất", + "@inProduction": {}, + "inProductionDetail": "Mặt hàng này đang được sản xuất tại kho", + "@inProductionDetail": {}, "invalidHost": "Tên máy chủ không hợp lệ", "@invalidHost": {}, + "invalidHostDetails": "Tên máy chủ được cung cấp không hợp lệ", + "@invalidHostDetails": {}, + "invalidPart": "Phụ kiện không hợp lệ", + "@invalidPart": {}, + "invalidStockLocation": "Vị trí kho không hợp lệ", + "@invalidStockLocation": {}, + "invalidStockItem": "Kho hàng không hợp lệ", + "@invalidStockItem": {}, + "invalidUsernamePassword": "Tên người dùng / mật khẩu không hợp lệ", + "@invalidUsernamePassword": {}, "issue": "Vấn đề", "@issue": {}, + "issueDate": "Ngày phát hành", + "@issueDate": {}, + "issueOrder": "Vấn đề đơn hàng", + "@issueOrder": {}, + "itemInLocation": "Vị trí mục đã có", + "@itemInLocation": {}, "keywords": "Từ khóa", "@keywords": {}, "labelPrinting": "In nhãn mã vạch", "@labelPrinting": {}, + "labelPrintingDetail": "Bật in nhãn tem", + "@labelPrintingDetail": {}, "labelTemplate": "Khuôn mẫu nhãn tem", "@labelTemplate": {}, "language": "Ngôn ngữ", @@ -266,12 +363,34 @@ "@languageDefault": {}, "languageSelect": "Chọn ngôn ngữ", "@languageSelect": {}, + "lastStocktake": "Kiểm kê cuối cùng", + "@lastStocktake": {}, + "lastUpdated": "Cập nhật mới nhất", + "@lastUpdated": {}, "level": "Cấp độ", "@level": {}, + "lineItem": "Sản phẩm", + "@lineItem": {}, + "lineItems": "Sản phẩm", + "@lineItems": {}, + "lineItemUpdated": "Sản phẩm đã được cập nhật", + "@lineItemUpdated": {}, + "locateItem": "Xác định vị trí hàng tồn kho", + "@locateItem": {}, + "locateLocation": "Xác định vị trí kho", + "@locateLocation": {}, "locationCreate": "Vị trí mới", "@locationCreate": {}, + "locationCreateDetail": "Thêm mới vị trí kho hàng", + "@locationCreateDetail": {}, + "locationNotSet": "Không xác định được vị trí", + "@locationNotSet": {}, + "locationUpdated": "Cập nhật vị trí kho hàng", + "@locationUpdated": {}, "link": "Liên kết", "@link": {}, + "lost": "Mất", + "@lost": {}, "manufacturerPartNumber": "Mã số nhà sản xuất", "@manufacturerPartNumber": {}, "manufacturer": "Nhà sản xuất", @@ -298,32 +417,98 @@ "@noResults": {}, "noSubcategories": "Không có danh mục con", "@noSubcategories": {}, + "noSubcategoriesAvailable": "Không có sẵn danh mục", + "@noSubcategoriesAvailable": {}, "numberInvalid": "Số không hợp lệ", "@numberInvalid": {}, + "onOrder": "Bật đơn hàng", + "@onOrder": {}, + "onOrderDetails": "Các mặt hàng hiện đang có trên đơn hàng", + "@onOrderDetails": {}, + "orientation": "Điều chỉnh xoay màn hình", + "@orientation": {}, + "orientationDetail": "Điều chỉnh xoay màn hình (bắt buộc khởi động lại)", + "@orientationDetail": {}, + "orientationLandscape": "Phong cảnh", + "@orientationLandscape": {}, + "orientationPortrait": "Chân dung", + "@orientationPortrait": {}, "orientationSystem": "Hệ thống", "@orientationSystem": {}, + "outstanding": "Nổi bật", + "@outstanding": {}, + "outstandingOrderDetail": "Hiển thị mặt hàng nổi bật", + "@outstandingOrderDetail": {}, + "packaging": "Đóng gói", + "@packaging": {}, "packageName": "Tên gói", "@packageName": {}, "parameters": "Thông số", "@parameters": {}, "parametersSettingDetail": "Hiển thị các thông số", "@parametersSettingDetail": {}, + "parent": "Thư mục cha", + "@parent": {}, "parentCategory": "Danh mục cha", "@parentCategory": {}, + "parentLocation": "Vị trí thư mục cha", + "@parentLocation": {}, + "part": "Phụ kiện", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Phụ kiện mới", + "@partCreate": {}, + "partCreateDetail": "Thêm phụ kiện mới trong danh mục", + "@partCreateDetail": {}, + "partEdited": "Cập nhật phụ kiện", + "@partEdited": {}, "parts": "Phụ tùng", "@parts": { "description": "Part (multiple)" }, "partsNone": "Không có phụ tùng", "@partsNone": {}, + "partNoResults": "Không có phụ kiện nào phù hợp", + "@partNoResults": {}, + "partSettings": "Cài đặt phụ kiện", + "@partSettings": {}, + "partsStarred": "Đăng kí phụ kiện", + "@partsStarred": {}, + "partsStarredNone": "Không có phụ kiện được gắn dấu sao nào", + "@partsStarredNone": {}, + "partSuppliers": "Nhà cung cấp phụ kiện", + "@partSuppliers": {}, + "partDetails": "Chi tiết phụ kiện", + "@partDetails": {}, + "partNotes": "Ghi chú phụ kiện", + "@partNotes": {}, + "partStock": "Phụ kiện trong kho", + "@partStock": { + "description": "part stock" + }, "password": "Mật khẩu", "@password": {}, "passwordEmpty": "Mật khẩu không được để trống", "@passwordEmpty": {}, + "permissionAccountDenied": "Tài khoản này bắt buộc phải có đủ các quyền để thực hiện thao tác này", + "@permissionAccountDenied": {}, "permissionRequired": "Yêu cầu quyền truy cập", "@permissionRequired": {}, + "printLabel": "In nhãn tem", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, "pluginPrinter": "Máy in", "@pluginPrinter": {}, + "pluginSupport": "Hỗ trợ bật Plugin", + "@pluginSupport": {}, + "pluginSupportDetail": "Máy chủ hỗ trợ cài đặt plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Lỗi in nhãn tem", + "@printLabelFailure": {}, + "printLabelSuccess": "Tem nhãn được gửi đến máy in", + "@printLabelSuccess": {}, "profile": "Hồ sơ", "@profile": {}, "profileAdd": "Thêm mới cấu hình máy chủ", @@ -334,24 +519,78 @@ "@profileEdit": {}, "profileDelete": "Xóa cấu hình máy chủ", "@profileDelete": {}, + "profileName": "Tên hồ sơ", + "@profileName": {}, + "profileNone": "Không có sẵn profile", + "@profileNone": {}, + "profileNotSelected": "Không chọn Profile", + "@profileNotSelected": {}, + "profileSelect": "Chọn máy chủ InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Chọn máy chủ hoặc tạo mới profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Nhấn để tạo hoặc chọn profile", + "@profileTapToCreate": {}, + "projectCode": "Mã dự án", + "@projectCode": {}, "purchaseOrder": "Đơn hàng", "@purchaseOrder": {}, + "purchaseOrderCreate": "Thêm mới đơn đặt hàng", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Chỉnh sửa đơn đặt hàng", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Đơn hàng", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Cập nhật đơn đặt hàng", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Giá đơn hàng", + "@purchasePrice": {}, "quantity": "Số lượng", "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Số lượng còn hàng", + "@quantityAvailable": {}, + "quantityEmpty": "Số lượng bị trống", + "@quantityEmpty": {}, + "quantityInvalid": "Số lượng không hợp lệ", + "@quantityInvalid": {}, + "quantityPositive": "Số lượng phải là số dương", + "@quantityPositive": {}, "queryEmpty": "Nhập nội dung cần tìm", "@queryEmpty": {}, "queryNoResults": "Không có kết quả nào", "@queryNoResults": {}, + "received": "Đã nhận", + "@received": {}, + "receivedFilterDetail": "Hiển thị mục có sẵn", + "@receivedFilterDetail": {}, + "receiveItem": "Mặt hàng đã nhận", + "@receiveItem": {}, + "receivedItem": "Kho hàng đã nhận", + "@receivedItem": {}, + "reference": "Tham chiếu", + "@reference": {}, "refresh": "Làm mới", "@refresh": {}, "refreshing": "Đang làm mới", "@refreshing": {}, + "rejected": "Đã từ chối", + "@rejected": {}, + "releaseNotes": "Ghi chú phát hành", + "@releaseNotes": {}, "remove": "Xóa", "@remove": { "description": "remove" }, + "removeStock": "Xóa hàng hóa", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Báo cáo lỗi", + "@reportBug": {}, + "reportBugDescription": "Báo cáo lỗi (bắt buộc phải có tài khoản GitHub)", + "@reportBugDescription": {}, "results": "Kết quả", "@results": {}, "request": "Yêu cầu", @@ -368,34 +607,52 @@ }, "response400": "Yêu cầu không hợp lệ", "@response400": {}, + "response401": "Chưa cấp quyền", + "@response401": {}, "response403": "Quyền truy cập bị từ chối", "@response403": {}, "response404": "Tài nguyên không tìm thấy", "@response404": {}, "response405": "Phương thức không được phép", "@response405": {}, + "response429": "Quá Nhiều Yêu Cầu", + "@response429": {}, "response500": "Lỗi máy chủ nội bộ", "@response500": {}, "response501": "Không được thực hiện", "@response501": {}, "response502": "Cổng không hợp lệ", "@response502": {}, + "response503": "Dịch vụ không sẵn sàng", + "@response503": {}, "response504": "Gateway quá hạn", "@response504": {}, "response505": "Phiên bản của HTTP không được hỗ trợ", "@response505": {}, + "responseData": "Dữ liệu trả về", + "@responseData": {}, + "responseInvalid": "Mã trả về không hợp lệ", + "@responseInvalid": {}, + "responseUnknown": "Trả lời không xác định", + "@responseUnknown": {}, "result": "Kết quả", "@result": { "description": "" }, "returned": "Trả lại", "@returned": {}, + "salesOrders": "Đơn đặt hàng", + "@salesOrders": {}, "save": "Lưu lại", "@save": { "description": "Save" }, "scanBarcode": "Quét mã vạch", "@scanBarcode": {}, + "scanIntoLocation": "Quét vào điểm bán", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Quét mặt hàng này vào điểm bán", + "@scanIntoLocationDetail": {}, "search": "Tìm kiếm", "@search": { "description": "search" @@ -414,6 +671,8 @@ "@selectFile": {}, "selectImage": "Chọn ảnh", "@selectImage": {}, + "selectLocation": "Chọn một điểm bán hàng", + "@selectLocation": {}, "send": "Gửi", "@send": {}, "serialNumber": "Số sê-ri", @@ -430,6 +689,8 @@ "@serverApiVersion": {}, "serverAuthenticationError": "Lỗi xác thực", "@serverAuthenticationError": {}, + "serverCertificateError": "Lỗi chứng chỉ", + "@serverCertificateError": {}, "serverCertificateInvalid": "Chứng chỉ máy chủ HTTPS không hợp lệ", "@serverCertificateInvalid": {}, "serverConnected": "Đã kết nối với máy chủ", @@ -444,40 +705,188 @@ "@serverError": {}, "serverDetails": "Thông tin máy chủ", "@serverDetails": {}, + "serverMissingData": "Phản hồi của máy chủ thiếu các trường bắt buộc", + "@serverMissingData": {}, "serverOld": "Phiên bản máy chủ cũ", "@serverOld": {}, "serverSettings": "Cài đặt máy chủ", "@serverSettings": {}, + "serverStart": "Máy chủ phải bắt đầu bằng http[s]", + "@serverStart": {}, "settings": "Cài đặt", "@settings": {}, + "serverInstance": "Phiên bản máy chủ", + "@serverInstance": {}, + "serverNotConnected": "Máy chủ chưa được kết nối", + "@serverNotConnected": {}, + "serverNotSelected": "Chưa chọn máy chủ", + "@serverNotSelected": {}, "sku": "Mã sản phẩm", "@sku": {}, "sounds": "Âm thanh", "@sounds": {}, + "soundOnBarcodeAction": "Phát âm thanh trên thao tác mã vạch", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Phát âm thanh khi lỗi máy chủ", + "@soundOnServerError": {}, "status": "Trạng thái", "@status": {}, + "statusCode": "Mã trạng thái", + "@statusCode": {}, "stock": "Kho hàng", "@stock": { "description": "stock" }, + "stockDetails": "Số lượng trong kho có sẵn", + "@stockDetails": {}, + "stockItem": "Kho hàng", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Kho hàng", + "@stockItems": {}, + "stockItemCreate": "Thêm kho hàng", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Tạo kho hàng mới trong điểm bán này", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Xóa kho hàng", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Bạn có chắc chắn muốn xóa kho hàng này?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Không thể xóa kho hàng này", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Kho hàng đã bị xóa", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Lịch sử kho hàng", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Hiển thị thông tin lịch sử kho hàng", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Chuyển kho hàng", + "@stockItemTransferred": {}, + "stockItemUpdated": "Kho hàng đã được cập nhật", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Không có mặt hàng nào trong kho", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Ghi chú tại kho hàng", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Kho hàng đã được cập nhật", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Cập nhật kho hàng bị lỗi", + "@stockItemUpdateFailure": {}, + "stockLocation": "Vị trí kho hàng", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Vị trí kho hàng", + "@stockLocations": {}, + "stockTopLevel": "Vị trí kho hàng cấp cao", + "@stockTopLevel": {}, "strictHttps": "Sử dụng HTTPS nghiêm ngặt", "@strictHttps": {}, + "strictHttpsDetails": "Thực thi kiểm tra nghiêm ngặt các chứng chỉ HTTPS", + "@strictHttpsDetails": {}, + "subcategory": "Danh mục con", + "@subcategory": {}, + "subcategories": "Danh mục con", + "@subcategories": {}, + "sublocation": "Kho phụ", + "@sublocation": {}, + "sublocations": "Kho phụ", + "@sublocations": {}, + "sublocationNone": "Chưa có kho phụ", + "@sublocationNone": {}, + "sublocationNoneDetail": "Không có sẵn kho phụ", + "@sublocationNoneDetail": {}, "submitFeedback": "Gửi phản hồi", "@submitFeedback": {}, + "suppliedParts": "Bộ phận nhà cung cấp", + "@suppliedParts": {}, + "supplier": "Nhà cung cấp", + "@supplier": {}, + "supplierPart": "Bộ phận nhà cung cấp", + "@supplierPart": {}, + "supplierPartEdit": "Chỉnh sửa nhà cung cấp", + "@supplierPartEdit": {}, + "supplierPartNumber": "Số phụ kiện nhà cung cấp", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Cập nhật phụ kiện nhà cung cấp", + "@supplierPartUpdated": {}, + "supplierParts": "Bộ phận nhà cung cấp", + "@supplierParts": {}, + "suppliers": "Nhà cung cấp", + "@suppliers": {}, + "supplierReference": "Tham khảo nhà cung cấp", + "@supplierReference": {}, "takePicture": "Chụp ảnh", "@takePicture": {}, + "targetDate": "Ngày", + "@targetDate": {}, + "testName": "Kiểm tra tên", + "@testName": {}, + "testPassedOrFailed": "Kiểm thử thất bại", + "@testPassedOrFailed": {}, + "testsRequired": "Kiểm thử bắt buộc", + "@testsRequired": {}, + "testResults": "Kết quả kiểm tra", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Kết quả kiểm thử mặt hàng tại kho", + "@testResultsDetail": {}, + "testResultAdd": "Thêm kết quả kiểm tra", + "@testResultAdd": {}, + "testResultNone": "Không thấy kết quả kiểm tra", + "@testResultNone": {}, + "testResultNoneDetail": "Kết quả kiểm thử không có sẵn", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Lỗi tải lên kết quả kiểm thử", + "@testResultUploadFail": {}, + "testResultUploadPass": "Kiểm tra kết quả tải lên", + "@testResultUploadPass": {}, + "timeout": "Quá hạn", + "@timeout": { + "description": "" + }, "tokenError": "Lỗi Token", "@tokenError": {}, + "tokenMissing": "Thiếu mã thông báo", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Mã thông báo truy cập bị thiếu trong phản hồi", + "@tokenMissingFromResponse": {}, "totalPrice": "Tổng tiền", "@totalPrice": {}, + "transfer": "Chuyển", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Chuyển kho", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Chuyển mục đến vị trí khác", + "@transferStockDetail": {}, + "transferStockLocation": "Chuyển vị trí kho hàng", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Thiếu mã thông báo", + "@transferStockLocationDetail": {}, "translate": "Dịch", "@translate": {}, + "translateHelp": "Hỗ trợ dịch InvenTree app", + "@translateHelp": {}, + "unitPrice": "Đơn giá", + "@unitPrice": {}, "units": "Đơn vị", "@units": {}, + "unknownResponse": "Trả lời không xác định", + "@unknownResponse": {}, "upload": "Tải lên", "@upload": {}, "uploadFailed": "Tập tin tải lên không thành công", "@uploadFailed": {}, + "uploadSuccess": "Tải tệp lên", + "@uploadSuccess": {}, + "usedIn": "Sử dụng trong", + "@usedIn": {}, "username": "Tên người dùng", "@username": {}, "usernameEmpty": "Tên người dùng không được để trống", @@ -490,8 +899,12 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Giá trị là bắt buộc", "@valueRequired": {}, + "variants": "Biến thể", + "@variants": {}, "version": "Phiên bản", "@version": {}, + "viewSupplierPart": "Xem nhà cung cấp phụ kiện", + "@viewSupplierPart": {}, "website": "Trang web", "@website": {} } \ No newline at end of file From d81f0d532d63dbff867e64d41a62c12f5e8bd4e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 10 Aug 2023 22:32:00 +1000 Subject: [PATCH 411/746] New translations app_en.arb (Russian) (#412) --- lib/l10n/ru_RU/app_ru_RU.arb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 16a5473..5477e90 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -289,7 +289,7 @@ "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Показывать детали, на которые включены уведомления, на главной странице", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Показать кнопку заказа заказа на главной станице", + "homeShowPoDescription": "Показывать кнопку заказа на главном экране", "@homeShowPoDescription": {}, "homeShowSuppliers": "Показать поставщиков", "@homeShowSuppliers": {}, @@ -729,6 +729,10 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Общая стоимость", "@totalPrice": {}, + "transferStock": "Переместить запасы", + "@transferStock": { + "description": "transfer stock" + }, "transferStockLocation": "Изменить местоположение склада", "@transferStockLocation": {}, "translate": "Перевод", From 82001409764c79c73025a99adb485cee61960275 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 12 Aug 2023 20:41:11 +1000 Subject: [PATCH 412/746] Label fix (#411) * Cleanup label printing options - Improve calls to setState() - Should fix potential race conditions * Use name if description not available * Code simplification * Fetch plugins even if the server reports "plugins enabled" - Builtin plugins are still a thing! * Use name *and* description to display label --- lib/api.dart | 6 +----- lib/labels.dart | 12 +++++++++--- lib/widget/location_display.dart | 16 ++++++++-------- lib/widget/part_detail.dart | 17 +++++++++++------ lib/widget/stock_detail.dart | 19 +++++++++++-------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 26cd5b9..fa740e0 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -645,11 +645,7 @@ class InvenTreeAPI { // Request plugin information from the server Future getPluginInformation() async { - // The server does not support plugins, or they are not enabled - if (!pluginsEnabled()) { - _plugins.clear(); - return true; - } + _plugins.clear(); debug("API: getPluginInformation()"); diff --git a/lib/labels.dart b/lib/labels.dart index ca4f8ad..c43ad30 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -66,12 +66,18 @@ Future selectAndPrintLabel( // Construct list of available label templates for (var label in labels) { - String display_name = (label["description"] ?? "").toString(); + String name = (label["name"] ?? "").toString(); + String description = (label["description"] ?? "").toString(); + + if (description.isNotEmpty) { + name += " - ${description}"; + } + int pk = (label["pk"] ?? -1) as int; - if (display_name.isNotEmpty && pk > 0) { + if (name.isNotEmpty && pk > 0) { label_options.add({ - "display_name": display_name, + "display_name": name, "value": pk, }); } diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index a26ddc9..0ca1c5d 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -40,8 +40,6 @@ class _LocationDisplayState extends RefreshableState { final InvenTreeStockLocation? location; - bool allowLabelPrinting = true; - List> labels = []; @override @@ -169,7 +167,7 @@ class _LocationDisplayState extends RefreshableState { ); } - if (widget.location != null && allowLabelPrinting && labels.isNotEmpty) { + if (widget.location != null && labels.isNotEmpty) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.print), @@ -225,21 +223,23 @@ class _LocationDisplayState extends RefreshableState { } } - allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); - allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + List> _labels = []; + bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { - labels.clear(); if (widget.location != null) { - labels = await getLabelTemplates("location", { + _labels = await getLabelTemplates("location", { "location": widget.location!.pk.toString() }); } } if (mounted) { - setState(() {}); + setState(() { + labels = _labels; + }); } } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index d8a81b9..1079fb1 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -56,7 +56,6 @@ class _PartDisplayState extends RefreshableState { bool showParameters = false; bool showBom = false; - bool allowLabelPrinting = true; int attachmentCount = 0; int bomCount = 0; @@ -121,7 +120,7 @@ class _PartDisplayState extends RefreshableState { ); } - if (allowLabelPrinting && labels.isNotEmpty) { + if (labels.isNotEmpty) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.print), @@ -244,15 +243,21 @@ class _PartDisplayState extends RefreshableState { } }); - allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); - allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + List> _labels = []; + bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { - labels.clear(); - labels = await getLabelTemplates("part", { + _labels = await getLabelTemplates("part", { "part": widget.part.pk.toString(), }); } + + if (mounted) { + setState(() { + labels = _labels; + }); + } } void _editPartDialog(BuildContext context) { diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 9e2f517..decf402 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -128,7 +128,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (allowLabelPrinting && labels.isNotEmpty) { + if (labels.isNotEmpty) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.print), @@ -204,8 +204,6 @@ class _StockItemDisplayState extends RefreshableState { int attachmentCount = 0; - bool allowLabelPrinting = true; - @override Future onBuild(BuildContext context) async { // Load part data if not already loaded @@ -259,18 +257,23 @@ class _StockItemDisplayState extends RefreshableState { } }); - // Determine if label printing is supported - allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); - allowLabelPrinting &= api.getPlugins(mixin: "labels").isNotEmpty; + List> _labels = []; + bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting &= api.supportsMixin("labels"); // Request information on labels available for this stock item if (allowLabelPrinting) { // Clear the existing labels list - labels.clear(); - labels = await getLabelTemplates("stock", { + _labels = await getLabelTemplates("stock", { "item": widget.item.pk.toString() }); } + + if (mounted) { + setState(() { + labels = _labels; + }); + } } /// Delete the stock item from the database From e6ad1bcb9887a02d75d96b03f42ecaaf3817e120 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 12 Aug 2023 20:44:59 +1000 Subject: [PATCH 413/746] New translations app_en.arb (Turkish) (#413) --- lib/l10n/tr_TR/app_tr_TR.arb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index b543606..70c900a 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Dikkat", "@attention": {}, + "available": "Mevcut", + "@available": {}, "availableStock": "Stokta hazır", "@availableStock": {}, "barcodes": "Barkod *", @@ -246,6 +248,8 @@ "@filterComponent": {}, "filterComponentDetail": "Bileşen parçalarını göster", "@filterComponentDetail": {}, + "filterExternal": "Harici", + "@filterExternal": {}, "filterInStock": "Stokta mevcut", "@filterInStock": {}, "filterInStockDetail": "Stoğu olan parçaları göster", @@ -347,12 +351,18 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", "@invalidUsernamePassword": {}, + "issue": "Sorun", + "@issue": {}, "issueDate": "Sorun Tarihi", "@issueDate": {}, "itemInLocation": "Parça zaten konumda", "@itemInLocation": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, + "labelPrinting": "Etiket Yazdırma", + "@labelPrinting": {}, + "labelPrintingDetail": "Etiket yazdırmayı aktifleştir", + "@labelPrintingDetail": {}, "labelTemplate": "Etiket Şablonu", "@labelTemplate": {}, "language": "Dil", From 38dfb03669a5868383d0b70c48b6357a14e6fb9b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 12 Aug 2023 20:59:15 +1000 Subject: [PATCH 414/746] Update release notes --- assets/release_notes.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 99fc78f..737cb5a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,7 +1,9 @@ -### 0.12.7 - July 2023 +### 0.12.7 - August 2023 --- - Bug fix for Supplier Part editing page +- Bug fix for label printing (blank template names) +- Updated translations ### 0.12.6 - July 2023 --- @@ -9,7 +11,7 @@ - Enable label printing for stock locations - Enable label printing for parts - Updated translation support -- Bug files +- Bug fixes ### 0.12.5 - July 2023 --- From 32c301a9b1370506acbbe76103d95fdb9be1192e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 21 Aug 2023 17:43:19 +1000 Subject: [PATCH 415/746] Show version (#415) --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dc848cd..43f0293 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,7 +46,7 @@ jobs: python3 collect_translations.py - name: Static Analysis Tests run: | - flutter upgrade + flutter --version cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get From af09cde29ef7a02805a11b30200ed6ffd462cf05 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 21 Aug 2023 17:50:11 +1000 Subject: [PATCH 416/746] New translations app_en.arb (French) (#414) --- lib/l10n/fr_FR/app_fr_FR.arb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 86e9d12..91e852e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Avertissement", "@attention": {}, + "available": "Disponible", + "@available": {}, "availableStock": "Stock disponible", "@availableStock": {}, "barcodes": "Code-barres", @@ -244,6 +246,10 @@ "@filterComponent": {}, "filterComponentDetail": "Afficher les pièces du composant", "@filterComponentDetail": {}, + "filterExternal": "Externe", + "@filterExternal": {}, + "filterExternalDetail": "Afficher le stock dans les emplacements externes", + "@filterExternalDetail": {}, "filterInStock": "En stock", "@filterInStock": {}, "filterInStockDetail": "Afficher les pièces qui ont du stock", @@ -327,6 +333,8 @@ "@inProduction": {}, "inProductionDetail": "Cet article de stock est en production", "@inProductionDetail": {}, + "internalPart": "Pièce interne", + "@internalPart": {}, "invalidHost": "Nom d’hôte invalide", "@invalidHost": {}, "invalidHostDetails": "Le nom d'hôte fourni n'est pas valide", @@ -353,6 +361,10 @@ "@itemInLocation": {}, "keywords": "Mots clés", "@keywords": {}, + "labelPrinting": "Impression étiquettes", + "@labelPrinting": {}, + "labelPrintingDetail": "Activer l'impression d'étiquettes", + "@labelPrintingDetail": {}, "labelTemplate": "Modèle d'étiquette", "@labelTemplate": {}, "language": "Langue", @@ -387,6 +399,8 @@ "@link": {}, "lost": "Perdu", "@lost": {}, + "manufacturerPartNumber": "Numéro de pièce fabricant", + "@manufacturerPartNumber": {}, "manufacturer": "Fabricant", "@manufacturer": {}, "manufacturers": "Fabricants", @@ -427,6 +441,8 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, + "orientationSystem": "Système", + "@orientationSystem": {}, "outstanding": "En attente", "@outstanding": {}, "outstandingOrderDetail": "Afficher les commandes en attente", @@ -805,6 +821,8 @@ "@supplierPart": {}, "supplierPartEdit": "Modifier la pièce du fournisseur", "@supplierPartEdit": {}, + "supplierPartNumber": "Numéro de pièce fournisseur", + "@supplierPartNumber": {}, "supplierPartUpdated": "Pièce fournisseur mise à jour", "@supplierPartUpdated": {}, "supplierParts": "Pièce fournisseur", From 81907ad72f293fa73d9fa6bfe7ced2f985115695 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 22 Aug 2023 22:52:18 +1000 Subject: [PATCH 417/746] Flutter upgrades (#416) * Upgrade flutter version * Update packages * update prj files * Bump android sdk target to 33 --- .github/workflows/android.yaml | 2 +- .github/workflows/ci.yaml | 4 +- .github/workflows/ios.yaml | 2 +- android/app/build.gradle | 2 +- ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- pubspec.lock | 142 +++++++++++++----- pubspec.yaml | 6 +- 8 files changed, 117 insertions(+), 45 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index f462ba4..b538b45 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -23,7 +23,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.10.4' + flutter-version: '3.13.0' channel: 'stable' - run: flutter --version - name: Setup Gradle diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 43f0293..0de5696 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,14 +39,14 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.10.4' + flutter-version: '3.13.0' - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py - name: Static Analysis Tests run: | - flutter --version + flutter upgrade cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 685a3ff..55ebe2a 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -25,7 +25,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.10.4' + flutter-version: '3.13.0' channel: 'stable' - name: Collect Translation Files run: | diff --git a/android/app/build.gradle b/android/app/build.gradle index b65c50a..7105a67 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,7 +48,7 @@ android { defaultConfig { applicationId "inventree.inventree_app" - minSdkVersion 25 + minSdkVersion 33 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e19424e..044f417 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -168,7 +168,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..a6b826d 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ =3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <3.13.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 20b00ec..ab68b3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: InvenTree stock management version: 0.12.7+74 environment: - sdk: ">=2.19.5 <3.0.0" + sdk: ">=2.19.5 <3.13.0" dependencies: adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) @@ -28,8 +28,8 @@ dependencies: flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation font_awesome_flutter: ^10.3.0 # FontAwesome icon set http: ^0.13.5 - image_picker: ^0.8.7+4 # Select or take photos - infinite_scroll_pagination: ^3.2.0 # Let the server do all the work! + image_picker: ^1.0.2 # Select or take photos + infinite_scroll_pagination: ^4.0.0 # Let the server do all the work! intl: ^0.18.0 one_context: ^2.1.0 # Dialogs without requiring context open_filex: ^4.3.2 # Open local files From 19600162880998be320991e319f7fb11da21ff8a Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 25 Aug 2023 23:22:14 +1000 Subject: [PATCH 418/746] Do not run flutter upgrade (#418) --- .github/workflows/android.yaml | 1 - .github/workflows/ci.yaml | 1 - .github/workflows/ios.yaml | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index b538b45..9481c5c 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -36,7 +36,6 @@ jobs: python3 collect_translations.py - name: Build for Android run: | - flutter upgrade flutter pub get cp lib/dummy_dsn.dart lib/dsn.dart flutter build apk --debug diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0de5696..02111c8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,7 +46,6 @@ jobs: python3 collect_translations.py - name: Static Analysis Tests run: | - flutter upgrade cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 55ebe2a..65c92a0 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -33,7 +33,6 @@ jobs: python3 collect_translations.py - name: Build for iOS run: | - flutter upgrade flutter pub get cd ios pod repo update From 9203ee8a3fb2b0c8bb7005458de6836685c81b80 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 25 Aug 2023 23:31:45 +1000 Subject: [PATCH 419/746] New Crowdin updates (#417) * New translations app_en.arb (Swedish) * New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 146 ++++++++++++++++++++++++++++++++--- lib/l10n/sv_SE/app_sv_SE.arb | 74 +++++++++++++++++- 2 files changed, 207 insertions(+), 13 deletions(-) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 5477e90..4c1d648 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -194,7 +194,7 @@ "@editNotes": {}, "editParameter": "Редактировать параметр", "@editParameter": {}, - "editPart": "Ред. эту часть", + "editPart": "Редактировать деталь", "@editPart": { "description": "edit part" }, @@ -335,9 +335,9 @@ "@invalidHost": {}, "invalidHostDetails": "Недопустимый пароль", "@invalidHostDetails": {}, - "invalidPart": "Недопустимый элемент", + "invalidPart": "Недопустимая деталь", "@invalidPart": {}, - "invalidPartCategory": "Неверная категория элемента", + "invalidPartCategory": "Неверная категория детали", "@invalidPartCategory": {}, "invalidStockLocation": "Неверное расположение склада", "@invalidStockLocation": {}, @@ -347,8 +347,12 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", "@invalidUsernamePassword": {}, + "issue": "Оформить", + "@issue": {}, "issueDate": "Дата проблемы", "@issueDate": {}, + "issueOrder": "Оформить заказ", + "@issueOrder": {}, "itemInLocation": "Элемент уже находится на месте", "@itemInLocation": {}, "keywords": "Ключевые слова", @@ -465,6 +469,8 @@ "@partSettings": {}, "partsStarred": "Детали с включёнными уведомлениями", "@partsStarred": {}, + "partSuppliers": "Поставщики детали", + "@partSuppliers": {}, "partCategory": "Категория детали", "@partCategory": {}, "partCategoryTopLevel": "Категория детали верхнего уровня", @@ -473,6 +479,12 @@ "@partCategories": {}, "partDetails": "Информация о детали", "@partDetails": {}, + "partNotes": "Заметки детали", + "@partNotes": {}, + "partStock": "Складские позиции детали", + "@partStock": { + "description": "part stock" + }, "password": "Пароль", "@password": {}, "passwordEmpty": "Пароль не может быть пустым", @@ -515,16 +527,44 @@ "@profileSelect": {}, "profileSelectOrCreate": "Выбрать сервер или создать новый профиль", "@profileSelectOrCreate": {}, + "purchaseOrder": "Заказ на поставку", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Новый заказ на поставку", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Редактировать заказ на поставку", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Заказы на поставку", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Заказ на поставку обновлен", + "@purchaseOrderUpdated": {}, "purchasePrice": "Закупочная цена", "@purchasePrice": {}, "quantity": "Количество", "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Доступное количество", + "@quantityAvailable": {}, + "quantityEmpty": "Количество не указано", + "@quantityEmpty": {}, + "quantityInvalid": "Недопустимое количество", + "@quantityInvalid": {}, + "quantityPositive": "Количество должно быть положительным", + "@quantityPositive": {}, "queryEmpty": "Введите поисковой запрос", "@queryEmpty": {}, "queryNoResults": "Нет результатов по запросу", "@queryNoResults": {}, + "received": "Получено", + "@received": {}, + "receivedFilterDetail": "Показать полученные позиции", + "@receivedFilterDetail": {}, + "receiveItem": "Получить позицию", + "@receiveItem": {}, + "receivedItem": "Полученные складские позиции", + "@receivedItem": {}, + "reference": "Ссылка", + "@reference": {}, "refresh": "Обновить", "@refresh": {}, "refreshing": "Обновление…", @@ -693,26 +733,46 @@ }, "stockDetails": "Текущее количество на складе", "@stockDetails": {}, - "stockItem": "Компонент на складе", + "stockItem": "Складская позиция", "@stockItem": { "description": "stock item title" }, - "stockItems": "Детали на складе", + "stockItems": "Складские позиции", "@stockItems": {}, - "stockItemCreate": "Новая деталь на складе", + "stockItemCreate": "Новая складская позиция", "@stockItemCreate": {}, - "stockItemCreateDetail": "Создать новый компонент в этом месте", + "stockItemCreateDetail": "Создать новую складскую позицию в этом месте", "@stockItemCreateDetail": {}, "stockItemDelete": "Удалить складскую позицию", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Вы уверены, что хотите удалить этот элемент Bom?", + "stockItemDeleteConfirm": "Вы уверены, что хотите удалить эту складскую позицию?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Не удалось удалить позицию", + "stockItemDeleteFailure": "Не удалось удалить складскую позицию", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Компонент на складе удален", + "stockItemDeleteSuccess": "Складская позиция удалена", "@stockItemDeleteSuccess": {}, "stockItemHistory": "История запасов", "@stockItemHistory": {}, + "stockItemHistoryDetail": "Отображать историческую информацию о складском учете", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Складская позиция перемещена", + "@stockItemTransferred": {}, + "stockItemUpdated": "Складская позиция устарела", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Нет доступных складских позиций", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Заметки складской позиции", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Складская позиция обновлена", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Сбой обновления складской позиции", + "@stockItemUpdateFailure": {}, + "stockLocation": "Место хранения", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Места хранения", + "@stockLocations": {}, "stockTopLevel": "Склад верхнего уровня", "@stockTopLevel": {}, "strictHttpsDetails": "Принудительная проверка HTTPs сертификатов", @@ -721,6 +781,52 @@ "@subcategory": {}, "subcategories": "Подкатегории", "@subcategories": {}, + "supplier": "Поставщик", + "@supplier": {}, + "supplierPart": "Деталь поставщика", + "@supplierPart": {}, + "supplierPartEdit": "Редактировать деталь поставщика", + "@supplierPartEdit": {}, + "supplierPartNumber": "Номер детали поставщика", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Деталь поставщика обновлена", + "@supplierPartUpdated": {}, + "supplierParts": "Детали поставщика", + "@supplierParts": {}, + "suppliers": "Поставщики", + "@suppliers": {}, + "supplierReference": "Ссылка на поставщика", + "@supplierReference": {}, + "targetDate": "Целевая дата", + "@targetDate": {}, + "templatePart": "Родительская шаблонная деталь", + "@templatePart": {}, + "testName": "Название теста", + "@testName": {}, + "testPassedOrFailed": "Тест пройден или не пройден", + "@testPassedOrFailed": {}, + "testsRequired": "Требуемые тесты", + "@testsRequired": {}, + "testResults": "Результаты тестов", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Показать результаты теста складских позиций", + "@testResultsDetail": {}, + "testResultAdd": "Добавить результат теста", + "@testResultAdd": {}, + "testResultNone": "Нет результатов теста", + "@testResultNone": {}, + "testResultNoneDetail": "Нет доступных результатов теста", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Ошибка загрузки результатов теста", + "@testResultUploadFail": {}, + "testResultUploadPass": "Результат теста загружен", + "@testResultUploadPass": {}, + "timeout": "Таймаут", + "@timeout": { + "description": "" + }, "tokenError": "Ошибка токена", "@tokenError": {}, "tokenMissing": "Отсутствует токен", @@ -729,12 +835,20 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Общая стоимость", "@totalPrice": {}, + "transfer": "Перемещение", + "@transfer": { + "description": "transfer" + }, "transferStock": "Переместить запасы", "@transferStock": { "description": "transfer stock" }, + "transferStockDetail": "Переместить складскую позицию в другое место", + "@transferStockDetail": {}, "transferStockLocation": "Изменить местоположение склада", "@transferStockLocation": {}, + "transferStockLocationDetail": "Перенести это место на складе в другое", + "@transferStockLocationDetail": {}, "translate": "Перевод", "@translate": {}, "translateHelp": "Помочь перевести приложение InvenTree", @@ -759,8 +873,20 @@ "@username": {}, "usernameEmpty": "Имя пользователя не может быть пустым", "@usernameEmpty": {}, + "value": "Значение", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Значение не может быть пустым", + "@valueCannotBeEmpty": {}, + "valueRequired": "Необходимо указать значение", + "@valueRequired": {}, + "variants": "Разновидности", + "@variants": {}, "version": "Версия", "@version": {}, + "viewSupplierPart": "Отобразить деталь поставщика", + "@viewSupplierPart": {}, "website": "Сайт", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 865f222..9f48b4a 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -74,6 +74,22 @@ "@barcodeInUse": {}, "build": "Bygg", "@build": {}, + "cancel": "Avbryt", + "@cancel": { + "description": "Cancel" + }, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Ny kategori", + "@categoryCreate": {}, + "company": "Företag", + "@company": {}, + "customers": "Kunder", + "@customers": {}, + "delete": "Radera", + "@delete": {}, + "description": "Beskrivning", + "@description": {}, "downloadError": "Nedladdningsfel", "@downloadError": {}, "edit": "Ändra", @@ -86,8 +102,6 @@ "@editLocation": {}, "editNotes": "Redigera anteckningar", "@editNotes": {}, - "editParameter": "Editera parametrar", - "@editParameter": {}, "editPart": "Redigera artikel", "@editPart": { "description": "edit part" @@ -110,6 +124,60 @@ "@errorDelete": {}, "errorDetails": "Felinformation", "@errorDetails": {}, + "filterInStock": "I lager", + "@filterInStock": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "homeShowSuppliers": "Visa leverantörer", + "@homeShowSuppliers": {}, + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Visa tillverkare", + "@homeShowManufacturers": {}, + "includeSubcategories": "Inkludera underkategorier", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Visa resultat från underkategorier", + "@includeSubcategoriesDetail": {}, + "keywords": "Nyckelord", + "@keywords": {}, + "lastUpdated": "Senast uppdaterad", + "@lastUpdated": {}, + "manufacturers": "Tillverkare", + "@manufacturers": {}, + "notes": "Anteckningar", + "@notes": { + "description": "Notes" + }, + "noSubcategories": "Inga underkategorier", + "@noSubcategories": {}, + "parameters": "Parametrar", + "@parameters": {}, + "password": "Lösenord", + "@password": {}, + "reference": "Referens", + "@reference": {}, + "save": "Spara", + "@save": { + "description": "Save" + }, + "search": "Sök", + "@search": { + "description": "search" + }, + "searching": "Söker", + "@searching": {}, + "serialNumbers": "Serienummer", + "@serialNumbers": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuskod", + "@statusCode": {}, + "subcategory": "Underkategori", + "@subcategory": {}, + "subcategories": "Underkategorier", + "@subcategories": {}, + "supplier": "Leverantör", + "@supplier": {}, + "suppliers": "Leverantörer", + "@suppliers": {}, + "username": "Användarnamn", + "@username": {} } \ No newline at end of file From dd12769a5139a981a0f72a1d1ace61dfbdef4a61 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 9 Sep 2023 00:32:57 +1000 Subject: [PATCH 420/746] Stock transfer extra (#420) * Add API version check * Support "packaging" and "status" fields when performing a stock-transfer action * Update release notes --- assets/release_notes.md | 5 +++++ lib/api.dart | 3 +++ lib/widget/stock_detail.dart | 16 ++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 737cb5a..dd851dc 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.12.8 - September 2023 +--- + +- Added extra options for transferring stock items + ### 0.12.7 - August 2023 --- diff --git a/lib/api.dart b/lib/api.dart index fa740e0..b8a4f21 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -323,6 +323,9 @@ class InvenTreeAPI { // Project codes require v109 or newer bool get supportsProjectCodes => isConnected() && apiVersion >= 109; + // Does the server support extra fields on stock adjustment actions? + bool get supportsStockAdjustExtraFields => isConnected() && apiVersion >= 133; + // Are plugins enabled on the server? bool _pluginsEnabled = false; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index decf402..b917e01 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -451,6 +451,16 @@ class _StockItemDisplayState extends RefreshableState { "location": { "value": widget.item.locationId, }, + "status": { + "parent": "items", + "nested": true, + "value": widget.item.status, + }, + "packaging": { + "parent": "items", + "nested": true, + "value": widget.item.packaging, + }, "notes": {}, }; @@ -459,6 +469,12 @@ class _StockItemDisplayState extends RefreshableState { fields["quantity"]["hidden"] = true; } + // Old API does not support these fields + if (!api.supportsStockAdjustExtraFields) { + fields.remove("packaging"); + fields.remove("status"); + } + launchApiForm( context, L10().transferStock, From 652087338450c82d450325d5a57427331290aabe Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 20 Sep 2023 08:37:48 +1000 Subject: [PATCH 421/746] Translation fix (#424) * Fix locale header - Moving to new framework meant that Intl.getCurrentLocale was no longer working * Update release notes * Fix typo in pubspec.yaml * Clear cached values when locale is changed * Add extra context check --- assets/release_notes.md | 1 + lib/api.dart | 47 +++++++++++++++++++++++++++------- lib/main.dart | 2 ++ lib/settings/app_settings.dart | 4 +++ pubspec.yaml | 2 +- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index dd851dc..3ed94b8 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Added extra options for transferring stock items +- Fixes bug where API data was not fetched with correct locale ### 0.12.7 - August 2023 --- diff --git a/lib/api.dart b/lib/api.dart index b8a4f21..ba64171 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -5,6 +5,8 @@ import "dart:io"; import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; import "package:intl/intl.dart"; +import "package:inventree/main.dart"; +import "package:one_context/one_context.dart"; import "package:open_filex/open_filex.dart"; import "package:cached_network_image/cached_network_image.dart"; import "package:flutter/material.dart"; @@ -772,10 +774,9 @@ class InvenTreeAPI { _request = await client.openUrl("GET", _uri).timeout(Duration(seconds: 10)); // Set headers - _request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader()); - _request.headers.set(HttpHeaders.acceptHeader, "application/json"); - _request.headers.set(HttpHeaders.contentTypeHeader, "application/json"); - _request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale()); + defaultHeaders().forEach((key, value) { + _request?.headers.set(key, value); + }); } on SocketException catch (error) { debug("SocketException at ${url}: ${error.toString()}"); @@ -1083,10 +1084,9 @@ class InvenTreeAPI { _request = await client.openUrl(method, _uri).timeout(Duration(seconds: 10)); // Set headers - _request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader()); - _request.headers.set(HttpHeaders.acceptHeader, "application/json"); - _request.headers.set(HttpHeaders.contentTypeHeader, "application/json"); - _request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale()); + defaultHeaders().forEach((key, value) { + _request?.headers.set(key, value); + }); return _request; } on SocketException catch (error) { @@ -1268,6 +1268,7 @@ class InvenTreeAPI { urlParams: params, ); + if (request == null) { // Return an "invalid" APIResponse return APIResponse( @@ -1305,6 +1306,28 @@ class InvenTreeAPI { ); } + // Find the current locale code for the running app + String get currentLocale { + + if (OneContext.hasContext) { + // Try to get app context + BuildContext? context = OneContext().context; + + if (context != null) { + Locale? locale = InvenTreeApp + .of(context) + ?.locale; + + if (locale != null) { + return locale.languageCode; //.toString(); + } + } + } + + // Fallback value + return Intl.getCurrentLocale(); + } + // Return a list of request headers Map defaultHeaders() { Map headers = {}; @@ -1312,7 +1335,7 @@ class InvenTreeAPI { headers[HttpHeaders.authorizationHeader] = _authorizationHeader(); headers[HttpHeaders.acceptHeader] = "application/json"; headers[HttpHeaders.contentTypeHeader] = "application/json"; - headers[HttpHeaders.acceptLanguageHeader] = Intl.getCurrentLocale(); + headers[HttpHeaders.acceptLanguageHeader] = currentLocale; return headers; } @@ -1527,6 +1550,12 @@ class InvenTreeAPI { InvenTreeStatusCode get StockStatus => _get_status_class("stock/status/"); InvenTreeStatusCode get PurchaseOrderStatus => _get_status_class("order/po/status/"); + void clearStatusCodeData() { + StockHistoryStatus.data.clear(); + StockStatus.data.clear(); + PurchaseOrderStatus.data.clear(); + } + int notification_counter = 0; Timer? _notification_timer; diff --git a/lib/main.dart b/lib/main.dart index aa2adb6..3a7d2f4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -152,6 +152,8 @@ class InvenTreeAppState extends State { }); } + Locale? get locale => _locale; + @override Widget build(BuildContext context) { diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 1937ff5..f5d2ab4 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:inventree/api.dart"; import "package:one_context/one_context.dart"; import "package:adaptive_theme/adaptive_theme.dart"; @@ -120,6 +121,9 @@ class _InvenTreeAppSettingsState extends State { // Refresh the entire app locale InvenTreeApp.of(context)?.setLocale(locale); + + // Clear the cached status label information + InvenTreeAPI().clearStatusCodeData(); } ); } diff --git a/pubspec.yaml b/pubspec.yaml index ab68b3e..d4d197a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.7+74 +version: 0.12.8+75 environment: sdk: ">=2.19.5 <3.13.0" From 3cc57101c4f344014974d84e5b2e0f240f18fc05 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 21 Sep 2023 21:17:55 +1000 Subject: [PATCH 422/746] Android: reduce minSdkVersion to 21 (#426) Fixes https://github.com/inventree/inventree-app/issues/425 --- android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 7105a67..0a28e9a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,7 +48,7 @@ android { defaultConfig { applicationId "inventree.inventree_app" - minSdkVersion 33 + minSdkVersion 21 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName From a119bcc465769e9917f13fe3ff8a95931f36c99b Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 1 Oct 2023 13:46:37 +1100 Subject: [PATCH 423/746] New translations app_en.arb (Spanish, Mexico) (#427) --- lib/l10n/es_MX/app_es_MX.arb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 1e0bd1a..512859d 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -250,6 +250,8 @@ "@filterComponentDetail": {}, "filterExternal": "Externo", "@filterExternal": {}, + "filterExternalDetail": "Mostrar existencias en ubicaciones exteriores", + "@filterExternalDetail": {}, "filterInStock": "En Existencia", "@filterInStock": {}, "filterInStockDetail": "Mostrar partes que tienen existencias", @@ -809,9 +811,9 @@ "@sublocation": {}, "sublocations": "Sub-ubicaciones", "@sublocations": {}, - "sublocationNone": "Sin sublocalizaciones", + "sublocationNone": "Sin sub-ubicaciones", "@sublocationNone": {}, - "sublocationNoneDetail": "No hay sublocalizaciones disponibles", + "sublocationNoneDetail": "No hay sub-ubicaciones disponibles", "@sublocationNoneDetail": {}, "submitFeedback": "Enviar comentarios", "@submitFeedback": {}, @@ -851,13 +853,13 @@ }, "testResultsDetail": "Mostrar los resultados de prueba de artículos en stock", "@testResultsDetail": {}, - "testResultAdd": "Añadir Resultado de Prueba", + "testResultAdd": "Añadir resultado de prueba", "@testResultAdd": {}, - "testResultNone": "No hay resultados de la prueba", + "testResultNone": "No hay resultados de prueba", "@testResultNone": {}, - "testResultNoneDetail": "No hay resultados disponibles", + "testResultNoneDetail": "No hay resultados de prueba disponibles", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error al cargar el resultado de la prueba", + "testResultUploadFail": "Error al cargar el resultado de prueba", "@testResultUploadFail": {}, "testResultUploadPass": "Resultado de prueba cargado", "@testResultUploadPass": {}, From f4be87e826a953da75cd712676c4d477701a7a84 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Oct 2023 00:17:44 +1100 Subject: [PATCH 424/746] New Crowdin updates (#429) * New translations app_en.arb (Russian) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/ru_RU/app_ru_RU.arb | 52 +++++++++++++++--- lib/l10n/zh_CN/app_zh_CN.arb | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 6 deletions(-) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 4c1d648..0d4cb0c 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -38,7 +38,7 @@ "@appReleaseNotes": {}, "appSettings": "Настройки приложения", "@appSettings": {}, - "appSettingsDetails": "Изменить настройки приложения", + "appSettingsDetails": "Изменить настройки приложения InvenTree", "@appSettingsDetails": {}, "attachments": "Вложения", "@attachments": {}, @@ -86,13 +86,15 @@ "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Сканировать штрих-код InvenTree", "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Сканировать товары на складе в это место", + "@barcodeScanInItems": {}, "barcodeScanLocation": "Сканировать местоположение склада", "@barcodeScanLocation": {}, - "barcodeScanIntoLocationSuccess": "Сканировано в местоположение", + "barcodeScanIntoLocationSuccess": "Сканирование на место", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Элемент не просканирован в", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Сканировать товар в наличии", + "barcodeScanItem": "Сканировать складскую позицию", "@barcodeScanItem": {}, "barcodeTones": "Сигналы штрих-кода", "@barcodeTones": {}, @@ -110,7 +112,7 @@ "@bomEnable": {}, "build": "Сборка", "@build": {}, - "building": "Здание", + "building": "Построение", "@building": {}, "cancel": "Отменить", "@cancel": { @@ -138,13 +140,13 @@ "@companies": {}, "configureServer": "Настройка параметров сервера", "@configureServer": {}, - "connectionRefused": "В соединении отказано", + "connectionRefused": "Отказано в подключении", "@connectionRefused": {}, "count": "Количество", "@count": { "description": "Count" }, - "countStock": "Количество на складе", + "countStock": "Количество в наличии", "@countStock": { "description": "Count Stock" }, @@ -200,6 +202,8 @@ }, "editItem": "Отредактированный товар", "@editItem": {}, + "editLineItem": "Изменить позицию", + "@editLineItem": {}, "enterPassword": "Введите пароль", "@enterPassword": {}, "enterUsername": "Введите имя пользователя", @@ -254,6 +258,8 @@ "@filterInStockDetail": {}, "filterSerialized": "Упорядочено", "@filterSerialized": {}, + "filterSerializedDetail": "Показать номерные позиции на складе", + "@filterSerializedDetail": {}, "filterTemplate": "Шаблон", "@filterTemplate": {}, "filterTemplateDetail": "Показать шаблоны компонентов", @@ -379,12 +385,20 @@ "@lineItem": {}, "lineItems": "Элементы строки", "@lineItems": {}, + "lineItemUpdated": "Позиция обновлена", + "@lineItemUpdated": {}, + "locateItem": "Найти деталь на складе", + "@locateItem": {}, + "locateLocation": "Найти местоположение склада", + "@locateLocation": {}, "locationCreate": "Новое местоположение", "@locationCreate": {}, "locationCreateDetail": "Создать новое расположение склада", "@locationCreateDetail": {}, "locationNotSet": "Не указано месторасположение", "@locationNotSet": {}, + "locationUpdated": "Расположение склада обновлено", + "@locationUpdated": {}, "link": "Ссылка", "@link": {}, "lost": "Потерян", @@ -433,6 +447,10 @@ "@orientationPortrait": {}, "orientationSystem": "Система", "@orientationSystem": {}, + "outstanding": "Не оплачено", + "@outstanding": {}, + "outstandingOrderDetail": "Показать не оплаченные товары", + "@outstandingOrderDetail": {}, "packaging": "Упаковка", "@packaging": {}, "packageName": "Название упаковки", @@ -469,6 +487,8 @@ "@partSettings": {}, "partsStarred": "Детали с включёнными уведомлениями", "@partsStarred": {}, + "partsStarredNone": "Отмеченные детали не доступны", + "@partsStarredNone": {}, "partSuppliers": "Поставщики детали", "@partSuppliers": {}, "partCategory": "Категория детали", @@ -527,6 +547,10 @@ "@profileSelect": {}, "profileSelectOrCreate": "Выбрать сервер или создать новый профиль", "@profileSelectOrCreate": {}, + "profileTapToCreate": "Нажмите, чтобы создать или выбрать профиль", + "@profileTapToCreate": {}, + "projectCode": "Код проекта", + "@projectCode": {}, "purchaseOrder": "Заказ на поставку", "@purchaseOrder": {}, "purchaseOrderCreate": "Новый заказ на поставку", @@ -775,12 +799,26 @@ "@stockLocations": {}, "stockTopLevel": "Склад верхнего уровня", "@stockTopLevel": {}, + "strictHttps": "Использовать строго HTTPS", + "@strictHttps": {}, "strictHttpsDetails": "Принудительная проверка HTTPs сертификатов", "@strictHttpsDetails": {}, "subcategory": "Подкатегория:", "@subcategory": {}, "subcategories": "Подкатегории", "@subcategories": {}, + "sublocation": "Подрасположение", + "@sublocation": {}, + "sublocations": "Подрасположения", + "@sublocations": {}, + "sublocationNone": "Нет подрасположений", + "@sublocationNone": {}, + "sublocationNoneDetail": "Нет доступных подрасположений", + "@sublocationNoneDetail": {}, + "submitFeedback": "Отправить отзыв", + "@submitFeedback": {}, + "suppliedParts": "Поставляемые детали", + "@suppliedParts": {}, "supplier": "Поставщик", "@supplier": {}, "supplierPart": "Деталь поставщика", @@ -797,6 +835,8 @@ "@suppliers": {}, "supplierReference": "Ссылка на поставщика", "@supplierReference": {}, + "takePicture": "Сделать снимок", + "@takePicture": {}, "targetDate": "Целевая дата", "@targetDate": {}, "templatePart": "Родительская шаблонная деталь", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index db7dc46..d07878e 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -54,8 +54,14 @@ "@attachmentSelect": {}, "attention": "注意", "@attention": {}, + "available": "可用的", + "@available": {}, "availableStock": "可用库存", "@availableStock": {}, + "barcodes": "条形码", + "@barcodes": {}, + "barcodeSettings": "条形码设置", + "@barcodeSettings": {}, "barcodeAssign": "分配条码", "@barcodeAssign": {}, "barcodeAssignDetail": "扫描自定义条形码进行分配", @@ -74,6 +80,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "扫描以分配条码", "@barcodeScanAssign": {}, + "barcodeScanDelay": "条形码扫描延迟", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "条形码扫描之间的延迟", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "扫描 InvenTree 条码", "@barcodeScanGeneral": {}, "barcodeScanInItems": "扫描库存物品到此位置", @@ -108,6 +118,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "取消订单", + "@cancelOrder": {}, "category": "分类", "@category": {}, "categoryCreate": "新建分类", @@ -144,6 +156,10 @@ "@customers": {}, "damaged": "破损", "@damaged": {}, + "darkMode": "暗色模式", + "@darkMode": {}, + "darkModeEnable": "启用暗色模式", + "@darkModeEnable": {}, "delete": "删除", "@delete": {}, "deleteFailed": "删除失败", @@ -178,12 +194,16 @@ "@editLocation": {}, "editNotes": "编辑备注", "@editNotes": {}, + "editParameter": "编辑参数", + "@editParameter": {}, "editPart": "编辑部件", "@editPart": { "description": "edit part" }, "editItem": "编辑库存物品", "@editItem": {}, + "editLineItem": "编辑列表条目", + "@editLineItem": {}, "enterPassword": "输入密码", "@enterPassword": {}, "enterUsername": "输入用户名", @@ -200,6 +220,10 @@ "@errorDetails": {}, "errorFetch": "从服务器获取数据时出现了一个错误", "@errorFetch": {}, + "errorUserRoles": "从服务器请求用户角色时出错", + "@errorUserRoles": {}, + "errorPluginInfo": "从服务器请求插件数据时出错", + "@errorPluginInfo": {}, "errorReporting": "错误报告", "@errorReporting": {}, "errorReportUpload": "上传错误报告", @@ -224,6 +248,10 @@ "@filterComponent": {}, "filterComponentDetail": "显示组件部分", "@filterComponentDetail": {}, + "filterExternal": "外部的", + "@filterExternal": {}, + "filterExternalDetail": "显示外部仓储地点的库存", + "@filterExternalDetail": {}, "filterInStock": "库存充足", "@filterInStock": {}, "filterInStockDetail": "显示有库存的部分", @@ -307,6 +335,8 @@ "@inProduction": {}, "inProductionDetail": "库存品正在生产", "@inProductionDetail": {}, + "internalPart": "内部零件", + "@internalPart": {}, "invalidHost": "无效的主机名", "@invalidHost": {}, "invalidHostDetails": "提供的主机名无效", @@ -323,12 +353,20 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "无效的用户名密码组合", "@invalidUsernamePassword": {}, + "issue": "下单任务", + "@issue": {}, "issueDate": "签发日期", "@issueDate": {}, + "issueOrder": "下达订单", + "@issueOrder": {}, "itemInLocation": "物品已就位", "@itemInLocation": {}, "keywords": "关键词", "@keywords": {}, + "labelPrinting": "打印标签", + "@labelPrinting": {}, + "labelPrintingDetail": "启用标签打印功能", + "@labelPrintingDetail": {}, "labelTemplate": "标签模板", "@labelTemplate": {}, "language": "语言", @@ -337,10 +375,36 @@ "@languageDefault": {}, "languageSelect": "选择语言", "@languageSelect": {}, + "lastStocktake": "最近库存盘点", + "@lastStocktake": {}, + "lastUpdated": "最近更新", + "@lastUpdated": {}, + "level": "级", + "@level": {}, + "lineItem": "行条目", + "@lineItem": {}, + "lineItems": "行条目", + "@lineItems": {}, + "lineItemUpdated": "行条目已更新", + "@lineItemUpdated": {}, + "locateItem": "定位库存项", + "@locateItem": {}, + "locationCreate": "新建仓储位置", + "@locationCreate": {}, + "locationNotSet": "没有指定仓储位置", + "@locationNotSet": {}, "link": "链接", "@link": {}, "lost": "丢失", "@lost": {}, + "manufacturerPartNumber": "制造商零件号", + "@manufacturerPartNumber": {}, + "manufacturer": "制造商", + "@manufacturer": {}, + "manufacturers": "制造商", + "@manufacturers": {}, + "missingData": "缺失数据", + "@missingData": {}, "name": "名称", "@name": {}, "notConnected": "未连接", @@ -349,6 +413,8 @@ "@notes": { "description": "Notes" }, + "notifications": "通知", + "@notifications": {}, "notificationsEmpty": "没有未读通知", "@notificationsEmpty": {}, "noResponse": "服务器未响应", @@ -361,6 +427,24 @@ "@noSubcategoriesAvailable": {}, "numberInvalid": "无效的数字", "@numberInvalid": {}, + "onOrder": "已订购", + "@onOrder": {}, + "onOrderDetails": "当前订购项目", + "@onOrderDetails": {}, + "orientation": "屏幕方向​​​​​​​​​​​​​​", + "@orientation": {}, + "orientationDetail": "屏幕方向(需要重启)", + "@orientationDetail": {}, + "orientationLandscape": "横向", + "@orientationLandscape": {}, + "orientationPortrait": "纵向", + "@orientationPortrait": {}, + "orientationSystem": "系统", + "@orientationSystem": {}, + "outstanding": "未完成", + "@outstanding": {}, + "outstandingOrderDetail": "显示未完成项目", + "@outstandingOrderDetail": {}, "packaging": "打包", "@packaging": {}, "packageName": "包名", @@ -397,8 +481,14 @@ "@partSettings": {}, "partsStarred": "订阅的商品", "@partsStarred": {}, + "partsStarredNone": "没有可用的带星号零件", + "@partsStarredNone": {}, + "partSuppliers": "配件供货商", + "@partSuppliers": {}, "partCategory": "部件分类", "@partCategory": {}, + "partCategoryTopLevel": "上一级零件类别", + "@partCategoryTopLevel": {}, "partCategories": "部件分类", "@partCategories": {}, "partDetails": "部件详情", @@ -411,6 +501,10 @@ }, "password": "密码", "@password": {}, + "passwordEmpty": "密码不能为空", + "@passwordEmpty": {}, + "permissionAccountDenied": "您的帐户没有执行此操作所需的权限", + "@permissionAccountDenied": {}, "profile": "档案", "@profile": {}, "quantity": "数量", @@ -457,6 +551,10 @@ "@result": { "description": "" }, + "returned": "已退回", + "@returned": {}, + "salesOrders": "销售订单", + "@salesOrders": {}, "save": "保存", "@save": { "description": "Save" @@ -469,6 +567,10 @@ "@search": { "description": "search" }, + "searching": "搜索", + "@searching": {}, + "searchLocation": "搜索仓储位置", + "@searchLocation": {}, "searchParts": "搜索部件", "@searchParts": {}, "searchStock": "搜索库存", From c76309341bf2f1955cb4d2a30d46c177d2bc5fd6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 8 Oct 2023 20:18:14 +1100 Subject: [PATCH 425/746] New translations app_en.arb (German) (#430) --- lib/l10n/de_DE/app_de_DE.arb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 9b3bae1..5861b9f 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -54,6 +54,8 @@ "@attachmentSelect": {}, "attention": "Achtung", "@attention": {}, + "available": "verfügbar", + "@available": {}, "availableStock": "Verfügbarer Lagerbestand", "@availableStock": {}, "barcodes": "Barcodes", @@ -78,6 +80,10 @@ "@barcodeNotAssigned": {}, "barcodeScanAssign": "Scannen um Barcode zuzuweisen", "@barcodeScanAssign": {}, + "barcodeScanDelay": "Barcode Scan-Verzögerung", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Verzögerung zwischen Barcode-Scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Einen InvenTree Barcode scannen", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Artikel per Barcode-Scan zu diesem Lagerort hinzufügen", @@ -242,6 +248,10 @@ "@filterComponent": {}, "filterComponentDetail": "Teil-Komponenten zeigen", "@filterComponentDetail": {}, + "filterExternal": "extern", + "@filterExternal": {}, + "filterExternalDetail": "Lagerbestand an externen Standorten anzeigen", + "@filterExternalDetail": {}, "filterInStock": "Auf Lager", "@filterInStock": {}, "filterInStockDetail": "Teile zeigen, die einen Lagerbestand haben", @@ -353,6 +363,10 @@ "@itemInLocation": {}, "keywords": "Schlüsselwörter", "@keywords": {}, + "labelPrinting": "Etikettendruck", + "@labelPrinting": {}, + "labelPrintingDetail": "Etikettendruck aktivieren", + "@labelPrintingDetail": {}, "labelTemplate": "Label Vorlage", "@labelTemplate": {}, "language": "Sprache", @@ -387,6 +401,8 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturerPartNumber": "Teilenummer des Herstellers", + "@manufacturerPartNumber": {}, "manufacturer": "Hersteller", "@manufacturer": {}, "manufacturers": "Hersteller", @@ -419,6 +435,14 @@ "@onOrder": {}, "onOrderDetails": "Artikel wurde bestellt", "@onOrderDetails": {}, + "orientation": "Bildschirmausrichtung", + "@orientation": {}, + "orientationDetail": "Bildschirmausrichtung (Neustart erforderlich)", + "@orientationDetail": {}, + "orientationLandscape": "Querformat", + "@orientationLandscape": {}, + "orientationPortrait": "Hochformat", + "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, "outstanding": "Ausstehend", @@ -797,6 +821,8 @@ "@supplierPart": {}, "supplierPartEdit": "Zuliefererteil bearbeiten", "@supplierPartEdit": {}, + "supplierPartNumber": "Teilenummer des Zulieferers", + "@supplierPartNumber": {}, "supplierPartUpdated": "Zuliefererteil aktualisiert", "@supplierPartUpdated": {}, "supplierParts": "Zuliefererteile", @@ -861,6 +887,8 @@ "@translate": {}, "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", "@translateHelp": {}, + "unitPrice": "Einzelpreis", + "@unitPrice": {}, "units": "Einheiten", "@units": {}, "unknownResponse": "Unbekannte Antwort", From 67fd6a564a63d2ca6aa0e0e06cb12614c929f487 Mon Sep 17 00:00:00 2001 From: Bobbe <34186858+30350n@users.noreply.github.com> Date: Thu, 19 Oct 2023 14:28:32 +0200 Subject: [PATCH 426/746] Add POReceiveBarcodeHandler to support barcode/po-receive/ endpoint (#421) * Add POReceiveBarcodeHandler to support barcode/po-receive/ endpoint * Remove german translation * Add api version checks * Add getOverlayText method to barcode handler * Bump required API version to 139 * Update barcode.dart The "quantity" field is not an integer, and can cause the app to crash if not handled correctly --------- Co-authored-by: Oliver --- lib/api.dart | 2 + lib/barcode/barcode.dart | 111 ++++++++++++++++++++++++++ lib/barcode/handler.dart | 6 +- lib/l10n/app_en.arb | 6 ++ lib/widget/location_display.dart | 15 ++++ lib/widget/purchase_order_detail.dart | 24 ++++++ lib/widget/purchase_order_list.dart | 23 ++++++ 7 files changed, 185 insertions(+), 2 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index ba64171..6ea7880 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -328,6 +328,8 @@ class InvenTreeAPI { // Does the server support extra fields on stock adjustment actions? bool get supportsStockAdjustExtraFields => isConnected() && apiVersion >= 133; + bool get supportsBarcodePOReceiveEndpoint => isConnected() && apiVersion >= 139; + // Are plugins enabled on the server? bool _pluginsEnabled = false; diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index d87f34c..6a2a069 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -6,6 +6,7 @@ import "package:one_context/one_context.dart"; import "package:inventree/api.dart"; +import "package:inventree/api_form.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -462,6 +463,116 @@ class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { } +/* + * Barcode handler class for scanning a supplier barcode to receive a part + * + * - The class can be initialized by optionally passing a valid, placed PurchaseOrder object + * - Expects to scan supplier barcode, possibly containing order_number and quantity + * - If location or quantity information wasn't provided, show a form to fill it in + */ +class POReceiveBarcodeHandler extends BarcodeHandler { + + POReceiveBarcodeHandler({this.purchaseOrder, this.location}); + + InvenTreePurchaseOrder? purchaseOrder; + InvenTreeStockLocation? location; + + @override + String getOverlayText(BuildContext context) => L10().barcodeReceivePart; + + @override + Future processBarcode(String barcode, + {String url = "barcode/po-receive/", + Map extra_data = const {}}) { + + final po_extra_data = { + "purchase_order": purchaseOrder?.pk, + "location": location?.pk, + ...extra_data, + }; + + return super.processBarcode(barcode, url: url, extra_data: po_extra_data); + } + + @override + Future onBarcodeMatched(Map data) async { + if (!data.containsKey("lineitem")) { + return onBarcodeUnknown(data); + } + + barcodeSuccessTone(); + showSnackIcon(L10().receivedItem, success: true); + } + + @override + Future onBarcodeUnhandled(Map data) async { + if (!data.containsKey("action_required") || !data.containsKey("lineitem")) { + return super.onBarcodeUnhandled(data); + } + + final lineItemData = data["lineitem"] as Map; + if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { + barcodeFailureTone(); + showSnackIcon(L10().missingData, success: false); + } + + // Construct fields to receive + Map fields = { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + "value": lineItemData["pk"] as int, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": lineItemData["quantity"] as double?, + }, + "status": { + "parent": "items", + "nested": true, + }, + "location": { + "value": lineItemData["location"] as int?, + }, + "barcode": { + "parent": "items", + "nested": true, + "hidden": true, + "type": "barcode", + "value": data["barcode_data"] as String, + } + }; + + final context = OneContext().context!; + final purchase_order_pk = lineItemData["purchase_order"]; + final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; + + launchApiForm( + context, + L10().receiveItem, + receive_url, + fields, + method: "POST", + icon: FontAwesomeIcons.rightToBracket, + onSuccess: (data) async { + showSnackIcon(L10().receivedItem, success: true); + } + ); + } + + @override + Future onBarcodeUnknown(Map data) async { + barcodeFailureTone(); + showSnackIcon( + data["error"] as String? ?? L10().barcodeError, + success: false + ); + } +} + + /* * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) */ diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index 3d72e9c..5048f63 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -58,8 +58,9 @@ class BarcodeHandler { * * Returns true only if the barcode scanner should remain open */ - Future processBarcode(String barcode, {String url = "barcode/"}) async { - + Future processBarcode(String barcode, + {String url = "barcode/", + Map extra_data = const {}}) async { debug("Scanned barcode data: '${barcode}'"); barcode = barcode.trim(); @@ -82,6 +83,7 @@ class BarcodeHandler { url, body: { "barcode": barcode, + ...extra_data, }, expectedStatusCode: null, // Do not show an error on "unexpected code" ); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9589f9b..673d284 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -112,6 +112,9 @@ "barcodeNotAssigned": "Barcode not assigned", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -988,6 +991,9 @@ "scanIntoLocationDetail": "Scan this item into location", "@scanIntoLocationDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", "@search": { "description": "search" diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 0ca1c5d..4e89f86 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -104,6 +104,21 @@ class _LocationDisplayState extends RefreshableState { ); } + if (api.supportsBarcodePOReceiveEndpoint) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().scanReceivedParts, + onTap:() async { + scanBarcode( + context, + handler: POReceiveBarcodeHandler(location: location), + ); + }, + ) + ); + } + // Scan this location into another one if (InvenTreeStockLocation().canEdit) { actions.add( diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index ba870a4..f03d4f0 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -6,6 +6,7 @@ import "package:inventree/widget/po_line_list.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -132,6 +133,29 @@ class _PurchaseOrderDetailState extends RefreshableState barcodeButtons(BuildContext context) { + List actions = []; + + if (api.supportsBarcodePOReceiveEndpoint) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().scanReceivedParts, + onTap:() async { + scanBarcode( + context, + handler: POReceiveBarcodeHandler(purchaseOrder: order), + ); + }, + ) + ); + } + + return actions; + } + + @override Future request(BuildContext context) async { await order.reload(); diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart index cdb8b8b..4404656 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/purchase_order_list.dart @@ -9,6 +9,7 @@ import "package:inventree/widget/purchase_order_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/inventree/purchase_order.dart"; /* @@ -79,6 +80,28 @@ class _PurchaseOrderListWidgetState extends RefreshableState barcodeButtons(BuildContext context) { + List actions = []; + + if (api.supportsBarcodePOReceiveEndpoint) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().scanReceivedParts, + onTap:() async { + scanBarcode( + context, + handler: POReceiveBarcodeHandler(), + ); + }, + ) + ); + } + + return actions; + } + @override Widget getBody(BuildContext context) { return PaginatedPurchaseOrderList(filters); From c65833cf6d79d220fb82faef0c70ba3b83d0505c Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 Oct 2023 23:29:33 +1100 Subject: [PATCH 427/746] New Crowdin updates (#431) * New translations app_en.arb (German) * New translations app_en.arb (Japanese) --- lib/l10n/de_DE/app_de_DE.arb | 8 +++++++- lib/l10n/ja_JP/app_ja_JP.arb | 24 ++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 5861b9f..af8ee30 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -385,6 +385,8 @@ "@lineItem": {}, "lineItems": "Positionen", "@lineItems": {}, + "lineItemUpdated": "Position aktualisiert", + "@lineItemUpdated": {}, "locateItem": "Lagerbestand lokalisieren", "@locateItem": {}, "locateLocation": "Lagerort lokalisieren", @@ -737,6 +739,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, + "sku": "Artikelnummer", + "@sku": {}, "sounds": "Töne", "@sounds": {}, "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", @@ -847,6 +851,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Testergebnisse für Lagerartikel anzeigen", + "@testResultsDetail": {}, "testResultAdd": "Testergebnis hinzufügen", "@testResultAdd": {}, "testResultNone": "Keine Testergebnisse", @@ -887,7 +893,7 @@ "@translate": {}, "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", "@translateHelp": {}, - "unitPrice": "Einzelpreis", + "unitPrice": "Preis pro Einheit", "@unitPrice": {}, "units": "Einheiten", "@units": {}, diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 0e2b7ce..fc36078 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,5 +1,9 @@ { "@@locale": "ja", + "ok": "はい", + "@ok": { + "description": "OK" + }, "about": "概要", "@about": {}, "accountDetails": "アカウントの詳細", @@ -48,6 +52,8 @@ "@attention": {}, "availableStock": "在庫あり", "@availableStock": {}, + "barcodeSettings": "バーコード設定", + "@barcodeSettings": {}, "barcodeAssign": "バーコードを割り当てる", "@barcodeAssign": {}, "barcodeAssigned": "バーコードが割り当てられました", @@ -190,11 +196,11 @@ "@feedbackSuccess": {}, "filterActive": "有効", "@filterActive": {}, - "filterActiveDetail": "有効な部品を表示", + "filterActiveDetail": "有効なパーツを表示", "@filterActiveDetail": {}, "filterAssembly": "組立済み", "@filterAssembly": {}, - "filterAssemblyDetail": "組み立てられた部品を表示", + "filterAssemblyDetail": "組み立てられたパーツを表示", "@filterAssemblyDetail": {}, "filterComponent": "コンポーネント", "@filterComponent": {}, @@ -202,11 +208,13 @@ "@filterComponentDetail": {}, "filterInStock": "在庫あり", "@filterInStock": {}, - "filterInStockDetail": "在庫がある部品を表示", + "filterInStockDetail": "在庫があるパーツを表示", "@filterInStockDetail": {}, "filterTemplate": "テンプレート", "@filterTemplate": {}, - "filterVirtualDetail": "仮想部品を表示", + "filterVirtual": "仮想", + "@filterVirtual": {}, + "filterVirtualDetail": "仮想パーツを表示", "@filterVirtualDetail": {}, "formatException": "フォーマットの例外エラー", "@formatException": {}, @@ -338,6 +346,8 @@ "@part": { "description": "Part (single)" }, + "partCreateDetail": "このカテゴリに新しいパーツを作成", + "@partCreateDetail": {}, "parts": "パーツ", "@parts": { "description": "Part (multiple)" @@ -558,6 +568,8 @@ "@stock": { "description": "stock" }, + "stockDetails": "現在の在庫数", + "@stockDetails": {}, "stockItem": "在庫アイテム", "@stockItem": { "description": "stock item title" @@ -660,6 +672,10 @@ "@transferStock": { "description": "transfer stock" }, + "transferStockLocation": "在庫の保管場所を移動", + "@transferStockLocation": {}, + "transferStockLocationDetail": "この在庫を他の場所に移動する", + "@transferStockLocationDetail": {}, "translate": "翻訳", "@translate": {}, "translateHelp": "InvenTree アプリの翻訳に協力する", From 0d44bd37996bbc7ded8792aa9a6a3713d1299f38 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 Oct 2023 23:35:13 +1100 Subject: [PATCH 428/746] Update release_notes.md (#432) --- assets/release_notes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3ed94b8..31e37f5 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.13.0 - October 2023 +--- + +- Add ability to scan in received items using supplier barcodes + ### 0.12.8 - September 2023 --- From 382c8461f9fadd35da02618b2f1abc5b46ae8e44 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 21 Oct 2023 23:24:02 +1100 Subject: [PATCH 429/746] New translations app_en.arb (Japanese) (#433) --- lib/l10n/ja_JP/app_ja_JP.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index fc36078..8a8e081 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -500,7 +500,7 @@ "@search": { "description": "search" }, - "searchLocation": "在庫場所場所を検索", + "searchLocation": "在庫場所を検索", "@searchLocation": {}, "searchParts": "パーツの検索", "@searchParts": {}, From 76b6191a675026eb3849e8afc0f0e6a051f7834b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Oct 2023 01:29:16 +1100 Subject: [PATCH 430/746] Token auth (#434) * Embed device platform information into token request * Remove username and password from userProfile * Display icon to show if profile has associated user token * Remove username / password from login settings screen * Refactor login procedure around token auth * Refactoring * Add profile login screen - Username / password values are not stored - Just to fetch api token * Login with basic auth * Pass profile to API when connecting * Remove _BASE_URL accessor - Fixes URL caching bug * Add more context to login screen * Add helper functions for unit tests - Change default port to 8000 (makes testing easier with local inventree instance) * api.dart handles basic auth now * fix api_test.dart * Further test improvements * linting fixes * Provide feedback when login fails * More linting * Record user details on login, and display in "about" widget * Fix string lookup * Add extra debug * Fix auth values * Fix user profile test --- .github/workflows/ci.yaml | 5 +- assets/release_notes.md | 3 + lib/api.dart | 383 +++++++++++++---------- lib/inventree/purchase_order.dart | 12 +- lib/inventree/sentry.dart | 5 +- lib/l10n/app_en.arb | 12 + lib/settings/about.dart | 14 +- lib/settings/login.dart | 485 ++++++++---------------------- lib/settings/select_server.dart | 430 ++++++++++++++++++++++++++ lib/settings/settings.dart | 4 +- lib/user_profile.dart | 51 ++-- lib/widget/dialogs.dart | 78 +++-- lib/widget/home.dart | 6 +- test/api_test.dart | 94 +++--- test/barcode_test.dart | 24 +- test/models_test.dart | 12 +- test/setup.dart | 76 +++++ test/user_profile_test.dart | 34 +-- 18 files changed, 1023 insertions(+), 705 deletions(-) create mode 100644 lib/settings/select_server.dart diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 02111c8..4e3e371 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,9 +18,6 @@ env: INVENTREE_ADMIN_USER: testuser INVENTREE_ADMIN_PASSWORD: testpassword INVENTREE_ADMIN_EMAIL: test@test.com - INVENTREE_PYTHON_TEST_SERVER: http://localhost:12345 - INVENTREE_PYTHON_TEST_USERNAME: testuser - INVENTREE_PYTHON_TEST_PASSWORD: testpassword jobs: test: @@ -64,7 +61,7 @@ jobs: invoke install invoke migrate invoke import-fixtures - invoke server -a 127.0.0.1:12345 & + invoke server -a 127.0.0.1:8000 & invoke wait sleep 30 - name: Unit Tests diff --git a/assets/release_notes.md b/assets/release_notes.md index 31e37f5..1bdcb63 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,9 @@ --- - Add ability to scan in received items using supplier barcodes +- Store API token, rather than username:password +- Ensure that user will lose access if token is revoked by server + ### 0.12.8 - September 2023 --- diff --git a/lib/api.dart b/lib/api.dart index 6ea7880..b8a2d7b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -192,16 +192,13 @@ class InvenTreeAPI { bool _strictHttps = false; // Endpoint for requesting an API token - static const _URL_GET_TOKEN = "user/token/"; - - static const _URL_GET_ROLES = "user/roles/"; - - // Base URL for InvenTree API e.g. http://192.168.120.10:8000 - String _BASE_URL = ""; + static const _URL_TOKEN = "user/token/"; + static const _URL_ROLES = "user/roles/"; + static const _URL_ME = "user/me/"; // Accessors for various url endpoints String get baseUrl { - String url = _BASE_URL; + String url = profile?.server ?? ""; if (!url.endsWith("/")) { url += "/"; @@ -242,21 +239,22 @@ class InvenTreeAPI { // Available user roles (permissions) are loaded when connecting to the server Map roles = {}; - // Authentication token (initially empty, must be requested) - String _token = ""; + // Profile authentication token + String get token => profile?.token ?? ""; + + bool get hasToken => token.isNotEmpty; String? get serverAddress { return profile?.server; } - bool get hasToken => _token.isNotEmpty; - /* * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. */ bool checkConnection() { - // Firstly, is the server connected? + + // Is the server connected? if (!isConnected()) { showSnackIcon( @@ -272,16 +270,20 @@ class InvenTreeAPI { return true; } - // Server instance information - String instance = ""; + // Map of user information + Map userInfo = {}; - // Server version information - String _version = ""; + String get username => (userInfo["username"] ?? "") as String; - // API version of the connected server - int _apiVersion = 1; + // Map of server information + Map serverInfo = {}; - int get apiVersion => _apiVersion; + String get serverInstance => (serverInfo["instance"] ?? "") as String; + String get serverVersion => (serverInfo["version"] ?? "") as String; + int get apiVersion => (serverInfo["apiVersion"] ?? 1) as int; + + // Plugins enabled at API v34 and above + bool get pluginsEnabled => apiVersion >= 34 && (serverInfo["plugins_enabled"] ?? false) as bool; // API endpoint for receiving purchase order line items was introduced in v12 bool get supportsPoReceive => apiVersion >= 12; @@ -330,13 +332,6 @@ class InvenTreeAPI { bool get supportsBarcodePOReceiveEndpoint => isConnected() && apiVersion >= 139; - // Are plugins enabled on the server? - bool _pluginsEnabled = false; - - // True plugin support requires API v34 or newer - // Returns True only if the server API version is new enough, and plugins are enabled - bool pluginsEnabled() => apiVersion >= 34 && _pluginsEnabled; - // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; @@ -363,9 +358,6 @@ class InvenTreeAPI { // Test if the provided plugin mixin is supported by any active plugins bool supportsMixin(String mixin) => getPlugins(mixin: mixin).isNotEmpty; - // Getter for server version information - String get version => _version; - // Connection status flag - set once connection has been validated bool _connected = false; @@ -379,33 +371,68 @@ class InvenTreeAPI { return !isConnected() && _connecting; } - /* - * Connect to the remote InvenTree server: - * - * - Check that the InvenTree server exists - * - Request user token from the server - * - Request user roles from the server - */ - Future _connect() async { - if (profile == null) return false; + /* + * Perform the required login steps, in sequence. + * Internal function, called by connectToServer() + * + * Performs the following steps: + * + * 1. Check the api/ endpoint to see if the sever exists + * 2. If no token available, perform user authentication + * 2. Check the api/user/me/ endpoint to see if the user is authenticated + * 3. If not authenticated, purge token, and exit + * 4. Request user roles + * 5. Request information on available plugins + */ + Future _connectToServer() async { + + if (!await _checkServer()) { + return false; + } + + if (!hasToken) { + return false; + } + + if (!await _checkAuth()) { + showServerError(_URL_ME, L10().serverNotConnected, L10().serverAuthenticationError); + + // Invalidate the token + if (profile != null) { + profile!.token = ""; + await UserProfileDBManager().updateProfile(profile!); + } + + return false; + } + + if (!await _fetchRoles()) { + return false; + } + + if (!await _fetchPlugins()) { + return false; + } + + // Finally, connected + return true; + } + + + /* + * Check that the remote server is available. + * Ping the api/ endpoint, which does not require user authentication + */ + Future _checkServer() async { String address = profile?.server ?? ""; - String username = profile?.username ?? ""; - String password = profile?.password ?? ""; - address = address.trim(); - username = username.trim(); - password = password.trim(); - - // Cache the "strictHttps" setting, so we can use it later without async requirement - _strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; - - if (address.isEmpty || username.isEmpty || password.isEmpty) { + if (address.isEmpty) { showSnackIcon( - L10().incompleteDetails, - icon: FontAwesomeIcons.circleExclamation, - success: false + L10().incompleteDetails, + icon: FontAwesomeIcons.circleExclamation, + success: false ); return false; } @@ -414,27 +441,24 @@ class InvenTreeAPI { address = address + "/"; } - _BASE_URL = address; + // Cache the "strictHttps" setting, so we can use it later without async requirement + _strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; - // Clear the list of available plugins - _plugins.clear(); + debug("Connecting to ${apiUrl}"); - debug("Connecting to ${apiUrl} -> username=${username}"); - - APIResponse response; - - response = await get("", expectedStatusCode: 200); + APIResponse response = await get("", expectedStatusCode: 200); if (!response.successful()) { + debug("Server returned invalid response: ${response.statusCode}"); showStatusCodeError(apiUrl, response.statusCode, details: response.data.toString()); return false; } - var data = response.asMap(); + Map _data = response.asMap(); - // We expect certain response from the server - if (!data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) { + serverInfo = {..._data}; + if (serverVersion.isEmpty) { showServerError( apiUrl, L10().missingData, @@ -444,17 +468,9 @@ class InvenTreeAPI { return false; } - // Record server information - _version = (data["version"] ?? "") as String; - instance = (data["instance"] ?? "") as String; + if (apiVersion < _minApiVersion) { - // Default API version is 1 if not provided - _apiVersion = (data["apiVersion"] ?? 1) as int; - _pluginsEnabled = (data["plugins_enabled"] ?? false) as bool; - - if (_apiVersion < _minApiVersion) { - - String message = L10().serverApiVersion + ": ${_apiVersion}"; + String message = L10().serverApiVersion + ": ${apiVersion}"; message += "\n"; message += L10().serverApiRequired + ": ${_minApiVersion}"; @@ -472,18 +488,86 @@ class InvenTreeAPI { return false; } - /** - * Request user token information from the server - * This is the stage that we check username:password credentials! - */ - // Clear the existing token value - _token = ""; + // At this point, we have a server which is responding + return true; + } - response = await get(_URL_GET_TOKEN); + + /* + * Check that the user is authenticated + * Fetch the user information + */ + Future _checkAuth() async { + debug("Checking user auth @ ${_URL_ME}"); + + userInfo.clear(); + + final response = await get(_URL_ME); + + if (response.successful() && response.statusCode == 200) { + userInfo = response.asMap(); + return true; + } else { + debug("Auth request failed: Server returned status ${response.statusCode}"); + if (response.data != null) { + debug("Server response: ${response.data.toString()}"); + } + + return false; + } + } + + /* + * Fetch a token from the server, + * with a temporary authentication header + */ + Future fetchToken(UserProfile userProfile, String username, String password) async { + + debug("Fetching user token from ${userProfile.server}"); + + profile = userProfile; + + // Form a name to request the token with + String platform_name = "inventree-mobile-app"; + + final deviceInfo = await getDeviceInfo(); + + if (Platform.isAndroid) { + platform_name += "-android"; + } else if (Platform.isIOS) { + platform_name += "-ios"; + } else if (Platform.isMacOS) { + platform_name += "-macos"; + } else if (Platform.isLinux) { + platform_name += "-linux"; + } else if (Platform.isWindows) { + platform_name += "-windows"; + } + + if (deviceInfo.containsKey("name")) { + platform_name += "-" + (deviceInfo["name"] as String); + } + + if (deviceInfo.containsKey("model")) { + platform_name += "-" + (deviceInfo["model"] as String); + } + + if (deviceInfo.containsKey("systemVersion")) { + platform_name += "-" + (deviceInfo["systemVersion"] as String); + } + + // Construct auth header from username and password + String authHeader = "Basic " + base64Encode(utf8.encode("${username}:${password}")); + + // Perform request to get a token + final response = await get( + _URL_TOKEN, + params: { "name": platform_name}, + headers: { HttpHeaders.authorizationHeader: authHeader} + ); // Invalid response if (!response.successful()) { - switch (response.statusCode) { case 401: case 403: @@ -500,67 +584,29 @@ class InvenTreeAPI { debug("Token request failed: STATUS ${response.statusCode}"); - return false; + if (response.data != null) { + debug("Response data: ${response.data.toString()}"); + } } - data = response.asMap(); + final data = response.asMap(); if (!data.containsKey("token")) { - showServerError( - apiUrl, - L10().tokenMissing, - L10().tokenMissingFromResponse, - ); - - return false; - } - - // Return the received token - _token = (data["token"] ?? "") as String; - - debug("Received token from server"); - - bool result = false; - - // Request user role information (async) - result = await getUserRoles(); - - if (!result) { showServerError( apiUrl, - L10().serverError, - L10().errorUserRoles, + L10().tokenMissing, + L10().tokenMissingFromResponse, ); - - return false; } - // Request plugin information (async) - result = await getPluginInformation(); + // Save the token to the user profile + userProfile.token = (data["token"] ?? "") as String; - if (!result) { - showServerError( - apiUrl, - L10().serverError, - L10().errorPluginInfo - ); + debug("Received token from server: ${userProfile.token}"); - return false; - } - - // Ok, probably pretty good... - - if (_notification_timer == null) { - debug("starting notification timer"); - _notification_timer = Timer.periodic( - Duration(seconds: 5), - (timer) { - _refreshNotifications(); - }); - } - - return true; + await UserProfileDBManager().updateProfile(userProfile); + return response; } void disconnectFromServer() { @@ -568,24 +614,25 @@ class InvenTreeAPI { _connected = false; _connecting = false; - _token = ""; profile = null; // Clear received settings _globalSettings.clear(); _userSettings.clear(); + serverInfo.clear(); _connectionStatusChanged(); } - // Public facing connection function - Future connectToServer() async { + + /* Public facing connection function. + */ + Future connectToServer(UserProfile prf) async { // Ensure server is first disconnected disconnectFromServer(); - // Load selected profile - profile = await UserProfileDBManager().getSelectedProfile(); + profile = prf; if (profile == null) { showSnackIcon( @@ -596,12 +643,14 @@ class InvenTreeAPI { return false; } - _connecting = true; + // Cancel notification timer + _notification_timer?.cancel(); + _connecting = true; _connectionStatusChanged(); - _connected = await _connect(); - + // Perform the actual connection routine + _connected = await _connectToServer(); _connecting = false; if (_connected) { @@ -610,6 +659,15 @@ class InvenTreeAPI { icon: FontAwesomeIcons.server, success: true, ); + + if (_notification_timer == null) { + debug("starting notification timer"); + _notification_timer = Timer.periodic( + Duration(seconds: 5), + (timer) { + _refreshNotifications(); + }); + } } _connectionStatusChanged(); @@ -620,18 +678,13 @@ class InvenTreeAPI { /* * Request the user roles (permissions) from the InvenTree server */ - Future getUserRoles() async { + Future _fetchRoles() async { roles.clear(); debug("API: Requesting user role data"); - // Next we request the permissions assigned to the current user - // Note: 2021-02-27 this "roles" feature for the API was just introduced. - // Any "older" version of the server allows any API method for any logged in user! - // We will return immediately, but request the user roles in the background - - final response = await get(_URL_GET_ROLES, expectedStatusCode: 200); + final response = await get(_URL_ROLES, expectedStatusCode: 200); if (!response.successful()) { return false; @@ -645,12 +698,17 @@ class InvenTreeAPI { return true; } else { + showServerError( + apiUrl, + L10().serverError, + L10().errorUserRoles, + ); return false; } } // Request plugin information from the server - Future getPluginInformation() async { + Future _fetchPlugins() async { _plugins.clear(); @@ -690,7 +748,7 @@ class InvenTreeAPI { if (roles[role] == null) { debug("checkPermission - role '$role' is null!"); - return true; + return false; } try { @@ -1045,7 +1103,14 @@ class InvenTreeAPI { * @param method is the HTTP method e.g. "POST" / "PATCH" / "GET" etc; * @param params is the request parameters */ - Future apiRequest(String url, String method, {Map urlParams = const {}}) async { + Future apiRequest( + String url, + String method, + { + Map urlParams = const {}, + Map headers = const {}, + } + ) async { var _url = makeApiUrl(url); @@ -1085,11 +1150,16 @@ class InvenTreeAPI { try { _request = await client.openUrl(method, _uri).timeout(Duration(seconds: 10)); - // Set headers + // Default headers defaultHeaders().forEach((key, value) { _request?.headers.set(key, value); }); + // Custom headers + headers.forEach((key, value) { + _request?.headers.set(key, value); + }); + return _request; } on SocketException catch (error) { debug("SocketException at ${url}: ${error.toString()}"); @@ -1262,12 +1332,13 @@ class InvenTreeAPI { * Perform a HTTP GET request * Returns a json object (or null if did not complete) */ - Future get(String url, {Map params = const {}, int? expectedStatusCode=200}) async { + Future get(String url, {Map params = const {}, Map headers = const {}, int? expectedStatusCode=200}) async { HttpClientRequest? request = await apiRequest( url, "GET", urlParams: params, + headers: headers, ); @@ -1334,7 +1405,10 @@ class InvenTreeAPI { Map defaultHeaders() { Map headers = {}; - headers[HttpHeaders.authorizationHeader] = _authorizationHeader(); + if (hasToken) { + headers[HttpHeaders.authorizationHeader] = _authorizationHeader(); + } + headers[HttpHeaders.acceptHeader] = "application/json"; headers[HttpHeaders.contentTypeHeader] = "application/json"; headers[HttpHeaders.acceptLanguageHeader] = currentLocale; @@ -1342,11 +1416,10 @@ class InvenTreeAPI { return headers; } + // Construct a token authorization header String _authorizationHeader() { - if (_token.isNotEmpty) { - return "Token $_token"; - } else if (profile != null) { - return "Basic " + base64Encode(utf8.encode("${profile?.username}:${profile?.password}")); + if (token.isNotEmpty) { + return "Token ${token}"; } else { return ""; } @@ -1579,3 +1652,5 @@ class InvenTreeAPI { }); } } + + diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 199bc15..defb9f8 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -131,7 +131,17 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } } - String get totalPriceCurrency => getString("total_price_currency"); + // Return the currency for this order + // Note that the nomenclature in the API changed at some point + String get totalPriceCurrency { + if (jsondata.containsKey("order_currency")) { + return getString("order_currency"); + } else if (jsondata.containsKey("total_price_currency")) { + return getString("total_price_currency"); + } else { + return ""; + } + } Future> getLineItems() async { diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 1d82ff0..4ca9cf4 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -44,7 +44,7 @@ Future> getDeviceInfo() async { "hardware": androidDeviceInfo.hardware, "manufacturer": androidDeviceInfo.manufacturer, "product": androidDeviceInfo.product, - "version": androidDeviceInfo.version.release, + "systemVersion": androidDeviceInfo.version.release, "supported32BitAbis": androidDeviceInfo.supported32BitAbis, "supported64BitAbis": androidDeviceInfo.supported64BitAbis, "supportedAbis": androidDeviceInfo.supportedAbis, @@ -57,7 +57,8 @@ Future> getDeviceInfo() async { Map getServerInfo() => { - "version": InvenTreeAPI().version, + "version": InvenTreeAPI().serverVersion, + "apiVersion": InvenTreeAPI().apiVersion, }; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 673d284..4d858d0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -591,6 +591,15 @@ "locationUpdated": "Stock location updated", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + + "loginEnter": "Enter login details", + "@loginEnter": {}, + + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", "@link": {}, @@ -795,6 +804,9 @@ "profileDelete": "Delete Server Profile", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", "@profileName": {}, diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 84578e0..3f02f6f 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -96,10 +96,18 @@ class InvenTreeAboutWidget extends StatelessWidget { ) ); + tiles.add( + ListTile( + title: Text(L10().username), + subtitle: Text(InvenTreeAPI().username), + leading: InvenTreeAPI().username.isNotEmpty ? FaIcon(FontAwesomeIcons.user) : FaIcon(FontAwesomeIcons.userSlash, color: COLOR_DANGER), + ) + ); + tiles.add( ListTile( title: Text(L10().version), - subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected), + subtitle: Text(InvenTreeAPI().serverVersion.isNotEmpty ? InvenTreeAPI().serverVersion : L10().notConnected), leading: FaIcon(FontAwesomeIcons.circleInfo), ) ); @@ -107,13 +115,13 @@ class InvenTreeAboutWidget extends StatelessWidget { tiles.add( ListTile( title: Text(L10().serverInstance), - subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : L10().notConnected), + subtitle: Text(InvenTreeAPI().serverInstance.isNotEmpty ? InvenTreeAPI().serverInstance : L10().notConnected), leading: FaIcon(FontAwesomeIcons.server), ) ); // Display extra tile if the server supports plugins - if (InvenTreeAPI().pluginsEnabled()) { + if (InvenTreeAPI().pluginsEnabled) { tiles.add( ListTile( title: Text(L10().pluginSupport), diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 185a779..57b1c16 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -1,295 +1,117 @@ + import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:one_context/one_context.dart"; - import "package:inventree/app_colors.dart"; -import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/spinner.dart"; +import "package:inventree/user_profile.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; -import "package:inventree/user_profile.dart"; +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/progress.dart"; -class InvenTreeLoginSettingsWidget extends StatefulWidget { + +class InvenTreeLoginWidget extends StatefulWidget { + + const InvenTreeLoginWidget(this.profile) : super(); + + final UserProfile profile; @override - _InvenTreeLoginSettingsState createState() => _InvenTreeLoginSettingsState(); + _InvenTreeLoginState createState() => _InvenTreeLoginState(); + } -class _InvenTreeLoginSettingsState extends State { - - _InvenTreeLoginSettingsState() { - _reload(); - } - - final GlobalKey<_InvenTreeLoginSettingsState> _loginKey = GlobalKey<_InvenTreeLoginSettingsState>(); - - List profiles = []; - - Future _reload() async { - - profiles = await UserProfileDBManager().getAllProfiles(); - - if (!mounted) { - return; - } - - setState(() { - }); - } - - void _editProfile(BuildContext context, {UserProfile? userProfile, bool createNew = false}) { - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ProfileEditWidget(userProfile) - ) - ).then((context) { - _reload(); - }); - } - - Future _selectProfile(BuildContext context, UserProfile profile) async { - - // Disconnect InvenTree - InvenTreeAPI().disconnectFromServer(); - - var key = profile.key; - - if (key == null) { - return; - } - - await UserProfileDBManager().selectProfile(key); - - if (!mounted) { - return; - } - - _reload(); - - // Attempt server login (this will load the newly selected profile - InvenTreeAPI().connectToServer().then((result) { - _reload(); - }); - - _reload(); - } - - Future _deleteProfile(UserProfile profile) async { - - await UserProfileDBManager().deleteProfile(profile); - - if (!mounted) { - return; - } - - _reload(); - - if (InvenTreeAPI().isConnected() && profile.key == (InvenTreeAPI().profile?.key ?? "")) { - InvenTreeAPI().disconnectFromServer(); - } - } - - Widget? _getProfileIcon(UserProfile profile) { - - // Not selected? No icon for you! - if (!profile.selected) return null; - - // Selected, but (for some reason) not the same as the API... - if ((InvenTreeAPI().profile?.key ?? "") != profile.key) { - return FaIcon( - FontAwesomeIcons.circleQuestion, - color: COLOR_WARNING - ); - } - - // Reflect the connection status of the server - if (InvenTreeAPI().isConnected()) { - return FaIcon( - FontAwesomeIcons.circleCheck, - color: COLOR_SUCCESS - ); - } else if (InvenTreeAPI().isConnecting()) { - return Spinner( - icon: FontAwesomeIcons.spinner, - color: COLOR_PROGRESS, - ); - } else { - return FaIcon( - FontAwesomeIcons.circleXmark, - color: COLOR_DANGER, - ); - } - } - - @override - Widget build(BuildContext context) { - - List children = []; - - if (profiles.isNotEmpty) { - for (int idx = 0; idx < profiles.length; idx++) { - UserProfile profile = profiles[idx]; - - children.add(ListTile( - title: Text( - profile.name, - ), - tileColor: profile.selected ? Theme.of(context).secondaryHeaderColor : null, - subtitle: Text("${profile.server}"), - trailing: _getProfileIcon(profile), - onTap: () { - _selectProfile(context, profile); - }, - onLongPress: () { - OneContext().showDialog( - builder: (BuildContext context) { - return SimpleDialog( - title: Text(profile.name), - children: [ - Divider(), - SimpleDialogOption( - onPressed: () { - Navigator.of(context).pop(); - _selectProfile(context, profile); - }, - child: ListTile( - title: Text(L10().profileConnect), - leading: FaIcon(FontAwesomeIcons.server), - ) - ), - SimpleDialogOption( - onPressed: () { - Navigator.of(context).pop(); - _editProfile(context, userProfile: profile); - }, - child: ListTile( - title: Text(L10().profileEdit), - leading: FaIcon(FontAwesomeIcons.penToSquare) - ) - ), - SimpleDialogOption( - onPressed: () { - Navigator.of(context).pop(); - // Navigator.of(context, rootNavigator: true).pop(); - confirmationDialog( - L10().delete, - L10().profileDelete + "?", - color: Colors.red, - icon: FontAwesomeIcons.trashCan, - onAccept: () { - _deleteProfile(profile); - } - ); - }, - child: ListTile( - title: Text(L10().profileDelete, style: TextStyle(color: Colors.red)), - leading: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), - ) - ) - ], - ); - } - ); - }, - )); - } - } else { - // No profile available! - children.add( - ListTile( - title: Text(L10().profileNone), - ) - ); - } - - return Scaffold( - key: _loginKey, - appBar: AppBar( - title: Text(L10().profileSelect), - actions: [ - IconButton( - icon: FaIcon(FontAwesomeIcons.circlePlus), - onPressed: () { - _editProfile(context, createNew: true); - }, - ) - ], - ), - body: Container( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: children - ).toList(), - ) - ), - ); - } -} - - -class ProfileEditWidget extends StatefulWidget { - - const ProfileEditWidget(this.profile) : super(); - - final UserProfile? profile; - - @override - _ProfileEditState createState() => _ProfileEditState(); -} - -class _ProfileEditState extends State { - - _ProfileEditState() : super(); +class _InvenTreeLoginState extends State { final formKey = GlobalKey(); - String name = ""; - String server = ""; String username = ""; String password = ""; bool _obscured = true; + String error = ""; + + // Attempt login + Future _doLogin(BuildContext context) async { + + // Save form + formKey.currentState?.save(); + + bool valid = formKey.currentState?.validate() ?? false; + + if (valid) { + + // Dismiss the keyboard + FocusScopeNode currentFocus = FocusScope.of(context); + + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + } + + showLoadingOverlay(context); + + // Attempt login + final response = await InvenTreeAPI().fetchToken(widget.profile, username, password); + + hideLoadingOverlay(); + + if (response.successful()) { + // Return to the server selector screen + Navigator.of(context).pop(); + } else { + var data = response.asMap(); + + String err; + + if (data.containsKey("detail")) { + err = (data["detail"] ?? "") as String; + } else { + err = statusCodeToString(response.statusCode); + } + setState(() { + error = err; + }); + } + } + + } + @override Widget build(BuildContext context) { + + List before = [ + ListTile( + title: Text(L10().loginEnter), + subtitle: Text(L10().loginEnterDetails), + leading: FaIcon(FontAwesomeIcons.userCheck), + ), + ListTile( + title: Text(L10().server), + subtitle: Text(widget.profile.server), + leading: FaIcon(FontAwesomeIcons.server), + ), + Divider(), + ]; + + List after = []; + + if (error.isNotEmpty) { + after.add(Divider()); + after.add(ListTile( + leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER), + title: Text(L10().error, style: TextStyle(color: COLOR_DANGER)), + subtitle: Text(error, style: TextStyle(color: COLOR_DANGER)), + )); + } return Scaffold( appBar: AppBar( - title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), + title: Text(L10().login), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.floppyDisk), + icon: FaIcon(FontAwesomeIcons.arrowRightToBracket, color: COLOR_SUCCESS), onPressed: () async { - if (formKey.currentState!.validate()) { - formKey.currentState!.save(); - - UserProfile? prf = widget.profile; - - if (prf == null) { - UserProfile profile = UserProfile( - name: name, - server: server, - username: username, - password: password, - ); - - await UserProfileDBManager().addProfile(profile); - } else { - - prf.name = name; - prf.server = server; - prf.username = username; - prf.password = password; - - await UserProfileDBManager().updateProfile(prf); - } - - // Close the window - Navigator.of(context).pop(); - } + _doLogin(context); }, ) ] @@ -302,79 +124,14 @@ class _ProfileEditState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + ...before, TextFormField( decoration: InputDecoration( - labelText: L10().profileName, - labelStyle: TextStyle(fontWeight: FontWeight.bold), + labelText: L10().username, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterUsername ), - initialValue: widget.profile?.name ?? "", - maxLines: 1, - keyboardType: TextInputType.text, - onSaved: (value) { - name = value?.trim() ?? ""; - }, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return L10().valueCannotBeEmpty; - } - - return null; - } - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().server, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: "http[s]://:", - ), - initialValue: widget.profile?.server ?? "", - keyboardType: TextInputType.url, - onSaved: (value) { - server = value?.trim() ?? ""; - }, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return L10().serverEmpty; - } - - value = value.trim(); - - // Spaces are bad - if (value.contains(" ")) { - return L10().invalidHost; - } - - if (!value.startsWith("http:") && !value.startsWith("https:")) { - // return L10().serverStart; - } - - Uri? _uri = Uri.tryParse(value); - - if (_uri == null || _uri.host.isEmpty) { - return L10().invalidHost; - } else { - Uri uri = Uri.parse(value); - - if (uri.hasScheme) { - if (!["http", "https"].contains(uri.scheme.toLowerCase())) { - return L10().serverStart; - } - } else { - return L10().invalidHost; - } - } - - // Everything is OK - return null; - }, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().username, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: L10().enterUsername - ), - initialValue: widget.profile?.username ?? "", + initialValue: "", keyboardType: TextInputType.text, onSaved: (value) { username = value?.trim() ?? ""; @@ -388,39 +145,41 @@ class _ProfileEditState extends State { }, ), TextFormField( - decoration: InputDecoration( - labelText: L10().password, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: L10().enterPassword, - suffixIcon: IconButton( - icon: _obscured ? FaIcon(FontAwesomeIcons.eye) : FaIcon(FontAwesomeIcons.solidEyeSlash), - onPressed: () { - setState(() { - _obscured = !_obscured; - }); - }, + decoration: InputDecoration( + labelText: L10().password, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterPassword, + suffixIcon: IconButton( + icon: _obscured ? FaIcon(FontAwesomeIcons.eye) : FaIcon(FontAwesomeIcons.solidEyeSlash), + onPressed: () { + setState(() { + _obscured = !_obscured; + }); + }, + ), ), - ), - initialValue: widget.profile?.password ?? "", - keyboardType: TextInputType.visiblePassword, - obscureText: _obscured, - onSaved: (value) { - password = value ?? ""; - }, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return L10().passwordEmpty; - } + initialValue: "", + keyboardType: TextInputType.visiblePassword, + obscureText: _obscured, + onSaved: (value) { + password = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().passwordEmpty; + } - return null; - } - ) - ] + return null; + } + ), + ...after, + ], ), padding: EdgeInsets.all(16), - ), + ) ) ); + } } \ No newline at end of file diff --git a/lib/settings/select_server.dart b/lib/settings/select_server.dart new file mode 100644 index 0000000..cd247b6 --- /dev/null +++ b/lib/settings/select_server.dart @@ -0,0 +1,430 @@ +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/settings/login.dart"; +import "package:one_context/one_context.dart"; + +import "package:inventree/app_colors.dart"; +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/spinner.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/api.dart"; +import "package:inventree/user_profile.dart"; + +class InvenTreeSelectServerWidget extends StatefulWidget { + + @override + _InvenTreeSelectServerState createState() => _InvenTreeSelectServerState(); +} + + +class _InvenTreeSelectServerState extends State { + + _InvenTreeSelectServerState() { + _reload(); + } + + final GlobalKey<_InvenTreeSelectServerState> _loginKey = GlobalKey<_InvenTreeSelectServerState>(); + + List profiles = []; + + Future _reload() async { + + profiles = await UserProfileDBManager().getAllProfiles(); + + if (!mounted) { + return; + } + + setState(() { + }); + } + + /* + * Logout the selected profile (delete the stored token) + */ + Future _logoutProfile(BuildContext context, {UserProfile? userProfile}) async { + + if (userProfile != null) { + userProfile.token = ""; + await UserProfileDBManager().updateProfile(userProfile); + + _reload(); + } + + InvenTreeAPI().disconnectFromServer(); + _reload(); + + } + + /* + * Edit the selected profile + */ + void _editProfile(BuildContext context, {UserProfile? userProfile, bool createNew = false}) { + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProfileEditWidget(userProfile) + ) + ).then((context) { + _reload(); + }); + } + + Future _selectProfile(BuildContext context, UserProfile profile) async { + + // Disconnect InvenTree + InvenTreeAPI().disconnectFromServer(); + + var key = profile.key; + + if (key == null) { + return; + } + + await UserProfileDBManager().selectProfile(key); + + UserProfile? prf = await UserProfileDBManager().getProfileByKey(key); + + if (prf == null) { + return; + } + + // First check if the profile has an associate token + if (!prf.hasToken) { + // Redirect user to login screen + Navigator.push(context, + MaterialPageRoute(builder: (context) => InvenTreeLoginWidget(profile)) + ).then((value) async { + _reload(); + // Reload profile + prf = await UserProfileDBManager().getProfileByKey(key); + if (prf?.hasToken ?? false) { + InvenTreeAPI().connectToServer(prf!).then((result) { + _reload(); + }); + } + }); + + // Exit now, login handled by next widget + return; + } + + if (!mounted) { + return; + } + + _reload(); + + // Attempt server login (this will load the newly selected profile + InvenTreeAPI().connectToServer(prf).then((result) { + _reload(); + }); + + _reload(); + } + + Future _deleteProfile(UserProfile profile) async { + + await UserProfileDBManager().deleteProfile(profile); + + if (!mounted) { + return; + } + + _reload(); + + if (InvenTreeAPI().isConnected() && profile.key == (InvenTreeAPI().profile?.key ?? "")) { + InvenTreeAPI().disconnectFromServer(); + } + } + + Widget? _getProfileIcon(UserProfile profile) { + + // Not selected? No icon for you! + if (!profile.selected) return null; + + // Selected, but (for some reason) not the same as the API... + if ((InvenTreeAPI().profile?.key ?? "") != profile.key) { + return null; + } + + // Reflect the connection status of the server + if (InvenTreeAPI().isConnected()) { + return FaIcon( + FontAwesomeIcons.circleCheck, + color: COLOR_SUCCESS + ); + } else if (InvenTreeAPI().isConnecting()) { + return Spinner( + icon: FontAwesomeIcons.spinner, + color: COLOR_PROGRESS, + ); + } else { + return FaIcon( + FontAwesomeIcons.circleXmark, + color: COLOR_DANGER, + ); + } + } + + @override + Widget build(BuildContext context) { + + List children = []; + + if (profiles.isNotEmpty) { + for (int idx = 0; idx < profiles.length; idx++) { + UserProfile profile = profiles[idx]; + + children.add(ListTile( + title: Text( + profile.name, + ), + tileColor: profile.selected ? Theme.of(context).secondaryHeaderColor : null, + subtitle: Text("${profile.server}"), + leading: profile.hasToken ? FaIcon(FontAwesomeIcons.userCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.userSlash, color: COLOR_WARNING), + trailing: _getProfileIcon(profile), + onTap: () { + _selectProfile(context, profile); + }, + onLongPress: () { + OneContext().showDialog( + builder: (BuildContext context) { + return SimpleDialog( + title: Text(profile.name), + children: [ + Divider(), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + _selectProfile(context, profile); + }, + child: ListTile( + title: Text(L10().profileConnect), + leading: FaIcon(FontAwesomeIcons.server), + ) + ), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + _editProfile(context, userProfile: profile); + }, + child: ListTile( + title: Text(L10().profileEdit), + leading: FaIcon(FontAwesomeIcons.penToSquare) + ) + ), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + _logoutProfile(context, userProfile: profile); + }, + child: ListTile( + title: Text(L10().profileLogout), + leading: FaIcon(FontAwesomeIcons.userSlash), + ) + ), + Divider(), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + // Navigator.of(context, rootNavigator: true).pop(); + confirmationDialog( + L10().delete, + L10().profileDelete + "?", + color: Colors.red, + icon: FontAwesomeIcons.trashCan, + onAccept: () { + _deleteProfile(profile); + } + ); + }, + child: ListTile( + title: Text(L10().profileDelete, style: TextStyle(color: Colors.red)), + leading: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), + ) + ) + ], + ); + } + ); + }, + )); + } + } else { + // No profile available! + children.add( + ListTile( + title: Text(L10().profileNone), + ) + ); + } + + return Scaffold( + key: _loginKey, + appBar: AppBar( + title: Text(L10().profileSelect), + actions: [ + IconButton( + icon: FaIcon(FontAwesomeIcons.circlePlus), + onPressed: () { + _editProfile(context, createNew: true); + }, + ) + ], + ), + body: Container( + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: children + ).toList(), + ) + ), + ); + } +} + + +/* + * Widget for editing server details + */ +class ProfileEditWidget extends StatefulWidget { + + const ProfileEditWidget(this.profile) : super(); + + final UserProfile? profile; + + @override + _ProfileEditState createState() => _ProfileEditState(); +} + +class _ProfileEditState extends State { + + _ProfileEditState() : super(); + + final formKey = GlobalKey(); + + String name = ""; + String server = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), + actions: [ + IconButton( + icon: FaIcon(FontAwesomeIcons.floppyDisk), + onPressed: () async { + if (formKey.currentState!.validate()) { + formKey.currentState!.save(); + + UserProfile? prf = widget.profile; + + if (prf == null) { + UserProfile profile = UserProfile( + name: name, + server: server, + ); + + await UserProfileDBManager().addProfile(profile); + } else { + + prf.name = name; + prf.server = server; + + await UserProfileDBManager().updateProfile(prf); + } + + // Close the window + Navigator.of(context).pop(); + } + }, + ) + ] + ), + body: Form( + key: formKey, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextFormField( + decoration: InputDecoration( + labelText: L10().profileName, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + ), + initialValue: widget.profile?.name ?? "", + maxLines: 1, + keyboardType: TextInputType.text, + onSaved: (value) { + name = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().valueCannotBeEmpty; + } + + return null; + } + ), + TextFormField( + decoration: InputDecoration( + labelText: L10().server, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: "http[s]://:", + ), + initialValue: widget.profile?.server ?? "", + keyboardType: TextInputType.url, + onSaved: (value) { + server = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().serverEmpty; + } + + value = value.trim(); + + // Spaces are bad + if (value.contains(" ")) { + return L10().invalidHost; + } + + if (!value.startsWith("http:") && !value.startsWith("https:")) { + // return L10().serverStart; + } + + Uri? _uri = Uri.tryParse(value); + + if (_uri == null || _uri.host.isEmpty) { + return L10().invalidHost; + } else { + Uri uri = Uri.parse(value); + + if (uri.hasScheme) { + if (!["http", "https"].contains(uri.scheme.toLowerCase())) { + return L10().serverStart; + } + } else { + return L10().invalidHost; + } + } + + // Everything is OK + return null; + }, + ), + ] + ), + padding: EdgeInsets.all(16), + ), + ) + ); + } + +} \ No newline at end of file diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 8c42071..dbf7e7e 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -9,7 +9,7 @@ import "package:inventree/settings/about.dart"; import "package:inventree/settings/app_settings.dart"; import "package:inventree/settings/barcode_settings.dart"; import "package:inventree/settings/home_settings.dart"; -import "package:inventree/settings/login.dart"; +import "package:inventree/settings/select_server.dart"; import "package:inventree/settings/part_settings.dart"; @@ -51,7 +51,7 @@ class _InvenTreeSettingsState extends State { subtitle: Text(L10().configureServer), leading: FaIcon(FontAwesomeIcons.server, color: COLOR_ACTION), onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget())); + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget())); }, ), ListTile( diff --git a/lib/user_profile.dart b/lib/user_profile.dart index e1b5446..9d17b06 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -10,20 +10,21 @@ class UserProfile { this.key, this.name = "", this.server = "", - this.username = "", - this.password = "", + this.token = "", this.selected = false, }); factory UserProfile.fromJson(int key, Map json, bool isSelected) => UserProfile( key: key, - name: json["name"] as String, - server: json["server"] as String, - username: json["username"] as String, - password: json["password"] as String, + name: (json["name"] ?? "") as String, + server: (json["server"] ?? "") as String, + token: (json["token"] ?? "") as String, selected: isSelected, ); + // Return true if this profile has a token + bool get hasToken => token.isNotEmpty; + // ID of the profile int? key; @@ -33,11 +34,8 @@ class UserProfile { // Base address of the InvenTree server String server = ""; - // Username - String username = ""; - - // Password - String password = ""; + // API token + String token = ""; bool selected = false; @@ -47,13 +45,12 @@ class UserProfile { Map toJson() => { "name": name, "server": server, - "username": username, - "password": password, + "token": token, }; @override String toString() { - return "<${key}> ${name} : ${server} - ${username}:${password}"; + return "<${key}> ${name} : ${server}"; } } @@ -88,7 +85,7 @@ class UserProfileDBManager { */ Future addProfile(UserProfile profile) async { - if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + if (profile.name.isEmpty) { debug("addProfile() : Profile missing required values - not adding to database"); return false; } @@ -118,7 +115,7 @@ class UserProfileDBManager { Future updateProfile(UserProfile profile) async { // Prevent invalid profile data from being updated - if (profile.name.isEmpty || profile.username.isEmpty || profile.password.isEmpty) { + if (profile.name.isEmpty) { debug("updateProfile() : Profile missing required values - not updating"); return false; } @@ -204,8 +201,6 @@ class UserProfileDBManager { UserProfile demoProfile = UserProfile( name: "InvenTree Demo", server: "https://demo.inventree.org", - username: "allaccess", - password: "nolimits", ); await addProfile(demoProfile); @@ -217,6 +212,26 @@ class UserProfileDBManager { return profileList; } + + /* + * Retrieve a profile by key (or null if no match exists) + */ + Future getProfileByKey(int key) async { + final profiles = await getAllProfiles(); + + UserProfile? prf; + + for (UserProfile profile in profiles) { + if (profile.key == key) { + prf = profile; + break; + } + } + + return prf; + } + + /* * Retrieve a profile by name (or null if no match exists) */ diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 1c86ef2..88229c1 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -235,50 +235,9 @@ Future showServerError(String url, String title, String description) async */ Future showStatusCodeError(String url, int status, {String details=""}) async { - String msg = L10().responseInvalid; + String msg = statusCodeToString(status); String extra = url + "\n" + "${L10().statusCode}: ${status}"; - switch (status) { - case 400: - msg = L10().response400; - break; - case 401: - msg = L10().response401; - break; - case 403: - msg = L10().response403; - break; - case 404: - msg = L10().response404; - break; - case 405: - msg = L10().response405; - break; - case 429: - msg = L10().response429; - break; - case 500: - msg = L10().response500; - break; - case 501: - msg = L10().response501; - break; - case 502: - msg = L10().response502; - break; - case 503: - msg = L10().response503; - break; - case 504: - msg = L10().response504; - break; - case 505: - msg = L10().response505; - break; - default: - break; - } - if (details.isNotEmpty) { extra += "\n"; extra += details; @@ -292,6 +251,41 @@ Future showStatusCodeError(String url, int status, {String details=""}) as } +/* + * Provide a human-readable descriptor for a particular error code + */ +String statusCodeToString(int status) { + switch (status) { + case 400: + return L10().response400; + case 401: + return L10().response401; + case 403: + return L10().response403; + case 404: + return L10().response404; + case 405: + return L10().response405; + case 429: + return L10().response429; + case 500: + return L10().response500; + case 501: + return L10().response501; + case 502: + return L10().response502; + case 503: + return L10().response503; + case 504: + return L10().response504; + case 505: + return L10().response505; + default: + return L10().responseInvalid + " : ${status}"; + } +} + + /* * Displays a message indicating that the server timed out on a certain request */ diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 5fa8a2e..b62daf7 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -8,7 +8,7 @@ import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; import "package:inventree/l10.dart"; -import "package:inventree/settings/login.dart"; +import "package:inventree/settings/select_server.dart"; import "package:inventree/user_profile.dart"; import "package:inventree/widget/category_display.dart"; @@ -119,7 +119,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr void _selectProfile() { Navigator.push( - context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget()) + context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget()) ).then((context) { // Once we return _loadProfile(); @@ -147,7 +147,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr if (!InvenTreeAPI().isConnected() && !InvenTreeAPI().isConnecting()) { // Attempt server connection - InvenTreeAPI().connectToServer().then((result) { + InvenTreeAPI().connectToServer(_profile!).then((result) { if (mounted) { setState(() {}); } diff --git a/test/api_test.dart b/test/api_test.dart index 5990d16..a9c7291 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -17,37 +17,11 @@ void main() { setUp(() async { - if (! await UserProfileDBManager().profileNameExists("Test Profile")) { - // Create and select a profile to user - - print("TEST: Creating profile for user 'testuser'"); - - await UserProfileDBManager().addProfile(UserProfile( - name: "Test Profile", - server: "http://localhost:12345", - username: "testuser", - password: "testpassword", - selected: true, - )); - } - - var prf = await UserProfileDBManager().getSelectedProfile(); - - // Ensure that the server settings are correct by default, - // as they can get overwritten by subsequent tests - - if (prf != null) { - prf.name = "Test Profile"; - prf.server = "http://localhost:12345"; - prf.username = "testuser"; - prf.password = "testpassword"; - - await UserProfileDBManager().updateProfile(prf); - } + await setupServerProfile(select: true); // Ensure the profile is selected assert(! await UserProfileDBManager().selectProfileByName("Missing Profile")); - assert(await UserProfileDBManager().selectProfileByName("Test Profile")); + assert(await UserProfileDBManager().selectProfileByName(testServerName)); }); @@ -71,53 +45,57 @@ void main() { var api = InvenTreeAPI(); // Incorrect server address - var profile = await UserProfileDBManager().getSelectedProfile(); + var profile = await setupServerProfile(); - assert(profile != null); + profile.server = "http://localhost:5555"; - if (profile != null) { - profile.server = "http://localhost:5555"; - await UserProfileDBManager().updateProfile(profile); + bool result = await api.connectToServer(profile); + assert(!result); - bool result = await api.connectToServer(); - assert(!result); + debugContains("SocketException at"); - debugContains("SocketException at"); + // Test incorrect login details + profile.server = testServerAddress; - // Test incorrect login details - profile.server = "http://localhost:12345"; - profile.username = "invalidusername"; + final response = await api.fetchToken(profile, "baduser", "badpassword"); + assert(!response.successful()); - await UserProfileDBManager().updateProfile(profile); + debugContains("Token request failed"); - await api.connectToServer(); - assert(!result); + assert(!api.checkConnection()); - debugContains("Token request failed"); + debugContains("Token request failed: STATUS 401"); + debugContains("showSnackIcon: 'Not Connected'"); - assert(!api.checkConnection()); + }); - debugContains("Token request failed: STATUS 401"); - debugContains("showSnackIcon: 'Not Connected'"); + test("Bad Token", () async { + // Test that login fails with a bad token + var profile = await setupServerProfile(); - } else { - assert(false); - } + profile.token = "bad-token"; + bool result = await InvenTreeAPI().connectToServer(profile); + assert(!result); }); test("Login Success", () async { // Test that we can login to the server successfully var api = InvenTreeAPI(); - // Attempt to connect - final bool result = await api.connectToServer(); + final profile = await setupServerProfile(select: true, fetchToken: true); + assert(profile.hasToken); + + // Now, connect to the server + bool result = await api.connectToServer(profile); // Check expected values assert(result); assert(api.hasToken); - expect(api.baseUrl, equals("http://localhost:12345/")); + expect(api.baseUrl, equals(testServerAddress)); + + assert(api.hasToken); assert(api.isConnected()); assert(!api.isConnecting()); assert(api.checkConnection()); @@ -127,7 +105,8 @@ void main() { // Test server version information var api = InvenTreeAPI(); - assert(await api.connectToServer()); + final profile = await setupServerProfile(fetchToken: true); + assert(await api.connectToServer(profile)); // Check supported functions assert(api.apiVersion >= 50); @@ -135,12 +114,15 @@ void main() { assert(api.supportsNotifications); assert(api.supportsPoReceive); - // Ensure we can request (and receive) user roles - assert(await api.getUserRoles()); + assert(api.serverInstance.isNotEmpty); + assert(api.serverVersion.isNotEmpty); + + // Ensure we can have user role data + assert(api.roles.isNotEmpty); // Check available permissions assert(api.checkPermission("part", "change")); - assert(api.checkPermission("stocklocation", "delete")); + assert(api.checkPermission("stock_location", "delete")); assert(!api.checkPermission("part", "weirdpermission")); assert(api.checkPermission("blah", "bloo")); diff --git a/test/barcode_test.dart b/test/barcode_test.dart index e28715b..181e74d 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -10,7 +10,6 @@ import "package:flutter_test/flutter_test.dart"; import "package:inventree/api.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; -import "package:inventree/user_profile.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; @@ -23,26 +22,7 @@ void main() { // Connect to the server setUpAll(() async { - final prf = await UserProfileDBManager().getProfileByName("Test Profile"); - - if (prf != null) { - await UserProfileDBManager().deleteProfile(prf); - } - - bool result = await UserProfileDBManager().addProfile( - UserProfile( - name: "Test Profile", - server: "http://localhost:12345", - username: "testuser", - password: "testpassword", - selected: true, - ), - ); - - assert(result); - - assert(await UserProfileDBManager().selectProfileByName("Test Profile")); - assert(await InvenTreeAPI().connectToServer()); + await connectToTestServer(); }); setUp(() async { @@ -91,8 +71,8 @@ void main() { test("Scan Into Location", () async { final item = await InvenTreeStockItem().get(1) as InvenTreeStockItem?; - assert(item != null); + assert(item!.pk == 1); var handler = StockItemScanIntoLocationHandler(item!); diff --git a/test/models_test.dart b/test/models_test.dart index c44ad5c..5a82d47 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -5,7 +5,6 @@ import "package:test/test.dart"; import "package:inventree/api.dart"; -import "package:inventree/user_profile.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; @@ -16,16 +15,7 @@ void main() { setupTestEnv(); setUp(() async { - await UserProfileDBManager().addProfile(UserProfile( - name: "Test Profile", - server: "http://localhost:12345", - username: "testuser", - password: "testpassword", - selected: true, - )); - - assert(await UserProfileDBManager().selectProfileByName("Test Profile")); - assert(await InvenTreeAPI().connectToServer()); + await connectToTestServer(); }); group("Category Tests:", () { diff --git a/test/setup.dart b/test/setup.dart index 1338f13..b9785b7 100644 --- a/test/setup.dart +++ b/test/setup.dart @@ -1,6 +1,8 @@ import "package:flutter/services.dart"; import "package:flutter_test/flutter_test.dart"; +import "package:inventree/api.dart"; +import "package:inventree/user_profile.dart"; // This is the same as the following issue except it keeps the http client // TestWidgetsFlutterBinding.ensureInitialized(); @@ -19,4 +21,78 @@ void setupTestEnv() { .setMockMethodCallHandler(channel, (MethodCall methodCall) async { return "."; }); +} + +// Accessors for default testing values +const String testServerAddress = "http://localhost:8000/"; +const String testServerName = "Test Server"; +const String testUsername = "testuser"; +const String testPassword = "testpassword"; + + +/* + * Request an API token for the given profile + */ +Future fetchProfileToken({ + UserProfile? profile, + String username = testUsername, + String password = testPassword +}) async { + + profile ??= await UserProfileDBManager().getProfileByName(testServerName); + + assert(profile != null); + + final response = await InvenTreeAPI().fetchToken(profile!, username, password); + return response.successful(); +} + + +/* + * Setup a valid profile, and return it + */ +Future setupServerProfile({bool select = true, bool fetchToken = false}) async { + // Setup a valid server profile + + UserProfile? profile = await UserProfileDBManager().getProfileByName(testServerName); + + if (profile == null) { + // Profile does not already exist - create it! + bool result = await UserProfileDBManager().addProfile( + UserProfile( + server: testServerAddress, + name: testServerName + ) + ); + + assert(result); + } + + profile = await UserProfileDBManager().getProfileByName(testServerName); + assert(profile != null); + + if (select) { + assert(await UserProfileDBManager().selectProfileByName(testServerName)); + } + + if (fetchToken && !profile!.hasToken) { + final bool result = await fetchProfileToken(profile: profile); + assert(result); + assert(profile.hasToken); + } + + return profile!; +} + + +/* + * Complete all steps necessary to login to the server + */ +Future connectToTestServer() async { + + // Setup profile, and fetch user token as necessary + final profile = await setupServerProfile(fetchToken: true); + + // Connect to the server + assert(await InvenTreeAPI().connectToServer(profile)); } \ No newline at end of file diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 1da201f..0921d76 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -27,10 +27,8 @@ void main() { // Now, create one! bool result = await UserProfileDBManager().addProfile(UserProfile( - name: "Test Profile", - username: "testuser", - password: "testpassword""", - server: "http://localhost:12345", + name: testServerName, + server: testServerAddress, selected: true, )); @@ -62,20 +60,15 @@ void main() { test("Add Invalid Profiles", () async { // Add a profile with missing data bool result = await UserProfileDBManager().addProfile( - UserProfile( - username: "what", - password: "why", - ) + UserProfile() ); expect(result, equals(false)); - // Add a profile with a name that already exists + // Add a profile with a new name result = await UserProfileDBManager().addProfile( UserProfile( - name: "Test Profile", - username: "xyz", - password: "hunter42", + name: "Another Test Profile", ) ); @@ -84,14 +77,14 @@ void main() { // Check that the number of protocols available is still the same var profiles = await UserProfileDBManager().getAllProfiles(); - expect(profiles.length, equals(1)); + expect(profiles.length, equals(2)); }); test("Profile Name Check", () async { bool result = await UserProfileDBManager().profileNameExists("doesnotexist"); expect(result, equals(false)); - result = await UserProfileDBManager().profileNameExists("Test Profile"); + result = await UserProfileDBManager().profileNameExists("Test Server"); expect(result, equals(true)); }); @@ -104,23 +97,16 @@ void main() { if (prf != null) { UserProfile p = prf; - expect(p.name, equals("Test Profile")); - expect(p.username, equals("testuser")); - expect(p.password, equals("testpassword")); - expect(p.server, equals("http://localhost:12345")); + expect(p.name, equals(testServerName)); + expect(p.server, equals(testServerAddress)); - expect(p.toString(), equals("<${p.key}> Test Profile : http://localhost:12345 - testuser:testpassword")); + expect(p.toString(), equals("<${p.key}> Test Server : http://localhost:8000/")); // Test that we can update the profile p.name = "different name"; bool result = await UserProfileDBManager().updateProfile(p); expect(result, equals(true)); - - // Trying to update with an invalid value will fail! - p.password = ""; - result = await UserProfileDBManager().updateProfile(p); - expect(result, equals(false)); } }); }); From 8f1cd1cae1b479ac813c6fd749d8dcee8019f1dc Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Oct 2023 21:37:33 +1100 Subject: [PATCH 431/746] Prevent notification dismissal from ocurring multiple times (#435) --- lib/widget/notifications.dart | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 966890c..4c34203 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -23,6 +23,8 @@ class _NotificationState extends RefreshableState { List notifications = []; + bool isDismissing = false; + @override String getAppBarTitle() => L10().notifications; @@ -45,10 +47,23 @@ class _NotificationState extends RefreshableState { */ Future dismissNotification(BuildContext context, InvenTreeNotification notification) async { + if (mounted) { + setState(() { + isDismissing = true; + }); + } else { + return; + } + await notification.dismiss(); - refresh(context); + if (mounted) { + refresh(context); + setState(() { + isDismissing = false; + }); + } } /* @@ -77,7 +92,7 @@ class _NotificationState extends RefreshableState { subtitle: Text(notification.message), trailing: IconButton( icon: FaIcon(FontAwesomeIcons.bookmark), - onPressed: () async { + onPressed: isDismissing ? null : () async { dismissNotification(context, notification); }, ), From b6ab9d5da5eb8455580d4b3a5b0196f22098df07 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Oct 2023 21:59:05 +1100 Subject: [PATCH 432/746] Refresh fix (#436) * Add notificationPredicate to improve scroll-to-reload Ref: https://api.flutter.dev/flutter/material/RefreshIndicator-class.html * Add scroll-to-refresh for paginated list --- assets/release_notes.md | 1 + lib/widget/paginator.dart | 45 +++++++++++++++++-------------- lib/widget/refreshable_state.dart | 24 +++++++++++++---- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 1bdcb63..7604eec 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ - Add ability to scan in received items using supplier barcodes - Store API token, rather than username:password - Ensure that user will lose access if token is revoked by server +- Improve scroll-to-refresh behaviour across multiple widgets ### 0.12.8 - September 2023 diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index a08b749..d3a69c6 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -394,31 +394,36 @@ abstract class PaginatedSearchState extends Sta children.add( Expanded( - child: CustomScrollView( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - scrollDirection: Axis.vertical, - slivers: [ - PagedSliverList.separated( - pagingController: _pagingController, - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (ctx, item, index) { - return buildItem(ctx, item); - }, - noItemsFoundIndicatorBuilder: (context) { - return NoResultsWidget(noResultsText); - } - ), - separatorBuilder: (context, item) => const Divider(height: .1), - ) - ] + child: CustomScrollView( + shrinkWrap: true, + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + slivers: [ + PagedSliverList.separated( + pagingController: _pagingController, + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (ctx, item, index) { + return buildItem(ctx, item); + }, + noItemsFoundIndicatorBuilder: (context) { + return NoResultsWidget(noResultsText); + } + ), + separatorBuilder: (context, item) => const Divider(height: 1), + ) + ] + ) ) - ) ); - return Column( + return RefreshIndicator( + child: Column( mainAxisAlignment: MainAxisAlignment.start, children: children, + ), + onRefresh: () async { + _pagingController.refresh(); + }, ); } diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 2bfc573..c2ce12b 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -21,7 +21,7 @@ mixin BaseWidgetProperties { */ List appBarActions(BuildContext context) => []; - // Return a title for the appBar + // Return a title for the appBar (placeholder) String getAppBarTitle() { return "--- app bar ---"; } // Function to construct a drawer (override if needed) @@ -40,6 +40,7 @@ mixin BaseWidgetProperties { // Default body calls getTiles() return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), child: Column( children: getTiles(context) ) @@ -202,7 +203,8 @@ mixin BaseWidgetProperties { */ abstract class RefreshableState extends State with BaseWidgetProperties { - final refreshableKey = GlobalKey(); + final scaffoldKey = GlobalKey(); + final refreshKey = GlobalKey(); // Storage for context once "Build" is called late BuildContext? _context; @@ -265,19 +267,31 @@ abstract class RefreshableState extends State with Widget body = tabs.isEmpty ? getBody(context) : TabBarView(children: getTabs(context)); + // predicateDepth needs to be different based on the child type + // hack, determined experimentally + int predicateDepth = 0; + + if (tabs.isNotEmpty) { + predicateDepth = 1; + } + Scaffold view = Scaffold( - key: refreshableKey, - appBar: buildAppBar(context, refreshableKey), + key: scaffoldKey, + appBar: buildAppBar(context, scaffoldKey), drawer: getDrawer(context), floatingActionButton: buildSpeedDial(context), floatingActionButtonLocation: FloatingActionButtonLocation.miniEndDocked, body: RefreshIndicator( + key: refreshKey, + notificationPredicate: (ScrollNotification notification) { + return notification.depth == predicateDepth; + }, onRefresh: () async { refresh(context); }, child: body ), - bottomNavigationBar: buildBottomAppBar(context, refreshableKey), + bottomNavigationBar: buildBottomAppBar(context, scaffoldKey), ); // Default implementation is *not* tabbed From c641cea3693023e2d3a5d96ee202afaea331fdcd Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 25 Oct 2023 22:40:49 +1100 Subject: [PATCH 433/746] Scanner wedge mode (#437) * Add code_scan_listener package * Implement wedge controller widget * Update barcode settings widget - Allow user to choose which barcode scanner to use * Fix typo * Select barcode scanner widget based on user preference * Fix rendering issues for wedge controller * Update release notes * Add unit test for wedge scanner widget - Required some tweaks to other code * Use better library - https://github.com/fuadreza/flutter_barcode_listener - Fork of https://github.com/shaxxx/flutter_barcode_listener - Properly handles key "case" issues (shift, essentially) - Verified that it works correctly for multiple character types * Local copy of code, rather than relying on package which is not available on pub.dev * Fix unit test --- analysis_options.yaml | 1 + assets/release_notes.md | 1 + lib/app_colors.dart | 5 + lib/barcode/barcode.dart | 15 ++ lib/barcode/controller.dart | 4 +- lib/barcode/flutter_barcode_listener.dart | 175 ++++++++++++++++++++++ lib/barcode/wedge_controller.dart | 102 +++++++++++++ lib/l10n/app_en.arb | 18 +++ lib/preferences.dart | 5 + lib/settings/barcode_settings.dart | 50 ++++++- lib/widget/progress.dart | 7 +- test/wedge_scanner_test.dart | 32 ++++ 12 files changed, 411 insertions(+), 4 deletions(-) create mode 100644 lib/barcode/flutter_barcode_listener.dart create mode 100644 lib/barcode/wedge_controller.dart create mode 100644 test/wedge_scanner_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 217d3d2..c470bae 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -79,3 +79,4 @@ linter: no_leading_underscores_for_local_identifiers: false use_super_parameters: false + diff --git a/assets/release_notes.md b/assets/release_notes.md index 7604eec..0a25673 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.13.0 - October 2023 --- +- Adds "wedge scanner" mode, allowing use with external barcode readers - Add ability to scan in received items using supplier barcodes - Store API token, rather than username:password - Ensure that user will lose access if token is revoked by server diff --git a/lib/app_colors.dart b/lib/app_colors.dart index feba6c0..5fb4bb1 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -6,6 +6,11 @@ const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 1); // Return an "action" color based on the current theme Color get COLOR_ACTION { + // OneContext might not have context, e.g. in testing + if (!OneContext.hasContext) { + return Colors.lightBlue; + } + BuildContext? context = OneContext().context; if (context != null) { diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 6a2a069..df110e6 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/preferences.dart"; import "package:one_context/one_context.dart"; @@ -11,6 +12,7 @@ import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/barcode/camera_controller.dart"; +import "package:inventree/barcode/wedge_controller.dart"; import "package:inventree/barcode/controller.dart"; import "package:inventree/barcode/handler.dart"; import "package:inventree/barcode/tones.dart"; @@ -44,6 +46,19 @@ Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) asy InvenTreeBarcodeController controller = CameraBarcodeController(handler); + // Select barcode controller based on user preference + final int barcodeControllerType = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_TYPE, BARCODE_CONTROLLER_CAMERA) as int; + + switch (barcodeControllerType) { + case BARCODE_CONTROLLER_WEDGE: + controller = WedgeBarcodeController(handler); + break; + case BARCODE_CONTROLLER_CAMERA: + default: + // Already set as default option + break; + } + return Navigator.of(context).push( PageRouteBuilder( pageBuilder: (context, _, __) => controller, diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index ca8e396..ad17aa6 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -58,9 +58,9 @@ class InvenTreeBarcodeControllerState extends State processingBarcode = true; }); - BuildContext? context = OneContext().context; + BuildContext? context = OneContext.hasContext ? OneContext().context : null; - showLoadingOverlay(context!); + showLoadingOverlay(context); await pauseScan(); await widget.handler.processBarcode(data); diff --git a/lib/barcode/flutter_barcode_listener.dart b/lib/barcode/flutter_barcode_listener.dart new file mode 100644 index 0000000..c2b2845 --- /dev/null +++ b/lib/barcode/flutter_barcode_listener.dart @@ -0,0 +1,175 @@ + +/* + * Custom keyboard listener which allows the app to act as a keyboard "wedge", + * and intercept barcodes from any compatible scanner. + * + * Note: This code was copied from https://github.com/fuadreza/flutter_barcode_listener/blob/master/lib/flutter_barcode_listener.dart + * + * If that code becomes available on pub.dev, we can remove this file and reference that library + */ + +import "dart:async"; + +import "package:flutter/material.dart"; +import "package:flutter/services.dart"; + +typedef BarcodeScannedCallback = void Function(String barcode); + +/// This widget will listen for raw PHYSICAL keyboard events +/// even when other controls have primary focus. +/// It will buffer all characters coming in specifed `bufferDuration` time frame +/// that end with line feed character and call callback function with result. +/// Keep in mind this widget will listen for events even when not visible. +/// Windows seems to be using the [RawKeyDownEvent] instead of the +/// [RawKeyUpEvent], this behaviour can be managed by setting [useKeyDownEvent]. +class BarcodeKeyboardListener extends StatefulWidget { + + /// This widget will listen for raw PHYSICAL keyboard events + /// even when other controls have primary focus. + /// It will buffer all characters coming in specifed `bufferDuration` time frame + /// that end with line feed character and call callback function with result. + /// Keep in mind this widget will listen for events even when not visible. + const BarcodeKeyboardListener( + {Key? key, + + /// Child widget to be displayed. + required this.child, + + /// Callback to be called when barcode is scanned. + required Function(String) onBarcodeScanned, + + /// When experiencing issueswith empty barcodes on Windows, + /// set this value to true. Default value is `false`. + this.useKeyDownEvent = false, + + /// Maximum time between two key events. + /// If time between two key events is longer than this value + /// previous keys will be ignored. + Duration bufferDuration = hundredMs}) + : _onBarcodeScanned = onBarcodeScanned, + _bufferDuration = bufferDuration, + super(key: key); + + final Widget child; + final BarcodeScannedCallback _onBarcodeScanned; + final Duration _bufferDuration; + final bool useKeyDownEvent; + + @override + _BarcodeKeyboardListenerState createState() => _BarcodeKeyboardListenerState( + _onBarcodeScanned, _bufferDuration, useKeyDownEvent); +} + +const Duration aSecond = Duration(seconds: 1); +const Duration hundredMs = Duration(milliseconds: 100); +const String lineFeed = "\n"; + +class _BarcodeKeyboardListenerState extends State { + + _BarcodeKeyboardListenerState(this._onBarcodeScannedCallback, + this._bufferDuration, this._useKeyDownEvent) { + RawKeyboard.instance.addListener(_keyBoardCallback); + _keyboardSubscription = + _controller.stream.where((char) => char != null).listen(onKeyEvent); + } + + List _scannedChars = []; + DateTime? _lastScannedCharCodeTime; + late StreamSubscription _keyboardSubscription; + + final BarcodeScannedCallback _onBarcodeScannedCallback; + final Duration _bufferDuration; + + final _controller = StreamController(); + + final bool _useKeyDownEvent; + + bool _isShiftPressed = false; + void onKeyEvent(String? char) { + //remove any pending characters older than bufferDuration value + checkPendingCharCodesToClear(); + _lastScannedCharCodeTime = DateTime.now(); + if (char == lineFeed) { + _onBarcodeScannedCallback.call(_scannedChars.join()); + resetScannedCharCodes(); + } else { + //add character to list of scanned characters; + _scannedChars.add(char!); + } + } + + void checkPendingCharCodesToClear() { + if (_lastScannedCharCodeTime != null) { + if (_lastScannedCharCodeTime! + .isBefore(DateTime.now().subtract(_bufferDuration))) { + resetScannedCharCodes(); + } + } + } + + void resetScannedCharCodes() { + _lastScannedCharCodeTime = null; + _scannedChars = []; + } + + void addScannedCharCode(String charCode) { + _scannedChars.add(charCode); + } + + void _keyBoardCallback(RawKeyEvent keyEvent) { + if (keyEvent.logicalKey.keyId > 255 && + keyEvent.data.logicalKey != LogicalKeyboardKey.enter && + keyEvent.data.logicalKey != LogicalKeyboardKey.shiftLeft) return; + if ((!_useKeyDownEvent && keyEvent is RawKeyUpEvent) || + (_useKeyDownEvent && keyEvent is RawKeyDownEvent)) { + if (keyEvent.data is RawKeyEventDataAndroid) { + if (keyEvent.data.logicalKey == LogicalKeyboardKey.shiftLeft) { + _isShiftPressed = true; + } else { + if (_isShiftPressed) { + _isShiftPressed = false; + _controller.sink.add(String.fromCharCode( + ((keyEvent.data) as RawKeyEventDataAndroid).codePoint).toUpperCase()); + } else { + _controller.sink.add(String.fromCharCode( + ((keyEvent.data) as RawKeyEventDataAndroid).codePoint)); + } + } + } else if (keyEvent.data is RawKeyEventDataFuchsia) { + _controller.sink.add(String.fromCharCode( + ((keyEvent.data) as RawKeyEventDataFuchsia).codePoint)); + } else if (keyEvent.data.logicalKey == LogicalKeyboardKey.enter) { + _controller.sink.add(lineFeed); + } else if (keyEvent.data is RawKeyEventDataWeb) { + _controller.sink.add(((keyEvent.data) as RawKeyEventDataWeb).keyLabel); + } else if (keyEvent.data is RawKeyEventDataLinux) { + _controller.sink + .add(((keyEvent.data) as RawKeyEventDataLinux).keyLabel); + } else if (keyEvent.data is RawKeyEventDataWindows) { + _controller.sink.add(String.fromCharCode( + ((keyEvent.data) as RawKeyEventDataWindows).keyCode)); + } else if (keyEvent.data is RawKeyEventDataMacOs) { + _controller.sink + .add(((keyEvent.data) as RawKeyEventDataMacOs).characters); + } else if (keyEvent.data is RawKeyEventDataIos) { + _controller.sink + .add(((keyEvent.data) as RawKeyEventDataIos).characters); + } else { + _controller.sink.add(keyEvent.character); + } + } + } + + @override + Widget build(BuildContext context) { + return widget.child; + } + + @override + void dispose() { + _keyboardSubscription.cancel(); + _controller.close(); + RawKeyboard.instance.removeListener(_keyBoardCallback); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart new file mode 100644 index 0000000..98b9f0c --- /dev/null +++ b/lib/barcode/wedge_controller.dart @@ -0,0 +1,102 @@ + +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +import "package:inventree/app_colors.dart"; +import "package:inventree/barcode/controller.dart"; +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/flutter_barcode_listener.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; + +/* + * Barcode controller which acts as a keyboard wedge, + * intercepting barcode data which is entered as rapid keyboard presses + */ +class WedgeBarcodeController extends InvenTreeBarcodeController { + + const WedgeBarcodeController(BarcodeHandler handler, {Key? key}) : super(handler, key: key); + + @override + State createState() => _WedgeBarcodeControllerState(); + +} + + +class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { + + _WedgeBarcodeControllerState() : super(); + + bool canScan = true; + + bool get scanning => mounted && canScan; + + @override + Future pauseScan() async { + + if (mounted) { + setState(() { + canScan = false; + }); + } + } + + @override + Future resumeScan() async { + + if (mounted) { + setState(() { + canScan = true; + }); + } + } + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: AppBar( + title: Text(L10().scanBarcode), + ), + backgroundColor: Colors.black.withOpacity(0.9), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(flex: 5), + FaIcon(FontAwesomeIcons.barcode, size: 64), + Spacer(flex: 5), + BarcodeKeyboardListener( + useKeyDownEvent: true, + child: SizedBox( + child: CircularProgressIndicator( + color: scanning ? COLOR_ACTION : COLOR_PROGRESS + ), + width: 64, + height: 64, + ), + onBarcodeScanned: (String barcode) { + debug("scanned: ${barcode}"); + if (scanning) { + // Process the barcode data + handleBarcodeData(barcode); + } + }, + ), + Spacer(flex: 5), + Padding( + child: Text( + widget.handler.getOverlayText(context), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.white) + ), + padding: EdgeInsets.all(20), + ) + ], + ) + ) + ); + } + +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 4d858d0..e1c1f2e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -118,6 +118,12 @@ "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", "@barcodeScanDelay": {}, @@ -169,6 +175,12 @@ "building": "Building", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", "@cancel": { "description": "Cancel" @@ -1003,6 +1015,12 @@ "scanIntoLocationDetail": "Scan this item into location", "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 5180152..3010597 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -40,6 +40,11 @@ const String INV_STRICT_HTTPS = "strictHttps"; // Barcode settings const String INV_BARCODE_SCAN_DELAY = "barcodeScanDelay"; +const String INV_BARCODE_SCAN_TYPE = "barcodeScanType"; + +// Barcode scanner types +const int BARCODE_CONTROLLER_CAMERA = 0; +const int BARCODE_CONTROLLER_WEDGE = 1; /* * Class for storing InvenTree preferences in a NoSql DB diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index 1624a10..44dfb7f 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -1,7 +1,9 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; + import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/dialogs.dart"; class InvenTreeBarcodeSettingsWidget extends StatefulWidget { @@ -15,6 +17,7 @@ class _InvenTreeBarcodeSettingsState extends State loadSettings() async { barcodeScanDelay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + barcodeScanType = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_TYPE, BARCODE_CONTROLLER_CAMERA) as int; if (mounted) { setState(() { @@ -89,11 +93,55 @@ class _InvenTreeBarcodeSettingsState extends State Date: Wed, 25 Oct 2023 22:50:01 +1100 Subject: [PATCH 434/746] Bump version number - 0.13.0 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d4d197a..3f5d633 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.12.8+75 +version: 0.13.0+76 environment: sdk: ">=2.19.5 <3.13.0" From cf83ae86b9bda613aa2ad6f695c6bcb22daa9105 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 9 Nov 2023 20:49:01 +1100 Subject: [PATCH 435/746] New Crowdin updates (#443) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Bulgarian) --- lib/l10n/bg_BG/app_bg_BG.arb | 5 ++ lib/l10n/zh_CN/app_zh_CN.arb | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 lib/l10n/bg_BG/app_bg_BG.arb diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb new file mode 100644 index 0000000..55f9683 --- /dev/null +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -0,0 +1,5 @@ +{ + "@@locale": "bg", + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {} +} \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index d07878e..c4ed4e3 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -78,8 +78,14 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "未分配条码", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "扫描条形码以接收部件", + "@barcodeReceivePart": {}, "barcodeScanAssign": "扫描以分配条码", "@barcodeScanAssign": {}, + "barcodeScanController": "扫描仪输入", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "选择条码扫描输入源", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "条形码扫描延迟", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "条形码扫描之间的延迟", @@ -114,6 +120,10 @@ "@build": {}, "building": "正在生成", "@building": {}, + "cameraInternal": "内置相机", + "@cameraInternal": {}, + "cameraInternalDetail": "使用内部摄像头读取条形码", + "@cameraInternalDetail": {}, "cancel": "取消", "@cancel": { "description": "Cancel" @@ -389,10 +399,22 @@ "@lineItemUpdated": {}, "locateItem": "定位库存项", "@locateItem": {}, + "locateLocation": "定位存货位置", + "@locateLocation": {}, "locationCreate": "新建仓储位置", "@locationCreate": {}, + "locationCreateDetail": "创建新库存位置", + "@locationCreateDetail": {}, "locationNotSet": "没有指定仓储位置", "@locationNotSet": {}, + "locationUpdated": "库存位置已更新", + "@locationUpdated": {}, + "login": "登入", + "@login": {}, + "loginEnter": "输入登录详情", + "@loginEnter": {}, + "loginEnterDetails": "用户名和密码未存储在本地", + "@loginEnterDetails": {}, "link": "链接", "@link": {}, "lost": "丢失", @@ -505,18 +527,86 @@ "@passwordEmpty": {}, "permissionAccountDenied": "您的帐户没有执行此操作所需的权限", "@permissionAccountDenied": {}, + "permissionRequired": "需要授权:", + "@permissionRequired": {}, + "printLabel": "打印标签", + "@printLabel": {}, + "plugin": "插件", + "@plugin": {}, + "pluginPrinter": "打印机", + "@pluginPrinter": {}, + "pluginSupport": "已启用插件支持", + "@pluginSupport": {}, + "pluginSupportDetail": "服务器支持自定义插件", + "@pluginSupportDetail": {}, + "printLabelFailure": "标签打印失败", + "@printLabelFailure": {}, + "printLabelSuccess": "标签已发送到打印机", + "@printLabelSuccess": {}, "profile": "档案", "@profile": {}, + "profileAdd": "添加服务器配置文件", + "@profileAdd": {}, + "profileConnect": "连接到服务器", + "@profileConnect": {}, + "profileEdit": "编辑服务器配置文件", + "@profileEdit": {}, + "profileDelete": "删除服务器配置文件", + "@profileDelete": {}, + "profileLogout": "登出配置文件", + "@profileLogout": {}, + "profileName": "配置文件名称", + "@profileName": {}, + "profileNone": "无可用配置文件", + "@profileNone": {}, + "profileNotSelected": "未选择配置文件", + "@profileNotSelected": {}, + "profileSelect": "选择Inventree 服务器", + "@profileSelect": {}, + "profileSelectOrCreate": "选择服务器或创建新的配置文件", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "点击创建或选择一个配置文件", + "@profileTapToCreate": {}, + "projectCode": "项目编码", + "@projectCode": {}, + "purchaseOrder": "采购订单", + "@purchaseOrder": {}, + "purchaseOrderCreate": "新订购单", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "编辑采购订单", + "@purchaseOrderEdit": {}, + "purchaseOrders": "采购订单", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "订单已更新", + "@purchaseOrderUpdated": {}, + "purchasePrice": "采购价格", + "@purchasePrice": {}, "quantity": "数量", "@quantity": { "description": "Quantity" }, + "quantityAvailable": "可用数量", + "@quantityAvailable": {}, "quantityEmpty": "容量为空", "@quantityEmpty": {}, "quantityInvalid": "数量无效", "@quantityInvalid": {}, "quantityPositive": "数量必须大于0", "@quantityPositive": {}, + "queryEmpty": "输入搜索查询", + "@queryEmpty": {}, + "queryNoResults": "无查询结果", + "@queryNoResults": {}, + "received": "已接收", + "@received": {}, + "receivedFilterDetail": "显示已收到的条目", + "@receivedFilterDetail": {}, + "receiveItem": "接收条目", + "@receiveItem": {}, + "receivedItem": "收到的库存物品", + "@receivedItem": {}, + "reference": "参考", + "@reference": {}, "refresh": "刷新", "@refresh": {}, "refreshing": "正在刷新", @@ -535,14 +625,26 @@ }, "reportBug": "反馈问题", "@reportBug": {}, + "reportBugDescription": "提交 bug 报告 (需要 GitHub 帐户)", + "@reportBugDescription": {}, + "results": "结果", + "@results": {}, "request": "请求", "@request": {}, + "requestFailed": "请求失败", + "@requestFailed": {}, + "requestSuccessful": "请求成功", + "@requestSuccessful": {}, "requestingData": "正在请求数据", "@requestingData": {}, "required": "必填", "@required": { "description": "This field is required" }, + "response400": "错误的请求", + "@response400": {}, + "response401": "未授权", + "@response401": {}, "responseInvalid": "无效响应码", "@responseInvalid": {}, "responseUnknown": "未知响应", From c1c0d469579fac21c8344fefa5df04046aa4a6be Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 10 Nov 2023 20:16:10 +1100 Subject: [PATCH 436/746] New translations app_en.arb (Chinese Simplified) (#447) --- lib/l10n/zh_CN/app_zh_CN.arb | 184 ++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 1 deletion(-) diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index c4ed4e3..896d036 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -30,7 +30,7 @@ "@address": {}, "appAbout": "关于 InventTree", "@appAbout": {}, - "appCredits": "额外应用积分", + "appCredits": "附加应用信用点", "@appCredits": {}, "appDetails": "应用详情", "@appDetails": {}, @@ -645,6 +645,28 @@ "@response400": {}, "response401": "未授权", "@response401": {}, + "response403": "权限受限", + "@response403": {}, + "response404": "资源未找到", + "@response404": {}, + "response405": "方法不允许", + "@response405": {}, + "response429": "太多请求", + "@response429": {}, + "response500": "内部服务器错误", + "@response500": {}, + "response501": "未实施", + "@response501": {}, + "response502": "不良网关", + "@response502": {}, + "response503": "服务暂时不可用", + "@response503": {}, + "response504": "网关超时", + "@response504": {}, + "response505": "HTTP版本不支持", + "@response505": {}, + "responseData": "响应数据", + "@responseData": {}, "responseInvalid": "无效响应码", "@responseInvalid": {}, "responseUnknown": "未知响应", @@ -665,6 +687,14 @@ "@scanBarcode": {}, "scanIntoLocation": "已扫描至位置", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "扫描此项目到此位置", + "@scanIntoLocationDetail": {}, + "scannerExternal": "外部扫描器", + "@scannerExternal": {}, + "scannerExternalDetail": "使用外部扫描仪读取条形码 (分割模式)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "扫描收到的部件", + "@scanReceivedParts": {}, "search": "搜索", "@search": { "description": "search" @@ -679,30 +709,68 @@ "@searchStock": {}, "select": "选择", "@select": {}, + "selectFile": "选择文件", + "@selectFile": {}, + "selectImage": "选择图片", + "@selectImage": {}, + "selectLocation": "选择一个位置", + "@selectLocation": {}, "send": "发送", "@send": {}, "serialNumber": "序列号", "@serialNumber": {}, + "serialNumbers": "序列号", + "@serialNumbers": {}, "server": "服务器", "@server": {}, "serverAddress": "服务器地址", "@serverAddress": {}, + "serverApiRequired": "需要的 API 版本", + "@serverApiRequired": {}, + "serverApiVersion": "服务器 API 版本", + "@serverApiVersion": {}, + "serverAuthenticationError": "授权出错", + "@serverAuthenticationError": {}, + "serverCertificateError": "信任错误", + "@serverCertificateError": {}, + "serverCertificateInvalid": "服务器 HTTPS 证书无效", + "@serverCertificateInvalid": {}, "serverConnected": "已连接至服务器", "@serverConnected": {}, + "serverConnecting": "正在连接服务器……", + "@serverConnecting": {}, + "serverCouldNotConnect": "无法连接到服务器", + "@serverCouldNotConnect": {}, + "serverEmpty": "服务器不能为空。", + "@serverEmpty": {}, "serverError": "服务器错误", "@serverError": {}, "serverDetails": "服务器详情", "@serverDetails": {}, + "serverMissingData": "服务器响应缺少必填字段", + "@serverMissingData": {}, "serverOld": "过时的服务器版本", "@serverOld": {}, "serverSettings": "服务器设置", "@serverSettings": {}, + "serverStart": "服务器必须以 httpp[s] 开始", + "@serverStart": {}, "settings": "设置", "@settings": {}, "serverInstance": "服务器实例", "@serverInstance": {}, "serverNotConnected": "未连接至服务器", "@serverNotConnected": {}, + "serverNotSelected": "未选定服务器", + "@serverNotSelected": {}, + "sku": "存货单位(SKU)", + "@sku": {}, + "sounds": "声音", + "@sounds": {}, + "soundOnBarcodeAction": "播放条形码动作音效", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "服务器错误时播放音效", + "@soundOnServerError": {}, "status": "状态", "@status": {}, "statusCode": "状态码", @@ -711,12 +779,36 @@ "@stock": { "description": "stock" }, + "stockDetails": "当前可用库存数量", + "@stockDetails": {}, "stockItem": "库存项", "@stockItem": { "description": "stock item title" }, "stockItems": "库存项", "@stockItems": {}, + "stockItemCreate": "新建库存项", + "@stockItemCreate": {}, + "stockItemCreateDetail": "在此位置创建新的库存项目", + "@stockItemCreateDetail": {}, + "stockItemDelete": "删除库存项目", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "确定要删除此库存项吗?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "无法删除库存项目", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "库存项目已删除", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "库存历史记录", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "显示历史库存追踪信息", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "已转移的库存物品", + "@stockItemTransferred": {}, + "stockItemUpdated": "库存项目已更新", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "没有可用的库存项目", + "@stockItemsNotAvailable": {}, "stockItemNotes": "库存项注释", "@stockItemNotes": {}, "stockItemUpdateSuccess": "库存项已更新", @@ -729,6 +821,12 @@ }, "stockLocations": "库存位置", "@stockLocations": {}, + "stockTopLevel": "顶级库存位置", + "@stockTopLevel": {}, + "strictHttps": "使用严格的 HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "强制严格检查 HTTPs 证书", + "@strictHttpsDetails": {}, "subcategory": "子类别", "@subcategory": {}, "subcategories": "子类别", @@ -737,10 +835,58 @@ "@sublocation": {}, "sublocations": "次级位置", "@sublocations": {}, + "sublocationNone": "无子块", + "@sublocationNone": {}, + "sublocationNoneDetail": "无可用子块", + "@sublocationNoneDetail": {}, + "submitFeedback": "提交反馈", + "@submitFeedback": {}, + "suppliedParts": "供应商商品", + "@suppliedParts": {}, + "supplier": "供应商", + "@supplier": {}, + "supplierPart": "供应商商品", + "@supplierPart": {}, + "supplierPartEdit": "编辑供应商商品", + "@supplierPartEdit": {}, + "supplierPartNumber": "供应商配件编号", + "@supplierPartNumber": {}, + "supplierPartUpdated": "供应商部件已更新", + "@supplierPartUpdated": {}, + "supplierParts": "供应商商品", + "@supplierParts": {}, + "suppliers": "供应商", + "@suppliers": {}, + "supplierReference": "供应商参号:", + "@supplierReference": {}, + "takePicture": "拍照", + "@takePicture": {}, + "targetDate": "预计日期", + "@targetDate": {}, + "templatePart": "父模板部件", + "@templatePart": {}, + "testName": "测试名", + "@testName": {}, + "testPassedOrFailed": "测试通过或失败", + "@testPassedOrFailed": {}, + "testsRequired": "所需测试", + "@testsRequired": {}, "testResults": "测试结果", "@testResults": { "description": "" }, + "testResultsDetail": "显示库存项测试结果", + "@testResultsDetail": {}, + "testResultAdd": "添加测试结果", + "@testResultAdd": {}, + "testResultNone": "无测试结果", + "@testResultNone": {}, + "testResultNoneDetail": "无可用测试结果", + "@testResultNoneDetail": {}, + "testResultUploadFail": "上传测试结果出错", + "@testResultUploadFail": {}, + "testResultUploadPass": "测试结果上传", + "@testResultUploadPass": {}, "timeout": "超时", "@timeout": { "description": "" @@ -749,6 +895,10 @@ "@tokenError": {}, "tokenMissing": "缺少令牌", "@tokenMissing": {}, + "tokenMissingFromResponse": "响应中缺少访问令牌", + "@tokenMissingFromResponse": {}, + "totalPrice": "总价", + "@totalPrice": {}, "transfer": "转移", "@transfer": { "description": "transfer" @@ -757,18 +907,50 @@ "@transferStock": { "description": "transfer stock" }, + "transferStockDetail": "将物品转移到另一个位置", + "@transferStockDetail": {}, + "transferStockLocation": "转移库存位置", + "@transferStockLocation": {}, + "transferStockLocationDetail": "将此存货位置转移到另一个存货位置", + "@transferStockLocationDetail": {}, + "translate": "转移", + "@translate": {}, + "translateHelp": "协助翻译 InventTree 应用", + "@translateHelp": {}, + "unitPrice": "单价", + "@unitPrice": {}, + "units": "单位", + "@units": {}, "unknownResponse": "未知响应", "@unknownResponse": {}, "upload": "上传", "@upload": {}, + "uploadFailed": "文件上传失败", + "@uploadFailed": {}, + "uploadSuccess": "文件已上传", + "@uploadSuccess": {}, + "usedIn": "用途", + "@usedIn": {}, + "usedInDetails": "需要此部分的组件。", + "@usedInDetails": {}, "username": "用户名", "@username": {}, + "usernameEmpty": "用户名不能为空", + "@usernameEmpty": {}, "value": "值", "@value": { "description": "value" }, + "valueCannotBeEmpty": "数值不能为空", + "@valueCannotBeEmpty": {}, + "valueRequired": "值为必填项", + "@valueRequired": {}, + "variants": "变体", + "@variants": {}, "version": "版本", "@version": {}, + "viewSupplierPart": "查看供应商部件", + "@viewSupplierPart": {}, "website": "网站", "@website": {} } \ No newline at end of file From bdd5470e68b4e843e9e2886b537295ed11298434 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 Nov 2023 23:13:22 +1100 Subject: [PATCH 437/746] Sales order support (#438) * Add new models for SalesOrder - Create generic Order and OrderLine models with common functionality * Refactor - Move some widgets around - Cleanup directory structure * Add link to home screen and nav drawer * Add SalesOrder list widget * Linting fixes * Fix string * Refactor PurchaseOrderDetailWidget * Tweaks to existing code * linting * Fixes for drawer widget * Add "detail" page for SalesOrder * Add more tiles to SalesOrder detail * Allow editing of salesorder * add list filters for sales orders * Display list of line items * Customer updates - Display customer icon on home screen - Fetch sales orders for customer detail page * Cleanup company detail view * Create new sales order from list * Stricter typing for formFields method * Create new PurchaseOrder and SalesOrder from company deatil * Status code updates - Add function for name comparison - Remove hard-coded values * Update view permission checks for home widget * Add ability to manually add SalesOrderLineItem * Add nice progress bar widgets * Display detail view for sales order line item * edit SalesOrderLineItem * Fix unused import * Hide "shipped items" tab - Will be added in a future update --- lib/api.dart | 17 + lib/barcode/barcode.dart | 10 +- lib/generated/i18n.dart | 6 +- lib/inventree/company.dart | 6 +- lib/inventree/model.dart | 2 +- lib/inventree/orders.dart | 107 +++++++ lib/inventree/part.dart | 10 +- lib/inventree/project_code.dart | 2 +- lib/inventree/purchase_order.dart | 127 ++------ lib/inventree/sales_order.dart | 190 +++++++++++ lib/inventree/status_codes.dart | 18 ++ lib/inventree/stock.dart | 12 +- lib/l10n/app_en.arb | 44 ++- lib/preferences.dart | 1 + lib/settings/home_settings.dart | 18 +- lib/widget/{ => company}/company_detail.dart | 128 +++++++- lib/widget/{ => company}/company_list.dart | 2 +- .../{ => company}/supplier_part_detail.dart | 4 +- .../{ => company}/supplier_part_list.dart | 2 +- lib/widget/drawer.dart | 82 +++-- lib/widget/home.dart | 86 +++-- lib/widget/{ => order}/po_line_detail.dart | 29 +- lib/widget/{ => order}/po_line_list.dart | 2 +- .../{ => order}/purchase_order_detail.dart | 101 +++--- .../{ => order}/purchase_order_list.dart | 22 +- lib/widget/order/sales_order_detail.dart | 303 ++++++++++++++++++ lib/widget/order/sales_order_list.dart | 176 ++++++++++ lib/widget/order/so_line_detail.dart | 164 ++++++++++ lib/widget/order/so_line_list.dart | 86 +++++ lib/widget/{ => part}/bom_list.dart | 2 +- lib/widget/{ => part}/category_display.dart | 6 +- lib/widget/{ => part}/category_list.dart | 2 +- lib/widget/{ => part}/part_detail.dart | 18 +- lib/widget/{ => part}/part_image_widget.dart | 0 lib/widget/{ => part}/part_list.dart | 2 +- .../{ => part}/part_parameter_widget.dart | 0 lib/widget/{ => part}/part_suppliers.dart | 2 +- lib/widget/progress.dart | 28 ++ lib/widget/search.dart | 12 +- lib/widget/{ => stock}/location_display.dart | 6 +- lib/widget/{ => stock}/location_list.dart | 2 +- lib/widget/{ => stock}/stock_detail.dart | 10 +- .../{ => stock}/stock_item_history.dart | 0 .../{ => stock}/stock_item_test_results.dart | 0 lib/widget/{ => stock}/stock_list.dart | 2 +- 45 files changed, 1565 insertions(+), 284 deletions(-) create mode 100644 lib/inventree/orders.dart create mode 100644 lib/inventree/sales_order.dart rename lib/widget/{ => company}/company_detail.dart (64%) rename lib/widget/{ => company}/company_list.dart (97%) rename lib/widget/{ => company}/supplier_part_detail.dart (98%) rename lib/widget/{ => company}/supplier_part_list.dart (97%) rename lib/widget/{ => order}/po_line_detail.dart (89%) rename lib/widget/{ => order}/po_line_list.dart (97%) rename lib/widget/{ => order}/purchase_order_detail.dart (74%) rename lib/widget/{ => order}/purchase_order_list.dart (90%) create mode 100644 lib/widget/order/sales_order_detail.dart create mode 100644 lib/widget/order/sales_order_list.dart create mode 100644 lib/widget/order/so_line_detail.dart create mode 100644 lib/widget/order/so_line_list.dart rename lib/widget/{ => part}/bom_list.dart (98%) rename lib/widget/{ => part}/category_display.dart (97%) rename lib/widget/{ => part}/category_list.dart (97%) rename lib/widget/{ => part}/part_detail.dart (97%) rename lib/widget/{ => part}/part_image_widget.dart (100%) rename lib/widget/{ => part}/part_list.dart (98%) rename lib/widget/{ => part}/part_parameter_widget.dart (100%) rename lib/widget/{ => part}/part_suppliers.dart (97%) rename lib/widget/{ => stock}/location_display.dart (98%) rename lib/widget/{ => stock}/location_list.dart (97%) rename lib/widget/{ => stock}/stock_detail.dart (98%) rename lib/widget/{ => stock}/stock_item_history.dart (100%) rename lib/widget/{ => stock}/stock_item_test_results.dart (100%) rename lib/widget/{ => stock}/stock_list.dart (98%) diff --git a/lib/api.dart b/lib/api.dart index b8a2d7b..28f85f3 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -620,6 +620,8 @@ class InvenTreeAPI { _globalSettings.clear(); _userSettings.clear(); + roles.clear(); + _plugins.clear(); serverInfo.clear(); _connectionStatusChanged(); } @@ -672,6 +674,8 @@ class InvenTreeAPI { _connectionStatusChanged(); + fetchStatusCodeData(); + return _connected; } @@ -735,6 +739,10 @@ class InvenTreeAPI { */ bool checkPermission(String role, String permission) { + if (!_connected) { + return false; + } + // If we do not have enough information, assume permission is allowed if (roles.isEmpty) { debug("checkPermission - no roles defined!"); @@ -1624,11 +1632,20 @@ class InvenTreeAPI { InvenTreeStatusCode get StockHistoryStatus => _get_status_class("stock/track/status/"); InvenTreeStatusCode get StockStatus => _get_status_class("stock/status/"); InvenTreeStatusCode get PurchaseOrderStatus => _get_status_class("order/po/status/"); + InvenTreeStatusCode get SalesOrderStatus => _get_status_class("order/so/status/"); void clearStatusCodeData() { StockHistoryStatus.data.clear(); StockStatus.data.clear(); PurchaseOrderStatus.data.clear(); + SalesOrderStatus.data.clear(); + } + + Future fetchStatusCodeData({bool forceReload = true}) async { + StockHistoryStatus.load(forceReload: forceReload); + StockStatus.load(forceReload: forceReload); + PurchaseOrderStatus.load(forceReload: forceReload); + SalesOrderStatus.load(forceReload: forceReload); } int notification_counter = 0; diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index df110e6..4ea044e 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -23,13 +23,13 @@ import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/location_display.dart"; -import "package:inventree/widget/part_detail.dart"; -import "package:inventree/widget/purchase_order_detail.dart"; +import "package:inventree/widget/stock/location_display.dart"; +import "package:inventree/widget/part/part_detail.dart"; +import "package:inventree/widget/order/purchase_order_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/stock_detail.dart"; -import "package:inventree/widget/supplier_part_detail.dart"; +import "package:inventree/widget/stock/stock_detail.dart"; +import "package:inventree/widget/company/supplier_part_detail.dart"; /* diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 09177b8..ad002d5 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -1,8 +1,8 @@ -import 'dart:async'; +import "dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +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 diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 032ee41..4ebbc98 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -22,7 +22,7 @@ class InvenTreeCompany extends InvenTreeModel { List get rolesRequired => ["purchase_order", "sales_order", "return_order"]; @override - Map formFields() { + Map> formFields() { return { "name": {}, "description": {}, @@ -121,8 +121,8 @@ class InvenTreeSupplierPart extends InvenTreeModel { List get rolesRequired => ["part", "purchase_order"]; @override - Map formFields() { - Map fields = { + Map> formFields() { + Map> fields = { "supplier": {}, "SKU": {}, "link": {}, diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index abb7ec6..fd4c29e 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -230,7 +230,7 @@ class InvenTreeModel { // Fields for editing / creating this model // Override per-model - Map formFields() { + Map> formFields() { return {}; } diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart new file mode 100644 index 0000000..0595b2d --- /dev/null +++ b/lib/inventree/orders.dart @@ -0,0 +1,107 @@ +/* + * Base model for various "orders" which share common properties + */ + + +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/part.dart"; + + +/* + * Generic class representing an "order" + */ +class InvenTreeOrder extends InvenTreeModel { + + InvenTreeOrder() : super(); + + InvenTreeOrder.fromJson(Map json) : super.fromJson(json); + + String get issueDate => getString("issue_date"); + + String get completeDate => getString("complete_date"); + + String get creationDate => getString("creation_date"); + + String get targetDate => getString("target_date"); + + int get lineItemCount => getInt("line_items", backup: 0); + + bool get overdue => getBool("overdue"); + + String get reference => getString("reference"); + + int get responsibleId => getInt("responsible"); + + // Project code information + int get projectCodeId => getInt("project_code"); + + String get projectCode => getString("code", subKey: "project_code_detail"); + + String get projectCodeDescription => getString("description", subKey: "project_code_detail"); + + bool get hasProjectCode => projectCode.isNotEmpty; + + int get status => getInt("status"); + + String get statusText => getString("status_text"); + + double? get totalPrice { + String price = getString("total_price"); + + if (price.isEmpty) { + return null; + } else { + return double.tryParse(price); + } + } + + // Return the currency for this order + // Note that the nomenclature in the API changed at some point + String get totalPriceCurrency { + if (jsondata.containsKey("order_currency")) { + return getString("order_currency"); + } else if (jsondata.containsKey("total_price_currency")) { + return getString("total_price_currency"); + } else { + return ""; + } + } +} + + +/* + * Generic class representing an "order line" + */ +class InvenTreeOrderLine extends InvenTreeModel { + + InvenTreeOrderLine() : super(); + + InvenTreeOrderLine.fromJson(Map json) : super.fromJson(json); + + bool get overdue => getBool("overdue"); + + double get quantity => getDouble("quantity"); + + String get reference => getString("reference"); + + int get orderId => getInt("order"); + + InvenTreePart? get part { + dynamic part_detail = jsondata["part_detail"]; + + if (part_detail == null) { + return null; + } else { + return InvenTreePart.fromJson(part_detail as Map); + } + } + + int get partId => getInt("pk", subKey: "part_detail"); + + String get partName => getString("name", subKey: "part_detail"); + + String get partImage => getString("thumbnail", subKey: "part_detail"); + + // TODO: Perhaps parse this as an actual date? + String get targetDate => getString("target_date"); +} \ No newline at end of file diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index e335a11..e44494e 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -27,9 +27,9 @@ class InvenTreePartCategory extends InvenTreeModel { List get rolesRequired => ["part_category"]; @override - Map formFields() { + Map> formFields() { - Map fields = { + Map> fields = { "name": {}, "description": {}, "parent": {}, @@ -140,9 +140,9 @@ class InvenTreePartParameter extends InvenTreeModel { InvenTreeModel createFromJson(Map json) => InvenTreePartParameter.fromJson(json); @override - Map formFields() { + Map> formFields() { - Map fields = { + Map> fields = { "header": { "type": "string", "read_only": true, @@ -200,7 +200,7 @@ class InvenTreePart extends InvenTreeModel { List get rolesRequired => ["part"]; @override - Map formFields() { + Map> formFields() { return { "name": {}, "description": {}, diff --git a/lib/inventree/project_code.dart b/lib/inventree/project_code.dart index 8e2c75b..07a0c19 100644 --- a/lib/inventree/project_code.dart +++ b/lib/inventree/project_code.dart @@ -17,7 +17,7 @@ class InvenTreeProjectCode extends InvenTreeModel { String get URL => "project-code/"; @override - Map formFields() { + Map> formFields() { return { "code": {}, "description": {}, diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index defb9f8..8070894 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,22 +1,22 @@ import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; -import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/orders.dart"; -const int PO_STATUS_PENDING = 10; -const int PO_STATUS_PLACED = 20; -const int PO_STATUS_COMPLETE = 30; -const int PO_STATUS_CANCELLED = 40; -const int PO_STATUS_LOST = 50; -const int PO_STATUS_RETURNED = 60; -class InvenTreePurchaseOrder extends InvenTreeModel { +/* + * Class representing an individual PurchaseOrder instance + */ +class InvenTreePurchaseOrder extends InvenTreeOrder { InvenTreePurchaseOrder() : super(); InvenTreePurchaseOrder.fromJson(Map json) : super.fromJson(json); + @override + InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrder.fromJson(json); + @override String get URL => "order/po/"; @@ -26,8 +26,8 @@ class InvenTreePurchaseOrder extends InvenTreeModel { String get receive_url => "${url}receive/"; @override - Map formFields() { - var fields = { + Map> formFields() { + Map> fields = { "reference": {}, "supplier": { "filters": { @@ -69,33 +69,8 @@ class InvenTreePurchaseOrder extends InvenTreeModel { }; } - String get issueDate => getString("issue_date"); - - String get completeDate => getString("complete_date"); - - String get creationDate => getString("creation_date"); - - String get targetDate => getString("target_date"); - - int get lineItemCount => getInt("line_items", backup: 0); - - bool get overdue => getBool("overdue"); - - String get reference => getString("reference"); - - int get responsibleId => getInt("responsible"); - int get supplierId => getInt("supplier"); - // Project code information - int get projectCodeId => getInt("project_code"); - - String get projectCode => getString("code", subKey: "project_code_detail"); - - String get projectCodeDescription => getString("description", subKey: "project_code_detail"); - - bool get hasProjectCode => projectCode.isNotEmpty; - InvenTreeCompany? get supplier { dynamic supplier_detail = jsondata["supplier_detail"]; @@ -109,39 +84,13 @@ class InvenTreePurchaseOrder extends InvenTreeModel { String get supplierReference => getString("supplier_reference"); - int get status => getInt("status"); + bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED"]); - String get statusText => getString("status_text"); + bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING"]); - bool get isOpen => status == PO_STATUS_PENDING || status == PO_STATUS_PLACED; + bool get isPlaced => api.PurchaseOrderStatus.isNameIn(status, ["PLACED"]); - bool get isPending => status == PO_STATUS_PENDING; - - bool get isPlaced => status == PO_STATUS_PLACED; - - bool get isFailed => status == PO_STATUS_CANCELLED || status == PO_STATUS_LOST || status == PO_STATUS_RETURNED; - - double? get totalPrice { - String price = getString("total_price"); - - if (price.isEmpty) { - return null; - } else { - return double.tryParse(price); - } - } - - // Return the currency for this order - // Note that the nomenclature in the API changed at some point - String get totalPriceCurrency { - if (jsondata.containsKey("order_currency")) { - return getString("order_currency"); - } else if (jsondata.containsKey("total_price_currency")) { - return getString("total_price_currency"); - } else { - return ""; - } - } + bool get isFailed => api.PurchaseOrderStatus.isNameIn(status, ["CANCELLED", "LOST", "RETURNED"]); Future> getLineItems() async { @@ -162,9 +111,6 @@ class InvenTreePurchaseOrder extends InvenTreeModel { return items; } - @override - InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrder.fromJson(json); - /// Mark this order as "placed" / "issued" Future issueOrder() async { // Order can only be placed when the order is 'pending' @@ -185,12 +131,15 @@ class InvenTreePurchaseOrder extends InvenTreeModel { } } -class InvenTreePOLineItem extends InvenTreeModel { +class InvenTreePOLineItem extends InvenTreeOrderLine { InvenTreePOLineItem() : super(); InvenTreePOLineItem.fromJson(Map json) : super.fromJson(json); + @override + InvenTreeModel createFromJson(Map json) => InvenTreePOLineItem.fromJson(json); + @override String get URL => "order/po-line/"; @@ -198,7 +147,7 @@ class InvenTreePOLineItem extends InvenTreeModel { List get rolesRequired => ["purchase_order"]; @override - Map formFields() { + Map> formFields() { return { "part": { // We cannot edit the supplier part field here @@ -232,38 +181,24 @@ class InvenTreePOLineItem extends InvenTreeModel { }; } + double get received => getDouble("received"); + bool get isComplete => received >= quantity; - double get quantity => getDouble("quantity"); + double get progressRatio { + if (quantity <= 0 || received <= 0) { + return 0; + } - double get received => getDouble("received"); + return received / quantity; + } String get progressString => simpleNumberString(received) + " / " + simpleNumberString(quantity); double get outstanding => quantity - received; - String get reference => getString("reference"); - - int get orderId => getInt("order"); - int get supplierPartId => getInt("part"); - InvenTreePart? get part { - dynamic part_detail = jsondata["part_detail"]; - - if (part_detail == null) { - return null; - } else { - return InvenTreePart.fromJson(part_detail as Map); - } - } - - int get partId => getInt("pk", subKey: "part_detail"); - - String get partName => getString("name", subKey: "part_detail"); - - String get partImage => getString("thumbnail", subKey: "part_detail"); - InvenTreeSupplierPart? get supplierPart { dynamic detail = jsondata["supplier_part_detail"]; @@ -281,19 +216,13 @@ class InvenTreePOLineItem extends InvenTreeModel { String get purchasePriceCurrency => getString("purchase_price_currency"); - String get purchasePriceString => getString("purchase_price_string"); - int get destination => getInt("destination"); Map get destinationDetail => getMap("destination_detail"); - - @override - InvenTreeModel createFromJson(Map json) => InvenTreePOLineItem.fromJson(json); - } /* - * Class representing an attachment file against a StockItem object + * Class representing an attachment file against a PurchaseOrder object */ class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart new file mode 100644 index 0000000..1225cb8 --- /dev/null +++ b/lib/inventree/sales_order.dart @@ -0,0 +1,190 @@ + + +import "package:inventree/helpers.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/orders.dart"; + +import "package:inventree/api.dart"; + + +/* + * Class representing an individual SalesOrder + */ +class InvenTreeSalesOrder extends InvenTreeOrder { + + InvenTreeSalesOrder() : super(); + + InvenTreeSalesOrder.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrder.fromJson(json); + + @override + String get URL => "order/so/"; + + @override + List get rolesRequired => ["sales_order"]; + + @override + Map> formFields() { + Map> fields = { + "reference": {}, + "customer": { + "filters": { + "is_customer": true, + } + }, + "customer_reference": {}, + "description": {}, + "project_code": {}, + "target_date": {}, + "link": {}, + "responsible": {}, + "contact": { + "filters": { + "company": customerId, + } + } + }; + + if (!InvenTreeAPI().supportsProjectCodes) { + fields.remove("project_code"); + } + + if (!InvenTreeAPI().supportsContactModel) { + fields.remove("contact"); + } + + return fields; + } + + @override + Map defaultGetFilters() { + return { + "customer_detail": "true", + }; + } + + @override + Map defaultListFilters() { + return { + "customer_detail": "true", + }; + } + + int get customerId => getInt("customer"); + + InvenTreeCompany? get customer { + dynamic customer_detail = jsondata["customer_detail"]; + + if (customer_detail == null) { + return null; + } else { + return InvenTreeCompany.fromJson(customer_detail as Map); + } + } + + String get customerReference => getString("customer_reference"); + + bool get isOpen => api.SalesOrderStatus.isNameIn(status, ["PENDING", "IN_PROGRESS"]); + + bool get isComplete => api.SalesOrderStatus.isNameIn(status, ["SHIPPED"]); + +} + + +/* + * Class representing an individual line item in a SalesOrder + */ +class InvenTreeSOLineItem extends InvenTreeOrderLine { + + InvenTreeSOLineItem() : super(); + + InvenTreeSOLineItem.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeSOLineItem.fromJson(json); + + @override + String get URL => "order/so-line/"; + + @override + List get rolesRequired => ["sales_order"]; + + @override + Map> formFields() { + return { + "order": { + "hidden": true, + }, + "part": {}, + "quantity": {}, + "reference": {}, + "notes": {}, + "link": {}, + }; + } + + @override + Map defaultGetFilters() { + return { + "part_detail": "true", + }; + } + + @override + Map defaultListFilters() { + return { + "part_detail": "true", + }; + } + + double get allocated => getDouble("allocated"); + + bool get isAllocated => allocated >= quantity; + + double get shipped => getDouble("shipped"); + + double get outstanding => quantity - shipped; + + double get progressRatio { + if (quantity <= 0 || shipped <= 0) { + return 0; + } + + return shipped / quantity; + } + + String get progressString => simpleNumberString(shipped) + " / " + simpleNumberString(quantity); + + bool get isComplete => shipped >= quantity; + + double get available => getDouble("available_stock") + getDouble("available_variant_stock"); + + double get salePrice => getDouble("sale_price"); + + String get salePriceCurrency => getString("sale_price_currency"); + +} + + +/* + * Class representing an attachment file against a SalesOrder object + */ +class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { + + InvenTreeSalesOrderAttachment() : super(); + + InvenTreeSalesOrderAttachment.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrderAttachment.fromJson(json); + + @override + String get REFERENCE_FIELD => "order"; + + @override + String get URL => "order/po/attachment/"; + +} diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart index 8edb4ea..9b75280 100644 --- a/lib/inventree/status_codes.dart +++ b/lib/inventree/status_codes.dart @@ -105,6 +105,24 @@ class InvenTreeStatusCode { } } + // Return the 'name' (untranslated) associated with a given status code + String name(int status) { + Map _entry = entry(status); + + String _name = (_entry["name"] ?? "") as String; + + if (_name.isEmpty) { + debug("No match for status code ${status} at '${URL}'"); + } + + return _name; + } + + // Test if the name associated with the given code is in the provided list + bool isNameIn(int code, List names) { + return names.contains(name(code)); + } + // Return the 'color' associated with a given status code Color color(int status) { Map _entry = entry(status); diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 22113d4..4f455fe 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -27,7 +27,7 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { List get rolesRequired => ["stock"]; @override - Map formFields() { + Map> formFields() { return { "stock_item": {"hidden": true}, "test": {}, @@ -158,8 +158,8 @@ class InvenTreeStockItem extends InvenTreeModel { String get WEB_URL => "stock/item/"; @override - Map formFields() { - return { + Map> formFields() { + Map> fields = { "part": {}, "location": {}, "quantity": {}, @@ -175,6 +175,8 @@ class InvenTreeStockItem extends InvenTreeModel { "packaging": {}, "link": {}, }; + + return fields; } @override @@ -609,8 +611,8 @@ class InvenTreeStockLocation extends InvenTreeModel { String get pathstring => getString("pathstring"); @override - Map formFields() { - Map fields = { + Map> formFields() { + Map> fields = { "name": {}, "description": {}, "parent": {}, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e1c1f2e..fb8f91c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -235,9 +235,15 @@ "credits": "Credits", "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", "@damaged": {}, @@ -440,15 +446,21 @@ "homeShowPo": "Show Purchase Orders", "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Show purchase order button on home screen", - "@homeShowPoDescription": {}, - "homeShowSuppliers": "Show Suppliers", "@homeShowSuppliers": {}, @@ -576,6 +588,9 @@ "level": "Level", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", "@lineItem": {}, @@ -687,9 +702,15 @@ "outstanding": "Outstanding", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding items", + "outstandingOrderDetail": "Show outstanding orders", "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", "@packaging": {}, @@ -997,9 +1018,21 @@ "returned": "Returned", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", "@save": { "description": "Save" @@ -1125,6 +1158,9 @@ "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", "@sku": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 3010597..581a5fd 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -11,6 +11,7 @@ import "package:path/path.dart"; // Settings key values const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; const String INV_HOME_SHOW_PO = "homeShowPo"; +const String INV_HOME_SHOW_SO = "homeShowSo"; const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 926f31d..c1bee1f 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -21,6 +21,7 @@ class _HomeScreenSettingsState extends State { // Home screen settings bool homeShowSubscribed = true; bool homeShowPo = true; + bool homeShowSo = true; bool homeShowSuppliers = true; bool homeShowManufacturers = true; bool homeShowCustomers = true; @@ -38,6 +39,7 @@ class _HomeScreenSettingsState extends State { homeShowSubscribed = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUBSCRIBED, true) as bool; homeShowPo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) as bool; + homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; homeShowManufacturers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_MANUFACTURERS, true) as bool; homeShowCustomers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) as bool; homeShowSuppliers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) as bool; @@ -85,6 +87,20 @@ class _HomeScreenSettingsState extends State { }, ), ), + ListTile( + title: Text(L10().homeShowSo), + subtitle: Text(L10().homeShowSoDescription), + leading: FaIcon(FontAwesomeIcons.truck), + trailing: Switch( + value: homeShowSo, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SO, value); + setState(() { + homeShowSo = value; + }); + }, + ), + ), ListTile( title: Text(L10().homeShowSuppliers), subtitle: Text(L10().homeShowSuppliersDescription), @@ -116,6 +132,7 @@ class _HomeScreenSettingsState extends State { }, ), ), + */ ListTile( title: Text(L10().homeShowCustomers), subtitle: Text(L10().homeShowCustomersDescription), @@ -130,7 +147,6 @@ class _HomeScreenSettingsState extends State { }, ), ), - */ ] ) ) diff --git a/lib/widget/company_detail.dart b/lib/widget/company/company_detail.dart similarity index 64% rename from lib/widget/company_detail.dart rename to lib/widget/company/company_detail.dart index 15684a1..bf83ee4 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -9,12 +9,16 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/attachment_widget.dart"; -import "package:inventree/widget/purchase_order_list.dart"; +import "package:inventree/widget/order/purchase_order_list.dart"; +import "package:inventree/widget/order/sales_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/supplier_part_list.dart"; +import "package:inventree/widget/company/supplier_part_list.dart"; +import "package:inventree/widget/order/sales_order_detail.dart"; +import "package:inventree/widget/order/purchase_order_detail.dart"; /* @@ -36,10 +40,11 @@ class _CompanyDetailState extends RefreshableState { _CompanyDetailState(); - List outstandingOrders = []; - int supplierPartCount = 0; + int outstandingPurchaseOrders = 0; + int outstandingSalesOrders = 0; + int attachmentCount = 0; @override @@ -68,11 +73,87 @@ class _CompanyDetailState extends RefreshableState { List actionButtons(BuildContext context) { List actions = []; - // TODO - Actions for this company + if (widget.company.isCustomer && InvenTreeSalesOrder().canCreate) { + actions.add(SpeedDialChild( + child: FaIcon(FontAwesomeIcons.truck), + label: L10().salesOrderCreate, + onTap: () async { + _createSalesOrder(context); + } + )); + } + + if (widget.company.isSupplier && InvenTreePurchaseOrder().canCreate) { + actions.add(SpeedDialChild( + child: FaIcon(FontAwesomeIcons.cartShopping), + label: L10().purchaseOrderCreate, + onTap: () async { + _createPurchaseOrder(context); + } + )); + } return actions; } + Future _createSalesOrder(BuildContext context) async { + var fields = InvenTreeSalesOrder().formFields(); + + // Cannot set contact until company is locked in + fields.remove("contact"); + + fields["customer"]?["value"] = widget.company.pk; + + InvenTreeSalesOrder().createForm( + context, + L10().salesOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var order = InvenTreeSalesOrder.fromJson(data); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderDetailWidget(order) + ) + ); + } + } + ); + } + + Future _createPurchaseOrder(BuildContext context) async { + var fields = InvenTreePurchaseOrder().formFields(); + + // Cannot set contact until company is locked in + fields.remove("contact"); + + fields["supplier"]?["value"] = widget.company.pk; + + InvenTreePurchaseOrder().createForm( + context, + L10().purchaseOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var order = InvenTreePurchaseOrder.fromJson(data); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderDetailWidget(order) + ) + ); + } + } + ); + } + @override Future request(BuildContext context) async { final bool result = await widget.company.reload(); @@ -83,11 +164,18 @@ class _CompanyDetailState extends RefreshableState { return; } - if (widget.company.isSupplier) { - outstandingOrders = - await widget.company.getPurchaseOrders(outstanding: true); - } + outstandingPurchaseOrders = widget.company.isSupplier ? + await InvenTreePurchaseOrder().count(filters: { + "supplier": widget.company.pk.toString(), + "outstanding": "true" + }) : 0; + outstandingSalesOrders = widget.company.isCustomer ? + await InvenTreeSalesOrder().count(filters: { + "customer": widget.company.pk.toString(), + "outstanding": "true" + }) : 0; + InvenTreeSupplierPart().count( filters: { "supplier": widget.company.pk.toString() @@ -224,7 +312,7 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().purchaseOrders), leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_ACTION), - trailing: Text("${outstandingOrders.length}"), + trailing: Text("${outstandingPurchaseOrders}"), onTap: () { Navigator.push( context, @@ -257,7 +345,25 @@ class _CompanyDetailState extends RefreshableState { } if (widget.company.isCustomer) { - // TODO - Add list of sales orders + tiles.add( + ListTile( + title: Text(L10().salesOrders), + leading: FaIcon(FontAwesomeIcons.truck, color: COLOR_ACTION), + trailing: Text("${outstandingSalesOrders}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget( + filters: { + "customer": widget.company.pk.toString() + } + ) + ) + ); + } + ) + ); } if (widget.company.notes.isNotEmpty) { diff --git a/lib/widget/company_list.dart b/lib/widget/company/company_list.dart similarity index 97% rename from lib/widget/company_list.dart rename to lib/widget/company/company_list.dart index a19762c..b68dffd 100644 --- a/lib/widget/company_list.dart +++ b/lib/widget/company/company_list.dart @@ -8,7 +8,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/company_detail.dart"; +import "package:inventree/widget/company/company_detail.dart"; /* diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart similarity index 98% rename from lib/widget/supplier_part_detail.dart rename to lib/widget/company/supplier_part_detail.dart index fe39c80..6ca43cb 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -10,8 +10,8 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/company.dart"; -import "package:inventree/widget/company_detail.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/company/company_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; diff --git a/lib/widget/supplier_part_list.dart b/lib/widget/company/supplier_part_list.dart similarity index 97% rename from lib/widget/supplier_part_list.dart rename to lib/widget/company/supplier_part_list.dart index 3674f66..5f41227 100644 --- a/lib/widget/supplier_part_list.dart +++ b/lib/widget/company/supplier_part_list.dart @@ -8,7 +8,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/supplier_part_detail.dart"; +import "package:inventree/widget/company/supplier_part_detail.dart"; /* diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 2ca8d88..f38ad33 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -3,15 +3,17 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/settings.dart"; -import "package:inventree/widget/category_display.dart"; +import "package:inventree/widget/order/sales_order_list.dart"; +import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/notifications.dart"; -import "package:inventree/widget/purchase_order_list.dart"; -import "package:inventree/widget/location_display.dart"; +import "package:inventree/widget/order/purchase_order_list.dart"; +import "package:inventree/widget/stock/location_display.dart"; /* @@ -28,6 +30,10 @@ class InvenTreeDrawer extends StatelessWidget { Navigator.of(context).pop(); } + bool _checkConnection() { + return InvenTreeAPI().checkConnection(); + } + /* * Return to the 'home' screen. * This will empty the navigation stack. @@ -43,37 +49,63 @@ class InvenTreeDrawer extends StatelessWidget { // Load "parts" page void _parts() { _closeDrawer(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)) - ); + + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)) + ); + } } // Load "stock" page void _stock() { _closeDrawer(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)) - ); + + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)) + ); + } + } + + // Load "sales orders" page + void _salesOrders() { + _closeDrawer(); + + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget(filters: {}) + ) + ); + } } // Load "purchase orders" page void _purchaseOrders() { _closeDrawer(); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PurchaseOrderListWidget(filters: {}) - ) - ); + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderListWidget(filters: {}) + ) + ); + } } // Load notifications screen void _notifications() { _closeDrawer(); - Navigator.push(context, MaterialPageRoute(builder: (context) => NotificationWidget())); + + if (_checkConnection()) { + Navigator.push(context, + MaterialPageRoute(builder: (context) => NotificationWidget())); + } } // Load settings widget @@ -98,7 +130,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add(Divider()); - if (InvenTreeCompany().canView) { + if (InvenTreePart().canView) { tiles.add( ListTile( title: Text(L10().parts), @@ -128,6 +160,16 @@ class InvenTreeDrawer extends StatelessWidget { ); } + if (InvenTreeSalesOrder().canView) { + tiles.add( + ListTile( + title: Text(L10().salesOrders), + leading: FaIcon(FontAwesomeIcons.truck, color: COLOR_ACTION), + onTap: _salesOrders, + ) + ); + } + if (tiles.length > 2) { tiles.add(Divider()); } diff --git a/lib/widget/home.dart b/lib/widget/home.dart index b62daf7..e9034a7 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -6,20 +6,25 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/inventree/stock.dart"; import "package:inventree/preferences.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/select_server.dart"; import "package:inventree/user_profile.dart"; -import "package:inventree/widget/category_display.dart"; +import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/drawer.dart"; -import "package:inventree/widget/location_display.dart"; -import "package:inventree/widget/part_list.dart"; -import "package:inventree/widget/purchase_order_list.dart"; +import "package:inventree/widget/stock/location_display.dart"; +import "package:inventree/widget/part/part_list.dart"; +import "package:inventree/widget/order/purchase_order_list.dart"; +import "package:inventree/widget/order/sales_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/spinner.dart"; -import "package:inventree/widget/company_list.dart"; +import "package:inventree/widget/company/company_list.dart"; class InvenTreeHomePage extends StatefulWidget { @@ -53,6 +58,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr final homeKey = GlobalKey(); bool homeShowPo = false; + bool homeShowSo = false; bool homeShowSubscribed = false; bool homeShowManufacturers = false; bool homeShowCustomers = false; @@ -97,6 +103,17 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr ); } + void _showSalesOrders(BuildContext context) { + if (!InvenTreeAPI().checkConnection()) return; + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget(filters: {}) + ) + ); + } + void _showSuppliers(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; @@ -110,12 +127,12 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().manufacturers, {"is_manufacturer": "true"}))); } + */ void _showCustomers(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"}))); } - */ void _selectProfile() { Navigator.push( @@ -130,6 +147,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr homeShowSubscribed = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUBSCRIBED, true) as bool; homeShowPo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) as bool; + homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; homeShowManufacturers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_MANUFACTURERS, true) as bool; homeShowCustomers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) as bool; homeShowSuppliers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) as bool; @@ -207,17 +225,19 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr ]; // Parts - tiles.add(_listTile( - context, - L10().parts, - FontAwesomeIcons.shapes, - callback: () { - _showParts(context); - }, - )); + if (InvenTreePart().canView) { + tiles.add(_listTile( + context, + L10().parts, + FontAwesomeIcons.shapes, + callback: () { + _showParts(context); + }, + )); + } // Starred parts - if (homeShowSubscribed) { + if (homeShowSubscribed && InvenTreePart().canView) { tiles.add(_listTile( context, L10().partsStarred, @@ -229,17 +249,19 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } // Stock button - tiles.add(_listTile( - context, - L10().stock, - FontAwesomeIcons.boxesStacked, - callback: () { - _showStock(context); - } - )); + if (InvenTreeStockItem().canView) { + tiles.add(_listTile( + context, + L10().stock, + FontAwesomeIcons.boxesStacked, + callback: () { + _showStock(context); + } + )); + } // Purchase orders - if (homeShowPo) { + if (homeShowPo && InvenTreePurchaseOrder().canView) { tiles.add(_listTile( context, L10().purchaseOrders, @@ -250,8 +272,19 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr )); } + if (homeShowSo && InvenTreeSalesOrder().canView) { + tiles.add(_listTile( + context, + L10().salesOrders, + FontAwesomeIcons.truck, + callback: () { + _showSalesOrders(context); + } + )); + } + // Suppliers - if (homeShowSuppliers) { + if (homeShowSuppliers && InvenTreePurchaseOrder().canView) { tiles.add(_listTile( context, L10().suppliers, @@ -277,7 +310,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } )); } - + */ // Customers if (homeShowCustomers) { tiles.add(_listTile( @@ -289,7 +322,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } )); } - */ return tiles; } diff --git a/lib/widget/po_line_detail.dart b/lib/widget/order/po_line_detail.dart similarity index 89% rename from lib/widget/po_line_detail.dart rename to lib/widget/order/po_line_detail.dart index b8ac8aa..d5510d9 100644 --- a/lib/widget/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -7,17 +7,17 @@ import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/widget/progress.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/supplier_part_detail.dart"; +import "package:inventree/widget/company/supplier_part_detail.dart"; /* - * Widget for displaying detail view of a purchase order line item + * Widget for displaying detail view of a single PurchaseOrderLineItem */ class POLineDetailWidget extends StatefulWidget { @@ -171,7 +171,6 @@ class _POLineDetailWidgetState extends RefreshableState { trailing: api.getThumbnail(widget.item.partImage), onTap: () async { showLoadingOverlay(context); - print("part id: ${widget.item.partId}"); var part = await InvenTreePart().get(widget.item.partId); hideLoadingOverlay(); @@ -200,16 +199,32 @@ class _POLineDetailWidgetState extends RefreshableState { ) ); - // Recevied + // Received quantity tiles.add( ListTile( title: Text(L10().received), - subtitle: Text(widget.item.received.toString()), - trailing: Text(widget.item.progressString, style: TextStyle(color: widget.item.isComplete ? COLOR_SUCCESS: COLOR_WARNING)), + subtitle: ProgressBar(widget.item.progressRatio), + trailing: Text( + widget.item.progressString, + style: TextStyle( + color: widget.item.isComplete ? COLOR_SUCCESS: COLOR_WARNING + ) + ), leading: FaIcon(FontAwesomeIcons.boxOpen), ) ); + // Reference + if (widget.item.reference.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().reference), + subtitle: Text(widget.item.reference), + leading: FaIcon(FontAwesomeIcons.hashtag), + ) + ); + } + // Pricing information tiles.add( ListTile( diff --git a/lib/widget/po_line_list.dart b/lib/widget/order/po_line_list.dart similarity index 97% rename from lib/widget/po_line_list.dart rename to lib/widget/order/po_line_list.dart index 27827f8..e7f53d4 100644 --- a/lib/widget/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -9,7 +9,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/paginator.dart"; -import "package:inventree/widget/po_line_detail.dart"; +import "package:inventree/widget/order/po_line_detail.dart"; import "package:inventree/widget/progress.dart"; /* diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart similarity index 74% rename from lib/widget/purchase_order_detail.dart rename to lib/widget/order/purchase_order_detail.dart index f03d4f0..73fa4eb 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -2,9 +2,8 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/po_line_list.dart"; +import "package:inventree/widget/order/po_line_list.dart"; -import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; @@ -13,13 +12,17 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/attachment_widget.dart"; -import "package:inventree/widget/company_detail.dart"; +import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/notes_widget.dart"; +import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/stock_list.dart"; +import "package:inventree/widget/stock/stock_list.dart"; +/* + * Widget for viewing a single PurchaseOrder instance + */ class PurchaseOrderDetailWidget extends StatefulWidget { const PurchaseOrderDetailWidget(this.order, {Key? key}): super(key: key); @@ -27,16 +30,14 @@ class PurchaseOrderDetailWidget extends StatefulWidget { final InvenTreePurchaseOrder order; @override - _PurchaseOrderDetailState createState() => _PurchaseOrderDetailState(order); + _PurchaseOrderDetailState createState() => _PurchaseOrderDetailState(); } class _PurchaseOrderDetailState extends RefreshableState { - _PurchaseOrderDetailState(this.order); - - final InvenTreePurchaseOrder order; - + _PurchaseOrderDetailState(); + List lines = []; int completedLines = 0; @@ -52,7 +53,7 @@ class _PurchaseOrderDetailState extends RefreshableState appBarActions(BuildContext context) { List actions = []; - if (order.canEdit) { + if (widget.order.canEdit) { actions.add( IconButton( icon: Icon(Icons.edit_square), @@ -71,8 +72,8 @@ class _PurchaseOrderDetailState extends RefreshableState actionButtons(BuildContext context) { List actions = []; - if (order.canCreate) { - if (order.isPending) { + if (widget.order.canCreate) { + if (widget.order.isPending) { actions.add( SpeedDialChild( child: FaIcon(FontAwesomeIcons.paperPlane, color: Colors.blue), @@ -84,7 +85,7 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { - await order.reload(); + await widget.order.reload(); await api.PurchaseOrderStatus.load(); - lines = await order.getLineItems(); + lines = await widget.order.getLineItems(); supportProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED"); @@ -174,16 +175,20 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { - var fields = order.formFields(); + var fields = widget.order.formFields(); // Cannot edit supplier field from here fields.remove("supplier"); @@ -198,7 +203,7 @@ class _PurchaseOrderDetailState extends RefreshableState tiles = []; - InvenTreeCompany? supplier = order.supplier; + InvenTreeCompany? supplier = widget.order.supplier; tiles.add(headerTile(context)); - if (supportProjectCodes && order.hasProjectCode) { + if (supportProjectCodes && widget.order.hasProjectCode) { tiles.add(ListTile( title: Text(L10().projectCode), - subtitle: Text("${order.projectCode} - ${order.projectCodeDescription}"), + subtitle: Text("${widget.order.projectCode} - ${widget.order.projectCodeDescription}"), leading: FaIcon(FontAwesomeIcons.list), )); } @@ -261,20 +266,24 @@ class _PurchaseOrderDetailState extends RefreshableState NotesWidget(order) + builder: (context) => NotesWidget(widget.order) ) ); }, @@ -329,8 +338,8 @@ class _PurchaseOrderDetailState extends RefreshableState AttachmentWidget( InvenTreePurchaseOrderAttachment(), - order.pk, - order.canEdit + widget.order.pk, + widget.order.canEdit ) ) ); @@ -355,9 +364,9 @@ class _PurchaseOrderDetailState extends RefreshableState getTabs(BuildContext context) { return [ ListView(children: orderTiles(context)), - PaginatedPOLineList({"order": order.pk.toString()}), + PaginatedPOLineList({"order": widget.order.pk.toString()}), // ListView(children: lineTiles(context)), - PaginatedStockItemList({"purchase_order": order.pk.toString()}), + PaginatedStockItemList({"purchase_order": widget.order.pk.toString()}), ]; } diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart similarity index 90% rename from lib/widget/purchase_order_list.dart rename to lib/widget/order/purchase_order_list.dart index 4404656..1eb851d 100644 --- a/lib/widget/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -5,7 +5,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/widget/paginator.dart"; -import "package:inventree/widget/purchase_order_detail.dart"; +import "package:inventree/widget/order/purchase_order_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -22,15 +22,13 @@ class PurchaseOrderListWidget extends StatefulWidget { final Map filters; @override - _PurchaseOrderListWidgetState createState() => _PurchaseOrderListWidgetState(filters); + _PurchaseOrderListWidgetState createState() => _PurchaseOrderListWidgetState(); } class _PurchaseOrderListWidgetState extends RefreshableState { - _PurchaseOrderListWidgetState(this.filters); - - final Map filters; + _PurchaseOrderListWidgetState(); @override String getAppBarTitle() => L10().purchaseOrders; @@ -45,7 +43,7 @@ class _PurchaseOrderListWidgetState extends RefreshableState createPurchaseOrder(BuildContext context) async { + // Launch form to create a new PurchaseOrder + Future _createPurchaseOrder(BuildContext context) async { var fields = InvenTreePurchaseOrder().formFields(); + // Cannot set contact until company is locked in fields.remove("contact"); InvenTreePurchaseOrder().createForm( @@ -104,7 +104,7 @@ class _PurchaseOrderListWidgetState extends RefreshableState _SalesOrderDetailState(); +} + + +class _SalesOrderDetailState extends RefreshableState { + + _SalesOrderDetailState(); + + List lines = []; + + bool supportsProjectCodes = false; + int completedLines = 0; + int attachmentCount = 0; + + @override + String getAppBarTitle() => L10().salesOrder; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.order.canEdit) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + onPressed: () { + editOrder(context); + }, + ) + ); + } + + return actions; + } + + // Add a new line item to this sales order + Future _addLineItem(BuildContext context) async { + var fields = InvenTreeSOLineItem().formFields(); + + fields["order"]?["value"] = widget.order.pk; + fields["order"]?["hidden"] = true; + + InvenTreeSOLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (result) async { + refresh(context); + } + ); + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + // Add line item + if (widget.order.isOpen && InvenTreeSOLineItem().canCreate) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus), + label: L10().lineItemAdd, + onTap: () async { + _addLineItem(context); + } + ) + ); + } + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + // TODO + + return actions; + } + + @override + Future request(BuildContext context) async { + await widget.order.reload(); + await api.SalesOrderStatus.load(); + + supportsProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED"); + + completedLines = 0; + + for (var line in lines) { + if (line.isComplete) { + completedLines += 1; + } + } + + InvenTreeSalesOrderAttachment().count(filters: { + "order": widget.order.pk.toString() + }).then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } + + // Edit the current SalesOrder instance + Future editOrder(BuildContext context) async { + var fields = widget.order.formFields(); + + fields.remove("customer"); + + // Contact model not supported by server + if (!api.supportsContactModel) { + fields.remove("contact"); + } + + // ProjectCode model not supported by server + if (!supportsProjectCodes) { + fields.remove("project_code"); + } + + widget.order.editForm( + context, + L10().salesOrderEdit, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().salesOrderUpdated, success: true); + } + ); + } + + // Construct header tile + Widget headerTile(BuildContext context) { + InvenTreeCompany? customer = widget.order.customer; + + return Card( + child: ListTile( + title: Text(widget.order.reference), + subtitle: Text(widget.order.description), + leading: customer == null ? null : api.getThumbnail(customer.thumbnail), + trailing: Text( + api.SalesOrderStatus.label(widget.order.status), + style: TextStyle( + color: api.SalesOrderStatus.color(widget.order.status) + ), + ), + ) + ); + } + + List orderTiles(BuildContext context) { + + List tiles = [ + headerTile(context) + ]; + + InvenTreeCompany? customer = widget.order.customer; + + if (supportsProjectCodes && widget.order.hasProjectCode) { + tiles.add(ListTile( + title: Text(L10().projectCode), + subtitle: Text("${widget.order.projectCode} - ${widget.order.projectCodeDescription}"), + leading: FaIcon(FontAwesomeIcons.list), + )); + } + + if (customer != null) { + tiles.add(ListTile( + title: Text(L10().customer), + subtitle: Text(customer.name), + leading: FaIcon(FontAwesomeIcons.userTie, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyDetailWidget(customer) + ) + ); + } + )); + } + + if (widget.order.customerReference.isNotEmpty) { + tiles.add(ListTile( + title: Text(L10().customerReference), + subtitle: Text(widget.order.customerReference), + leading: FaIcon(FontAwesomeIcons.hashtag), + )); + } + + Color lineColor = completedLines < widget.order.lineItemCount ? COLOR_WARNING : COLOR_SUCCESS; + + tiles.add(ListTile( + title: Text(L10().lineItems), + subtitle: ProgressBar( + completedLines.toDouble(), + maximum: widget.order.lineItemCount.toDouble() + ), + leading: FaIcon(FontAwesomeIcons.clipboardCheck), + trailing: Text("${completedLines} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), + )); + + // TODO: total price + + if (widget.order.targetDate.isNotEmpty) { + tiles.add(ListTile( + title: Text(L10().targetDate), + subtitle: Text(widget.order.targetDate), + leading: FaIcon(FontAwesomeIcons.calendarDays), + )); + } + + // Notes tile + tiles.add( + ListTile( + title: Text(L10().notes), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => NotesWidget(widget.order) + ) + ); + }, + ) + ); + + // Attachments + tiles.add( + ListTile( + title: Text(L10().attachments), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeSalesOrderAttachment(), + widget.order.pk, + widget.order.canEdit + ) + ) + ); + }, + ) + ); + + return tiles; + } + + @override + List getTabIcons(BuildContext context) { + return [ + Tab(text: L10().details), + Tab(text: L10().lineItems), + // TODO: Add in the "shipped items" tab + // Tab(text: L10().shipped) + ]; + } + + @override + List getTabs(BuildContext context) { + return [ + ListView(children: orderTiles(context)), + PaginatedSOLineList({"order": widget.order.pk.toString()}), + // Center(), // TODO: Delivered stock + ]; + } + +} \ No newline at end of file diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart new file mode 100644 index 0000000..a97de80 --- /dev/null +++ b/lib/widget/order/sales_order_list.dart @@ -0,0 +1,176 @@ + +import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/order/sales_order_detail.dart"; +import "package:inventree/widget/paginator.dart"; + +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/model.dart"; + + +class SalesOrderListWidget extends StatefulWidget { + + const SalesOrderListWidget({this.filters = const {}, Key? key}) : super(key: key); + + final Map filters; + + @override + _SalesOrderListWidgetState createState() => _SalesOrderListWidgetState(); + +} + +class _SalesOrderListWidgetState extends RefreshableState { + + _SalesOrderListWidgetState(); + + @override + String getAppBarTitle() => L10().salesOrders; + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreeSalesOrder().canCreate) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus), + label: L10().salesOrderCreate, + onTap: () { + _createSalesOrder(context); + } + ) + ); + } + + return actions; + } + + // Launch form to create a new SalesOrder + Future _createSalesOrder(BuildContext context) async { + var fields = InvenTreeSalesOrder().formFields(); + + // Cannot set contact until company is locked in + fields.remove("contact"); + + InvenTreeSalesOrder().createForm( + context, + L10().salesOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var order = InvenTreeSalesOrder.fromJson(data); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderDetailWidget(order) + ) + ); + } + } + ); + } + + @override + List barcodeButtons(BuildContext context) { + // TODO: return custom barcode actions + return []; + } + + @override + Widget getBody(BuildContext context) { + return PaginatedSalesOrderList(widget.filters); + } + +} + + +class PaginatedSalesOrderList extends PaginatedSearchWidget { + + const PaginatedSalesOrderList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().salesOrders; + + @override + _PaginatedSalesOrderListState createState() => _PaginatedSalesOrderListState(); + +} + + +class _PaginatedSalesOrderListState extends PaginatedSearchState { + + _PaginatedSalesOrderListState() : super(); + + @override + String get prefix => "so_"; + + @override + Map get orderingOptions => { + "reference": L10().reference, + "status": L10().status, + "target_date": L10().targetDate, + "customer__name": L10().customer, + }; + + @override + Map> get filterOptions => { + "outstanding": { + "label": L10().outstanding, + "help_text": L10().outstandingOrderDetail, + "tristate": true, + }, + "overdue": { + "label": L10().overdue, + "help_text": L10().overdueDetail, + "tristate": true, + } + }; + + @override + Future requestPage(int limit, int offset, Map params) async { + + await InvenTreeAPI().SalesOrderStatus.load(); + final page = await InvenTreeSalesOrder().listPaginated(limit, offset, filters: params); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + + InvenTreeSalesOrder order = model as InvenTreeSalesOrder; + + InvenTreeCompany? customer = order.customer; + + return ListTile( + title: Text(order.reference), + subtitle: Text(order.description), + leading: customer == null ? null : InvenTreeAPI().getThumbnail(customer.thumbnail), + trailing: Text( + InvenTreeAPI().SalesOrderStatus.label(order.status), + style: TextStyle( + color: InvenTreeAPI().SalesOrderStatus.color(order.status), + ) + ), + onTap: () async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderDetailWidget(order) + ) + ); + } + ); + + } + +} \ No newline at end of file diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart new file mode 100644 index 0000000..e0ddd89 --- /dev/null +++ b/lib/widget/order/so_line_detail.dart @@ -0,0 +1,164 @@ + + +/* + * Widget for displaying detail view of a single SalesOrderLineItem + */ +import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +import "package:inventree/app_colors.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/part/part_detail.dart"; + +import "package:inventree/helpers.dart"; +import "package:inventree/widget/snacks.dart"; + + +class SoLineDetailWidget extends StatefulWidget { + + const SoLineDetailWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreeSOLineItem item; + + @override + _SOLineDetailWidgetState createState() => _SOLineDetailWidgetState(); + +} + + +class _SOLineDetailWidgetState extends RefreshableState { + + _SOLineDetailWidgetState(); + + @override + String getAppBarTitle() => L10().lineItem; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.item.canEdit) { + actions.add( + IconButton( + icon: Icon(Icons.edit_square), + onPressed: () { + _editLineItem(context); + }), + ); + } + + return actions; + } + + Future _editLineItem(BuildContext context) async { + var fields = widget.item.formFields(); + + // Prevent editing of the line item + if (widget.item.shipped > 0) { + fields["part"]?["hidden"] = true; + } + + widget.item.editForm( + context, + L10().editLineItem, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().lineItemUpdated, success: true); + } + ); + } + + @override + List actionButtons(BuildContext context) { + // TODO + return []; + } + + @override + Future request(BuildContext context) async { + await widget.item.reload(); + } + + @override + List getTiles(BuildContext context) { + List tiles = []; + + // Reference to the part + tiles.add( + ListTile( + title: Text(L10().part), + subtitle: Text(widget.item.partName), + leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + trailing: api.getThumbnail(widget.item.partImage), + onTap: () async { + showLoadingOverlay(context); + var part = await InvenTreePart().get(widget.item.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + } + } + ) + ); + + // Shipped quantity + tiles.add( + ListTile( + title: Text(L10().shipped), + subtitle: ProgressBar(widget.item.progressRatio), + trailing: Text( + widget.item.progressString, + style: TextStyle( + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING + ), + ), + leading: FaIcon(FontAwesomeIcons.truck) + ) + ); + + // Reference + if (widget.item.reference.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().reference), + subtitle: Text(widget.item.reference), + leading: FaIcon(FontAwesomeIcons.hashtag) + ) + ); + } + + // Note + if (widget.item.notes.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.item.notes), + leading: FaIcon(FontAwesomeIcons.noteSticky), + ) + ); + } + + // External link + if (widget.item.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().link), + subtitle: Text(widget.item.link), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + onTap: () async { + await openLink(widget.item.link); + }, + ) + ); + } + + return tiles; + } +} \ No newline at end of file diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart new file mode 100644 index 0000000..6d7e1ac --- /dev/null +++ b/lib/widget/order/so_line_list.dart @@ -0,0 +1,86 @@ +import "package:flutter/material.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/order/so_line_detail.dart"; +import "package:inventree/widget/paginator.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/widget/progress.dart"; + + +/* + * Paginated widget class for displaying a list of sales order line items + */ + +class PaginatedSOLineList extends PaginatedSearchWidget { + const PaginatedSOLineList(Map filters) : super(filters: filters); + + @override + String get searchTitle => L10().lineItems; + + @override + _PaginatedSOLineListState createState() => _PaginatedSOLineListState(); + +} + + +/* + * State class for PaginatedSOLineList + */ +class _PaginatedSOLineListState extends PaginatedSearchState { + + _PaginatedSOLineListState() : super(); + + @override + String get prefix => "so_line_"; + + @override + Map get orderingOptions => { + "part": L10().part, + "quantity": L10().quantity, + }; + + @override + Map> get filterOptions => { + + }; + + @override + Future requestPage(int limit, int offset, Map params) async { + final page = await InvenTreeSOLineItem().listPaginated(limit, offset, filters: params); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeSOLineItem item = model as InvenTreeSOLineItem; + InvenTreePart? part = item.part; + + if (part != null) { + return ListTile( + title: Text(part.name), + subtitle: Text(part.description), + leading: InvenTreeAPI().getThumbnail(part.thumbnail), + trailing: Text(item.progressString), + onTap: () async { + showLoadingOverlay(context); + await item.reload(); + hideLoadingOverlay(); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SoLineDetailWidget(item)) + ); + } + ); + } else { + return ListTile( + title: Text(L10().error), + subtitle: Text("Missing part detail", style: TextStyle(color: COLOR_DANGER)), + ); + } + } + +} diff --git a/lib/widget/bom_list.dart b/lib/widget/part/bom_list.dart similarity index 98% rename from lib/widget/bom_list.dart rename to lib/widget/part/bom_list.dart index a39b277..d9e16bb 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/part/bom_list.dart @@ -11,7 +11,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/paginator.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; diff --git a/lib/widget/category_display.dart b/lib/widget/part/category_display.dart similarity index 97% rename from lib/widget/category_display.dart rename to lib/widget/part/category_display.dart index 261840a..c399cef 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -7,11 +7,11 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/widget/category_list.dart"; -import "package:inventree/widget/part_list.dart"; +import "package:inventree/widget/part/category_list.dart"; +import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; diff --git a/lib/widget/category_list.dart b/lib/widget/part/category_list.dart similarity index 97% rename from lib/widget/category_list.dart rename to lib/widget/part/category_list.dart index c1c9551..a203102 100644 --- a/lib/widget/category_list.dart +++ b/lib/widget/part/category_list.dart @@ -2,7 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/widget/category_display.dart"; +import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; diff --git a/lib/widget/part_detail.dart b/lib/widget/part/part_detail.dart similarity index 97% rename from lib/widget/part_detail.dart rename to lib/widget/part/part_detail.dart index 1079fb1..8009ee6 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -15,18 +15,18 @@ import "package:inventree/labels.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/attachment_widget.dart"; -import "package:inventree/widget/bom_list.dart"; -import "package:inventree/widget/part_list.dart"; +import "package:inventree/widget/part/bom_list.dart"; +import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/notes_widget.dart"; -import "package:inventree/widget/part_parameter_widget.dart"; +import "package:inventree/widget/part/part_parameter_widget.dart"; import "package:inventree/widget/progress.dart"; -import "package:inventree/widget/category_display.dart"; +import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/part_image_widget.dart"; +import "package:inventree/widget/part/part_image_widget.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/stock_detail.dart"; -import "package:inventree/widget/stock_list.dart"; -import "package:inventree/widget/supplier_part_list.dart"; +import "package:inventree/widget/stock/stock_detail.dart"; +import "package:inventree/widget/stock/stock_list.dart"; +import "package:inventree/widget/company/supplier_part_list.dart"; /* @@ -634,7 +634,7 @@ class _PartDisplayState extends RefreshableState { fields.remove("serial"); // Hide the "part" field - fields["part"]["hidden"] = true; + fields["part"]?["hidden"] = true; int? default_location = part.defaultLocation; diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part/part_image_widget.dart similarity index 100% rename from lib/widget/part_image_widget.dart rename to lib/widget/part/part_image_widget.dart diff --git a/lib/widget/part_list.dart b/lib/widget/part/part_list.dart similarity index 98% rename from lib/widget/part_list.dart rename to lib/widget/part/part_list.dart index 6def9b1..80dbdbd 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part/part_list.dart @@ -7,7 +7,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/widget/paginator.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; diff --git a/lib/widget/part_parameter_widget.dart b/lib/widget/part/part_parameter_widget.dart similarity index 100% rename from lib/widget/part_parameter_widget.dart rename to lib/widget/part/part_parameter_widget.dart diff --git a/lib/widget/part_suppliers.dart b/lib/widget/part/part_suppliers.dart similarity index 97% rename from lib/widget/part_suppliers.dart rename to lib/widget/part/part_suppliers.dart index b9fb05a..ae3788d 100644 --- a/lib/widget/part_suppliers.dart +++ b/lib/widget/part/part_suppliers.dart @@ -7,7 +7,7 @@ import "package:inventree/api.dart"; import "package:flutter/material.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/company.dart"; -import "package:inventree/widget/company_detail.dart"; +import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; class PartSupplierWidget extends StatefulWidget { diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index 8417469..ff13cee 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -2,6 +2,34 @@ import "package:flutter/material.dart"; import "package:flutter_overlay_loader/flutter_overlay_loader.dart"; +import "package:inventree/app_colors.dart"; + + +/* + * A simplified linear progress bar widget, + * with standardized color depiction + */ +Widget ProgressBar( + double value, +{ + double maximum = 1.0 +}) { + + double v = 0; + + if (value <= 0 || maximum <= 0) { + v = 0; + } else { + v = value / maximum; + } + + return LinearProgressIndicator( + value: v, + backgroundColor: Colors.grey, + color: v >= 1 ? COLOR_SUCCESS : COLOR_WARNING, + ); +} + /* * Construct a circular progress indicator diff --git a/lib/widget/search.dart b/lib/widget/search.dart index a719633..a899c83 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -11,13 +11,13 @@ import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/stock.dart"; -import "package:inventree/widget/part_list.dart"; -import "package:inventree/widget/purchase_order_list.dart"; +import "package:inventree/widget/part/part_list.dart"; +import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/stock_list.dart"; -import "package:inventree/widget/category_list.dart"; -import "package:inventree/widget/company_list.dart"; -import "package:inventree/widget/location_list.dart"; +import "package:inventree/widget/stock/stock_list.dart"; +import "package:inventree/widget/part/category_list.dart"; +import "package:inventree/widget/company/company_list.dart"; +import "package:inventree/widget/stock/location_list.dart"; // Widget for performing database-wide search diff --git a/lib/widget/location_display.dart b/lib/widget/stock/location_display.dart similarity index 98% rename from lib/widget/location_display.dart rename to lib/widget/stock/location_display.dart index 4e89f86..e44e726 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -10,12 +10,12 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/preferences.dart"; -import "package:inventree/widget/location_list.dart"; +import "package:inventree/widget/stock/location_list.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/stock_detail.dart"; -import "package:inventree/widget/stock_list.dart"; +import "package:inventree/widget/stock/stock_detail.dart"; +import "package:inventree/widget/stock/stock_list.dart"; import "package:inventree/labels.dart"; diff --git a/lib/widget/location_list.dart b/lib/widget/stock/location_list.dart similarity index 97% rename from lib/widget/location_list.dart rename to lib/widget/stock/location_list.dart index fe39659..a8bc2fe 100644 --- a/lib/widget/location_list.dart +++ b/lib/widget/stock/location_list.dart @@ -2,7 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; -import "package:inventree/widget/location_display.dart"; +import "package:inventree/widget/stock/location_display.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock/stock_detail.dart similarity index 98% rename from lib/widget/stock_detail.dart rename to lib/widget/stock/stock_detail.dart index b917e01..d9b4edf 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -16,16 +16,16 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/widget/supplier_part_detail.dart"; +import "package:inventree/widget/company/supplier_part_detail.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/attachment_widget.dart"; -import "package:inventree/widget/location_display.dart"; -import "package:inventree/widget/part_detail.dart"; +import "package:inventree/widget/stock/location_display.dart"; +import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/stock_item_history.dart"; -import "package:inventree/widget/stock_item_test_results.dart"; +import "package:inventree/widget/stock/stock_item_history.dart"; +import "package:inventree/widget/stock/stock_item_test_results.dart"; import "package:inventree/widget/notes_widget.dart"; diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock/stock_item_history.dart similarity index 100% rename from lib/widget/stock_item_history.dart rename to lib/widget/stock/stock_item_history.dart diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock/stock_item_test_results.dart similarity index 100% rename from lib/widget/stock_item_test_results.dart rename to lib/widget/stock/stock_item_test_results.dart diff --git a/lib/widget/stock_list.dart b/lib/widget/stock/stock_list.dart similarity index 98% rename from lib/widget/stock_list.dart rename to lib/widget/stock/stock_list.dart index 3fa474a..c24c35c 100644 --- a/lib/widget/stock_list.dart +++ b/lib/widget/stock/stock_list.dart @@ -5,7 +5,7 @@ import "package:inventree/inventree/stock.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; -import "package:inventree/widget/stock_detail.dart"; +import "package:inventree/widget/stock/stock_detail.dart"; import "package:inventree/api.dart"; From e22ba95214d53d448a617cad6e768843f5956ffe Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 Nov 2023 23:26:07 +1100 Subject: [PATCH 438/746] New translations app_en.arb (German) (#450) --- lib/l10n/de_DE/app_de_DE.arb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index af8ee30..97d0910 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -114,6 +114,10 @@ "@build": {}, "building": "Gebäude", "@building": {}, + "cameraInternal": "Integrierte Kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Integrierte Kamera zum Lesen von Barcodes verwenden", + "@cameraInternalDetail": {}, "cancel": "Abbrechen", "@cancel": { "description": "Cancel" @@ -399,6 +403,8 @@ "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", "@locationUpdated": {}, + "loginEnterDetails": "Benutzername und Passwort werden nicht lokal gespeichert", + "@loginEnterDetails": {}, "link": "Link", "@link": {}, "lost": "Verloren", @@ -537,6 +543,8 @@ "@profileEdit": {}, "profileDelete": "Server-Profil löschen", "@profileDelete": {}, + "profileLogout": "Profil abmelden", + "@profileLogout": {}, "profileName": "Profil-Name", "@profileName": {}, "profileNone": "Keine Profile angelegt", @@ -671,6 +679,10 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Artikel per Scan zu Lagerort hinzufügen", "@scanIntoLocationDetail": {}, + "scannerExternal": "Externer Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Benutze externen Scanner um Barcodes zu lesen", + "@scannerExternalDetail": {}, "search": "Suchen", "@search": { "description": "search" From bb87d0dd6d56b3d1413c53b2562b3322385d489d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 Nov 2023 23:43:52 +1100 Subject: [PATCH 439/746] Item deplete fix (#452) * Add status code information to server error message * More informative error message for 404 * Update release note --- assets/release_notes.md | 6 ++++++ lib/inventree/model.dart | 25 ++++++++++++++++++++----- lib/l10n/app_en.arb | 3 +++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 0a25673..dc12be1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.14.0 - November 2023 +--- + +- Adds support for Sales Orders +- Fixes bug when removing entire quantity of a stock item + ### 0.13.0 - October 2023 --- diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index fd4c29e..63bcc50 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -3,6 +3,7 @@ import "dart:io"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter/material.dart"; +import "package:inventree/widget/snacks.dart"; import "package:url_launcher/url_launcher.dart"; import "package:path/path.dart" as path; @@ -553,11 +554,25 @@ class InvenTreeModel { return false; } } else { - showServerError( - url, - L10().serverError, - L10().errorFetch, - ); + + switch (response.statusCode) { + case 404: // Object has been deleted + showSnackIcon( + L10().itemDeleted, + success: false, + ); + break; + default: + String detail = L10().errorFetch; + detail += "\n${L10().statusCode}: ${response.statusCode}"; + + showServerError( + url, + L10().serverError, + detail + ); + break; + } return false; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fb8f91c..c47b495 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -557,6 +557,9 @@ "itemInLocation": "Item already in location", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", "@keywords": {}, From 20127c6090bf473bf405145bc6328e804eae5f19 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 13 Nov 2023 20:48:28 +1100 Subject: [PATCH 440/746] New Crowdin updates (#454) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Hindi) * New translations app_en.arb (Bulgarian) --- lib/l10n/bg_BG/app_bg_BG.arb | 3 ++- lib/l10n/cs_CZ/app_cs_CZ.arb | 7 +++---- lib/l10n/da_DK/app_da_DK.arb | 3 ++- lib/l10n/de_DE/app_de_DE.arb | 7 +++---- lib/l10n/el_GR/app_el_GR.arb | 3 ++- lib/l10n/es_ES/app_es_ES.arb | 5 +++-- lib/l10n/es_MX/app_es_MX.arb | 7 +++---- lib/l10n/fa_IR/app_fa_IR.arb | 3 ++- lib/l10n/fi_FI/app_fi_FI.arb | 1 + lib/l10n/fr_FR/app_fr_FR.arb | 7 +++---- lib/l10n/he_IL/app_he_IL.arb | 3 ++- lib/l10n/hi_IN/app_hi_IN.arb | 3 ++- lib/l10n/hu_HU/app_hu_HU.arb | 7 +++---- lib/l10n/id_ID/app_id_ID.arb | 1 + lib/l10n/it_IT/app_it_IT.arb | 5 +++-- lib/l10n/ja_JP/app_ja_JP.arb | 1 + lib/l10n/ko_KR/app_ko_KR.arb | 1 + lib/l10n/nl_NL/app_nl_NL.arb | 7 +++---- lib/l10n/no_NO/app_no_NO.arb | 7 +++---- lib/l10n/pl_PL/app_pl_PL.arb | 5 +++-- lib/l10n/pt_BR/app_pt_BR.arb | 7 +++---- lib/l10n/pt_PT/app_pt_PT.arb | 3 ++- lib/l10n/ru_RU/app_ru_RU.arb | 7 +++---- lib/l10n/sl_SI/app_sl_SI.arb | 3 ++- lib/l10n/sv_SE/app_sv_SE.arb | 1 + lib/l10n/th_TH/app_th_TH.arb | 3 ++- lib/l10n/tr_TR/app_tr_TR.arb | 5 +++-- lib/l10n/vi_VN/app_vi_VN.arb | 7 +++---- lib/l10n/zh_CN/app_zh_CN.arb | 7 +++---- lib/l10n/zh_TW/app_zh_TW.arb | 1 + 30 files changed, 69 insertions(+), 61 deletions(-) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 55f9683..f3dcbcd 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -1,5 +1,6 @@ { "@@locale": "bg", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index a95a56e..7105b3d 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -275,12 +275,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Zobrazit objednávky", "@homeShowPo": {}, + "homeShowPoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Odebírané díly", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Zobrazit odebírané díly na domovské obrazovce", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Zobrazit dodavatele", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Zobrazit tlačítko dodavatele na domovské obrazovce", @@ -419,8 +419,6 @@ "@onOrderDetails": {}, "outstanding": "Nevyřízené", "@outstanding": {}, - "outstandingOrderDetail": "Zobrazit nevyřízené položky", - "@outstandingOrderDetail": {}, "packaging": "Balení", "@packaging": {}, "packageName": "Název balíčku", @@ -631,6 +629,7 @@ "@returned": {}, "salesOrders": "Prodejní objednávky", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Uložit", "@save": { "description": "Save" diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 88c45d5..17e3377 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -1,5 +1,6 @@ { "@@locale": "da", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 97d0910..8c94a37 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -295,12 +295,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Bestellungen anzeigen", "@homeShowPo": {}, + "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Abonnierte Teile", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Lieferanten anzeigen", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Lieferanten auf Startseite anzeigen", @@ -455,8 +455,6 @@ "@orientationSystem": {}, "outstanding": "Ausstehend", "@outstanding": {}, - "outstandingOrderDetail": "Ausstehende Artikel anzeigen", - "@outstandingOrderDetail": {}, "packaging": "Paket", "@packaging": {}, "packageName": "Paket-Name", @@ -669,6 +667,7 @@ "@returned": {}, "salesOrders": "Kundenauftrag", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Speichern", "@save": { "description": "Save" diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 0a07b12..1daa12a 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -31,5 +31,6 @@ "categoryCreate": "Νέα Κατηγορία", "@categoryCreate": {}, "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 6417056..6629a16 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -263,12 +263,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Mostrar órdenes de compra", "@homeShowPo": {}, + "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Piezas Destacadas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar piezas destacadas en la pantalla de inicio", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Mostrar Proveedores", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Mostrar botón de proveedores en la pantalla de inicio", @@ -595,6 +595,7 @@ "@returned": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Guardar", "@save": { "description": "Save" diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 512859d..4c24e6b 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -291,12 +291,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Mostrar órdenes de compra", "@homeShowPo": {}, + "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Partes Suscritas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar las partes suscritas en la página principal", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Mostrar Proveedores", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Mostrar botón de proveedores en la pantalla de inicio", @@ -449,8 +449,6 @@ "@orientationSystem": {}, "outstanding": "Pendiente", "@outstanding": {}, - "outstandingOrderDetail": "Mostrar artículos pendientes", - "@outstandingOrderDetail": {}, "packaging": "Embalaje", "@packaging": {}, "packageName": "Nombre de Paquete", @@ -661,6 +659,7 @@ "@returned": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Guardar", "@save": { "description": "Save" diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index fc4f529..c3329f5 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,6 @@ { "@@locale": "fa", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 733dbcc..046381d 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -325,6 +325,7 @@ "@response505": {}, "responseUnknown": "Tuntematon vastaus", "@responseUnknown": {}, + "@saleOrderCreate": {}, "save": "Tallenna", "@save": { "description": "Save" diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 91e852e..fab5fb5 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -289,12 +289,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Voir bon de commande", "@homeShowPo": {}, + "homeShowPoDescription": "Afficher le bouton de l'ordre d'achat sur l'écran d'accueil", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Pièces suivies", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Afficher le bouton de l'ordre d'achat sur l'écran d'accueil", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Afficher les fournisseurs", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Afficher le bouton fournisseurs sur l'écran d'accueil", @@ -445,8 +445,6 @@ "@orientationSystem": {}, "outstanding": "En attente", "@outstanding": {}, - "outstandingOrderDetail": "Afficher les commandes en attente", - "@outstandingOrderDetail": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -657,6 +655,7 @@ "@returned": {}, "salesOrders": "Ventes", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Enregistrer", "@save": { "description": "Save" diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 9c4a221..2a2c1e0 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,6 @@ { "@@locale": "he", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 213d5df..bf55292 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -1,5 +1,6 @@ { "@@locale": "hi", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 46a2814..6f80ad7 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -291,12 +291,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Beszerzési rendelések megjelenítése", "@homeShowPo": {}, + "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Értesítésre beállított alkatrészek", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Beszállítók megjelenítése", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Beszállítók gomb megjelenítése a főoldalon", @@ -449,8 +449,6 @@ "@orientationSystem": {}, "outstanding": "Kintlévő", "@outstanding": {}, - "outstandingOrderDetail": "Hiányzó tételek megjelenítése", - "@outstandingOrderDetail": {}, "packaging": "Csomagolás", "@packaging": {}, "packageName": "Csomag neve", @@ -661,6 +659,7 @@ "@returned": {}, "salesOrders": "Vevői rendelések", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Mentés", "@save": { "description": "Save" diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index fa8947a..f135d89 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -4,6 +4,7 @@ "@homeShowSupplierDescription": {}, "imageUploadSuccess": "Gambar telah diunggah", "@imageUploadSuccess": {}, + "@saleOrderCreate": {}, "save": "Simpan", "@save": { "description": "Save" diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 703ae7c..3b15de4 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -275,12 +275,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Mostra Ordini di Acquisto", "@homeShowPo": {}, + "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Articoli Sottoscritti", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostra gli articoli sottoscritti sulla schermata home", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Mostra Fornitori", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Mostra il pulsante fornitori nella schermata home", @@ -617,6 +617,7 @@ "@returned": {}, "salesOrders": "Ordini di vendita", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Salva", "@save": { "description": "Save" diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 8a8e081..a7f096d 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -488,6 +488,7 @@ }, "returned": "返品済", "@returned": {}, + "@saleOrderCreate": {}, "save": "保存", "@save": { "description": "Save" diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 53bcc17..54efe61 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -50,6 +50,7 @@ "@reportBug": {}, "response505": "지원되지 않는 HTTP 버전", "@response505": {}, + "@saleOrderCreate": {}, "save": "저장", "@save": { "description": "Save" diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index de53bff..6eb2071 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -291,12 +291,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Inkooporders tonen", "@homeShowPo": {}, + "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Geabonneerde Onderdelen", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Geabonneerde Onderdelen weergeven op startscherm", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Leveranciers weergeven", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Leveranciersknop weergeven op startscherm", @@ -449,8 +449,6 @@ "@orientationSystem": {}, "outstanding": "Openstaand", "@outstanding": {}, - "outstandingOrderDetail": "Openstaande items tonen", - "@outstandingOrderDetail": {}, "packaging": "Verpakkingen", "@packaging": {}, "packageName": "Pakketnaam", @@ -661,6 +659,7 @@ "@returned": {}, "salesOrders": "Verkooporders", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Bewaren", "@save": { "description": "Save" diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index a6970cb..887d100 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -275,12 +275,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Vis innkjøpsordrer", "@homeShowPo": {}, + "homeShowPoDescription": "Vis innkjøpsordre-knappen på startside", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Abonnerte deler", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Vis abonnerte deler på startside", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Vis innkjøpsordre-knappen på startside", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Vis leverandører", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Vis leverandørknapp på startside", @@ -419,8 +419,6 @@ "@onOrderDetails": {}, "outstanding": "Utestående", "@outstanding": {}, - "outstandingOrderDetail": "Vis utestående artikler", - "@outstandingOrderDetail": {}, "packaging": "Emballasje", "@packaging": {}, "packageName": "Pakkenavn", @@ -631,6 +629,7 @@ "@returned": {}, "salesOrders": "Salgsordre", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Lagre", "@save": { "description": "Save" diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 4474772..86bc620 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -204,12 +204,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Pokaż zamówienia zakupu", "@homeShowPo": {}, + "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Obserwowane części", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Pokaż dostawców", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Pokaż przycisk dostawców na ekranie głównym", @@ -484,6 +484,7 @@ "@returned": {}, "salesOrders": "Zlecenia Sprzedaży", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Zapisz", "@save": { "description": "Save" diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 4d8028a..f86cfd6 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -291,12 +291,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Mostrar pedidos de compra", "@homeShowPo": {}, + "homeShowPoDescription": "Mostrar botão de ordem de compra na tela inicial", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Peças subscritas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar peças subscritas na tela inicial", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Mostrar botão de ordem de compra na tela inicial", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Mostrar fornecedores", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Mostrar botao de fornecedores na pagina inicial", @@ -449,8 +449,6 @@ "@orientationSystem": {}, "outstanding": "Pendente", "@outstanding": {}, - "outstandingOrderDetail": "Mostrar itens pendentes", - "@outstandingOrderDetail": {}, "packaging": "Embalagem", "@packaging": {}, "packageName": "Nome do pacote", @@ -661,6 +659,7 @@ "@returned": {}, "salesOrders": "Pedido de vendas", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Salvar", "@save": { "description": "Save" diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 8e60015..006f306 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -199,5 +199,6 @@ "lastUpdated": "Ultima atualização", "@lastUpdated": {}, "lineItems": "Itens de linha", - "@lineItems": {} + "@lineItems": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 0d4cb0c..0ac8484 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -291,12 +291,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Показать заказы на поставку", "@homeShowPo": {}, + "homeShowPoDescription": "Показывать кнопку заказа на главном экране", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Детали с включёнными уведомлениями", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Показывать детали, на которые включены уведомления, на главной странице", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Показывать кнопку заказа на главном экране", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Показать поставщиков", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Отображение кнопки поставщиков на главном экране", @@ -449,8 +449,6 @@ "@orientationSystem": {}, "outstanding": "Не оплачено", "@outstanding": {}, - "outstandingOrderDetail": "Показать не оплаченные товары", - "@outstandingOrderDetail": {}, "packaging": "Упаковка", "@packaging": {}, "packageName": "Название упаковки", @@ -661,6 +659,7 @@ "@returned": {}, "salesOrders": "Заказы на продажу", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Сохранить", "@save": { "description": "Save" diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index c51c253..dc5da7f 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -1,5 +1,6 @@ { "@@locale": "sl", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 9f48b4a..068e6e3 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -154,6 +154,7 @@ "@password": {}, "reference": "Referens", "@reference": {}, + "@saleOrderCreate": {}, "save": "Spara", "@save": { "description": "Save" diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 6a6b92f..cd61a88 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,6 @@ { "@@locale": "th", "@homeShowSubscsribedDescription": {}, - "@homeShowSupplierDescription": {} + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 70c900a..7480ce1 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -289,12 +289,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Satın Alma Siparişlerini Göster", "@homeShowPo": {}, + "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Parça bildirimlerine abone ol", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Tedarikçileri Göster", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Tedarikçi butonunu ana ekranda göster", @@ -643,6 +643,7 @@ "@returned": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Kaydet", "@save": { "description": "Save" diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 245014c..e0b2e17 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -285,12 +285,12 @@ "@homeScreenSettings": {}, "homeShowPo": "Hiển thị đơn đặt hàng mới", "@homeShowPo": {}, + "homeShowPoDescription": "Hiển thị đơn hàng mới tại màn hình chính", + "@homeShowPoDescription": {}, "homeShowSubscribed": "Đăng kí phụ kiện", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Hiển thị các phần đã đăng kí trên màn hình chính", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "Hiển thị đơn hàng mới tại màn hình chính", - "@homeShowPoDescription": {}, "homeShowSuppliers": "Hiện nhà cung cấp", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Hiện nút nhà cung cấp tại màn hình chính", @@ -437,8 +437,6 @@ "@orientationSystem": {}, "outstanding": "Nổi bật", "@outstanding": {}, - "outstandingOrderDetail": "Hiển thị mặt hàng nổi bật", - "@outstandingOrderDetail": {}, "packaging": "Đóng gói", "@packaging": {}, "packageName": "Tên gói", @@ -643,6 +641,7 @@ "@returned": {}, "salesOrders": "Đơn đặt hàng", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "Lưu lại", "@save": { "description": "Save" diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 896d036..d94f977 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -301,12 +301,12 @@ "@homeScreenSettings": {}, "homeShowPo": "显示采购订单", "@homeShowPo": {}, + "homeShowPoDescription": "在主屏幕上显示订单按钮", + "@homeShowPoDescription": {}, "homeShowSubscribed": "订阅的商品", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "在主屏幕上显示订阅的商品", "@homeShowSubscsribedDescription": {}, - "homeShowPoDescription": "在主屏幕上显示订单按钮", - "@homeShowPoDescription": {}, "homeShowSuppliers": "显示供应商", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "在主屏幕上显示供应商按钮", @@ -465,8 +465,6 @@ "@orientationSystem": {}, "outstanding": "未完成", "@outstanding": {}, - "outstandingOrderDetail": "显示未完成项目", - "@outstandingOrderDetail": {}, "packaging": "打包", "@packaging": {}, "packageName": "包名", @@ -679,6 +677,7 @@ "@returned": {}, "salesOrders": "销售订单", "@salesOrders": {}, + "@saleOrderCreate": {}, "save": "保存", "@save": { "description": "Save" diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 25fbb16..0e6d01d 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -187,6 +187,7 @@ "@parts": { "description": "Part (multiple)" }, + "@saleOrderCreate": {}, "stock": "庫存", "@stock": { "description": "stock" From 8cb5dd20f05a37bd3c3bfbd699552539eff148b6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 14 Nov 2023 07:39:06 +1100 Subject: [PATCH 441/746] Barcode Scanning Updates (#448) * Add new setting for controlling manual barcode scan * Adds ability to pause and resume scanning with button - Camera is still "live" during this * Add UI elements * Change scan setting - "Continuous" scanning - Enabled by default * Update release notes * Scanner updates - Use "hold to pause" in continuous scan - Use "tap to pause" in single scan * Improve barcode scanning options - Allow tap-to-pause or hold-to-pause - More obvious user interactions * Ensure consistent icon placement * Remove separate setting for barcode pause mode --- assets/release_notes.md | 3 + lib/barcode/camera_controller.dart | 141 +++++++++++++++++++++-------- lib/l10n/app_en.arb | 12 +++ lib/preferences.dart | 1 + lib/settings/barcode_settings.dart | 16 ++++ pubspec.yaml | 2 +- 6 files changed, 134 insertions(+), 41 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index dc12be1..544c49d 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,8 +2,11 @@ --- - Adds support for Sales Orders +- Adds option to pause and resume barcode scanning with camera +- Adds option for "single shot" barcode scanning with camera - Fixes bug when removing entire quantity of a stock item + ### 0.13.0 - October 2023 --- diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 94031e8..9947c1a 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,5 +1,8 @@ import "dart:io"; import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/preferences.dart"; import "package:qr_code_scanner/qr_code_scanner.dart"; @@ -13,30 +16,54 @@ import "package:inventree/barcode/controller.dart"; * Under the hood it uses the qr_code_scanner package. */ class CameraBarcodeController extends InvenTreeBarcodeController { - - const CameraBarcodeController(BarcodeHandler handler, {Key? key}) : super(handler, key: key); + const CameraBarcodeController(BarcodeHandler handler, {Key? key}) + : super(handler, key: key); @override State createState() => _CameraBarcodeControllerState(); - } - class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { - _CameraBarcodeControllerState() : super(); QRViewController? _controller; bool flash_status = false; + bool single_scanning = false; + bool scanning_paused = false; + + Future _loadSettings() async { + bool _single = await InvenTreeSettingsManager() + .getBool(INV_BARCODE_SCAN_SINGLE, false); + + if (mounted) { + setState(() { + single_scanning = _single; + scanning_paused = false; + }); + } + } + /* Callback function when the Barcode scanner view is initially created */ void _onViewCreated(BuildContext context, QRViewController controller) { _controller = controller; controller.scannedDataStream.listen((barcode) { - handleBarcodeData(barcode.code); + if (!scanning_paused) { + handleBarcodeData(barcode.code).then((value) => { + // If in single-scanning mode, pause after successful scan + if (single_scanning && mounted) + { + setState(() { + scanning_paused = true; + }) + } + }); + } }); + + _loadSettings(); } // In order to get hot reload to work we need to pause the camera if the platform @@ -71,7 +98,6 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future resumeScan() async { - // Do not attempt to resume if the widget is not mounted if (!mounted) { return; @@ -97,17 +123,25 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Widget build(BuildContext context) { + Widget actionIcon = + FaIcon(FontAwesomeIcons.circlePause, color: COLOR_WARNING, size: 64); + + if (scanning_paused) { + actionIcon = + FaIcon(FontAwesomeIcons.circlePlay, color: COLOR_ACTION, size: 64); + } + + String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; return Scaffold( appBar: AppBar( title: Text(L10().scanBarcode), actions: [ IconButton( - icon: Icon(Icons.flip_camera_android), - onPressed: () { - _controller?.flipCamera(); - } - ), + icon: Icon(Icons.flip_camera_android), + onPressed: () { + _controller?.flipCamera(); + }), IconButton( icon: flash_status ? Icon(Icons.flash_off) : Icon(Icons.flash_on), onPressed: () { @@ -117,44 +151,71 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { ) ], ), - body: Stack( - children: [ - Column( - children: [ - Expanded( - child: QRView( + body: GestureDetector( + onTapDown: (details) async { + setState(() { + scanning_paused = !scanning_paused; + }); + }, + onLongPressEnd: (details) async { + if (mounted) { + setState(() { + scanning_paused = false; + }); + } + }, + child: Stack( + children: [ + Column(children: [ + Expanded( + child: QRView( key: barcodeControllerKey, onQRViewCreated: (QRViewController controller) { _onViewCreated(context, controller); }, overlay: QrScannerOverlayShape( - borderColor: Colors.red, + borderColor: + scanning_paused ? COLOR_WARNING : COLOR_ACTION, borderRadius: 10, borderLength: 30, borderWidth: 10, cutOutSize: 300, ), - ) - ) - ] - ), - Center( - child: Column( - children: [ - Spacer(), - Padding( - child: Text(widget.handler.getOverlayText(context), - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.white), - ), - padding: EdgeInsets.all(20), + )) + ]), + Center( + child: Column(children: [ + Padding( + child: Text( + widget.handler.getOverlayText(context), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, color: Colors.white), ), - ] - ) - ) - ], - ) - ); + padding: EdgeInsets.all(25)), + Padding( + child: CircularProgressIndicator( + value: scanning_paused ? 0 : null), + padding: EdgeInsets.all(40), + ), + Spacer(), + SizedBox( + child: Center( + child: actionIcon, + ), + width: 100, + height: 150, + ), + Padding( + child: Text(info_text, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + )), + padding: EdgeInsets.all(25), + ), + ])) + ], + ))); } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index c47b495..4ca99a6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -115,6 +115,12 @@ "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -139,6 +145,12 @@ "barcodeScanLocation": "Scan stock location", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", "@barcodeScanIntoLocationSuccess": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 581a5fd..19e4ffb 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -42,6 +42,7 @@ const String INV_STRICT_HTTPS = "strictHttps"; // Barcode settings const String INV_BARCODE_SCAN_DELAY = "barcodeScanDelay"; const String INV_BARCODE_SCAN_TYPE = "barcodeScanType"; +const String INV_BARCODE_SCAN_SINGLE = "barcodeScanSingle"; // Barcode scanner types const int BARCODE_CONTROLLER_CAMERA = 0; diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index 44dfb7f..bb202b2 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -18,6 +18,7 @@ class _InvenTreeBarcodeSettingsState extends State loadSettings() async { barcodeScanDelay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; barcodeScanType = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_TYPE, BARCODE_CONTROLLER_CAMERA) as int; + barcodeScanSingle = await InvenTreeSettingsManager().getBool(INV_BARCODE_SCAN_SINGLE, false); if (mounted) { setState(() { @@ -153,6 +155,20 @@ class _InvenTreeBarcodeSettingsState extends State=2.19.5 <3.13.0" From 1148f01d4a7f066b57bd32dcba564b2c5fcfcf86 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 15 Nov 2023 21:00:33 +1100 Subject: [PATCH 442/746] New Crowdin updates (#455) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Hindi) --- lib/l10n/bg_BG/app_bg_BG.arb | 1 + lib/l10n/cs_CZ/app_cs_CZ.arb | 1 + lib/l10n/da_DK/app_da_DK.arb | 1 + lib/l10n/de_DE/app_de_DE.arb | 1 + lib/l10n/el_GR/app_el_GR.arb | 1 + lib/l10n/es_ES/app_es_ES.arb | 1 + lib/l10n/es_MX/app_es_MX.arb | 1 + lib/l10n/fa_IR/app_fa_IR.arb | 1 + lib/l10n/fi_FI/app_fi_FI.arb | 1 + lib/l10n/fr_FR/app_fr_FR.arb | 1 + lib/l10n/he_IL/app_he_IL.arb | 1 + lib/l10n/hi_IN/app_hi_IN.arb | 1 + lib/l10n/hu_HU/app_hu_HU.arb | 1 + lib/l10n/id_ID/app_id_ID.arb | 1 + lib/l10n/it_IT/app_it_IT.arb | 1 + lib/l10n/ja_JP/app_ja_JP.arb | 1 + lib/l10n/ko_KR/app_ko_KR.arb | 1 + lib/l10n/nl_NL/app_nl_NL.arb | 1 + lib/l10n/no_NO/app_no_NO.arb | 1 + lib/l10n/pl_PL/app_pl_PL.arb | 1 + lib/l10n/pt_BR/app_pt_BR.arb | 1 + lib/l10n/pt_PT/app_pt_PT.arb | 1 + lib/l10n/ru_RU/app_ru_RU.arb | 1 + lib/l10n/sl_SI/app_sl_SI.arb | 1 + lib/l10n/sv_SE/app_sv_SE.arb | 1 + lib/l10n/th_TH/app_th_TH.arb | 1 + lib/l10n/tr_TR/app_tr_TR.arb | 1 + lib/l10n/vi_VN/app_vi_VN.arb | 1 + lib/l10n/zh_CN/app_zh_CN.arb | 1 + lib/l10n/zh_TW/app_zh_TW.arb | 1 + 30 files changed, 30 insertions(+) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index f3dcbcd..0087450 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -1,5 +1,6 @@ { "@@locale": "bg", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 7105b3d..2b44549 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -72,6 +72,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Čárový kód nebyl přiřazen", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Naskenuj čárový kód InvenTree", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 17e3377..8c7ae32 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -1,5 +1,6 @@ { "@@locale": "da", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 8c94a37..f192f48 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode nicht zugewiesen", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Scannen um Barcode zuzuweisen", "@barcodeScanAssign": {}, "barcodeScanDelay": "Barcode Scan-Verzögerung", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 1daa12a..a7e442f 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -28,6 +28,7 @@ "@availableStock": {}, "barcodeAssign": "Αντιστοίχιση Barcode", "@barcodeAssign": {}, + "@barodeScanPaused": {}, "categoryCreate": "Νέα Κατηγορία", "@categoryCreate": {}, "@homeShowSubscsribedDescription": {}, diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 6629a16..025a854 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -72,6 +72,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Escanear un código de barras de InvenTree", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 4c24e6b..ad7ad4e 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, "barcodeScanDelay": "Retraso de escaneo de código de barras", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index c3329f5..e62cd93 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,5 +1,6 @@ { "@@locale": "fa", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 046381d..8de61c1 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -60,6 +60,7 @@ "@barcodeError": {}, "barcodeInUse": "Viivakoodi on jo käytössä", "@barcodeInUse": {}, + "@barodeScanPaused": {}, "barcodeUnknown": "Viivakoodia ei tunnistettu", "@barcodeUnknown": {}, "cancel": "Peruuta", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index fab5fb5..ebce2f8 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Code-barres non assigné", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Scanner pour attribuer un code-barres", "@barcodeScanAssign": {}, "barcodeScanDelay": "Délai de Numérisation des Codes-barres", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 2a2c1e0..7882200 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,5 +1,6 @@ { "@@locale": "he", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index bf55292..9d605f6 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -1,5 +1,6 @@ { "@@locale": "hi", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 6f80ad7..00ce57d 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", "@barcodeScanAssign": {}, "barcodeScanDelay": "Vonalkód olvasási késleltetés", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index f135d89..c70fee0 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,5 +1,6 @@ { "@@locale": "id", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "imageUploadSuccess": "Gambar telah diunggah", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 3b15de4..d0176e2 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -72,6 +72,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Codice a barre non assegnato", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Scansiona per assegnare codice a barre", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index a7f096d..14ecb4b 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -68,6 +68,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "バーコードが割り当てられていません", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "スキャンしてバーコードを割り当てます", "@barcodeScanAssign": {}, "barcodeScanGeneral": "InvenTree バーコードをスキャンする", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 54efe61..6264b1f 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -12,6 +12,7 @@ "@appReleaseNotes": {}, "appSettings": "앱 설정", "@appSettings": {}, + "@barodeScanPaused": {}, "billOfMaterials": "부품 명세서", "@billOfMaterials": {}, "cancel": "취소", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 6eb2071..e567bf7 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Streepjescode niet toegewezen", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, "barcodeScanDelay": "Barcode Scan vertraging", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 887d100..6488ce2 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -72,6 +72,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Strekkode ikke tildelt", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Skann for å tildele strekkode", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Skann en InvenTree-strekkode", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 86bc620..0a29762 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -58,6 +58,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Kod kreskowy nieprzypisany", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index f86cfd6..83e075c 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, "barcodeScanDelay": "Atraso na leitura de Código de Barras", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 006f306..39f4646 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -70,6 +70,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 0ac8484..dc29c2b 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Штрих-код не назначен", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Сканировать для присвоения штрих-кода", "@barcodeScanAssign": {}, "barcodeScanDelay": "Задержка сканирования штрих-кода", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index dc5da7f..7a3dfc7 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -1,5 +1,6 @@ { "@@locale": "sl", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 068e6e3..90058eb 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -72,6 +72,7 @@ "@barcodeError": {}, "barcodeInUse": "Streckkoden används redan", "@barcodeInUse": {}, + "@barodeScanPaused": {}, "build": "Bygg", "@build": {}, "cancel": "Avbryt", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index cd61a88..c1727ff 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,5 +1,6 @@ { "@@locale": "th", + "@barodeScanPaused": {}, "@homeShowSubscsribedDescription": {}, "@homeShowSupplierDescription": {}, "@saleOrderCreate": {} diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 7480ce1..53aae3d 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barkod atanmış değil", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, "barcodeScanDelay": "Barkod Tarama Gecikmesi", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index e0b2e17..35d5f3a 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -78,6 +78,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Mã vạch chưa được quét", "@barcodeNotAssigned": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "Quét để gán mã vạch", "@barcodeScanAssign": {}, "barcodeScanDelay": "Độ trễ quét mã vạch", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index d94f977..d70b094 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -80,6 +80,7 @@ "@barcodeNotAssigned": {}, "barcodeReceivePart": "扫描条形码以接收部件", "@barcodeReceivePart": {}, + "@barodeScanPaused": {}, "barcodeScanAssign": "扫描以分配条码", "@barcodeScanAssign": {}, "barcodeScanController": "扫描仪输入", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 0e6d01d..996d478 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -54,6 +54,7 @@ "@available": {}, "barcodes": "條碼", "@barcodes": {}, + "@barodeScanPaused": {}, "billOfMaterials": "材料清單", "@billOfMaterials": {}, "bom": "材料清單", From 0a8544113170b243c4b784ceab986a44b746a9ef Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 15 Nov 2023 23:53:47 +1100 Subject: [PATCH 443/746] Purchase order updates (#456) * Support supplierpart in related field * Manual add line item to purchase order * Update release notes --- assets/release_notes.md | 1 + lib/api_form.dart | 30 ++++++++++++++---- lib/widget/order/purchase_order_detail.dart | 35 +++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 544c49d..5063db6 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,7 @@ - Adds option to pause and resume barcode scanning with camera - Adds option for "single shot" barcode scanning with camera - Fixes bug when removing entire quantity of a stock item +- Add line items to purchase orders directly from the app ### 0.13.0 - October 2023 diff --git a/lib/api_form.dart b/lib/api_form.dart index 237b1d5..043eedb 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -524,11 +524,10 @@ class APIFormField { ), selectedItem: initial_data, asyncItems: (String filter) async { - Map _filters = {}; - - filters.forEach((key, value) { - _filters[key] = value; - }); + Map _filters = { + ..._relatedFieldFilters(), + ...filters, + }; _filters["search"] = filter; _filters["offset"] = "0"; @@ -586,6 +585,17 @@ class APIFormField { }); } + // Construct a set of custom filters for the dropdown search + Map _relatedFieldFilters() { + + switch (model) { + case "supplierpart": + return InvenTreeSupplierPart().defaultListFilters(); + } + + return {}; + } + // Render a "related field" based on the "model" type Widget _renderRelatedField(String fieldName, dynamic item, bool selected, bool extended) { @@ -611,7 +621,6 @@ class APIFormField { switch (model) { case "part": - var part = InvenTreePart.fromJson(data); return ListTile( @@ -626,6 +635,15 @@ class APIFormField { leading: extended ? InvenTreeAPI().getThumbnail(part.thumbnail) : null, ); + case "supplierpart": + var part = InvenTreeSupplierPart.fromJson(data); + + return ListTile( + title: Text(part.SKU), + subtitle: Text(part.partName), + leading: extended ? InvenTreeAPI().getThumbnail(part.partImage) : null, + trailing: extended && part.supplierImage.isNotEmpty ? InvenTreeAPI().getThumbnail(part.supplierImage) : null, + ); case "partcategory": var cat = InvenTreePartCategory.fromJson(data); diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 73fa4eb..13cb7a4 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -74,6 +74,17 @@ class _PurchaseOrderDetailState extends RefreshableState _addLineItem(BuildContext context) async { + + var fields = InvenTreePOLineItem().formFields(); + + // Update part field definition + fields["part"]?["hidden"] = false; + fields["part"]?["filters"] = { + "supplier": widget.order.supplierId + }; + + fields["order"]?["value"] = widget.order.pk; + + InvenTreePOLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().lineItemUpdated, success: true); + } + ); + } + /// Issue this order Future _issueOrder(BuildContext context) async { From bf3df770c7ca9484a73a039eb9a53224977c80aa Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 20 Nov 2023 23:48:42 +1100 Subject: [PATCH 444/746] Po barcode scan (#458) * Refactor existing barcode scan endpoint - Break out into new file just for purchase orders * Handle scanning of salesorder * Add new handler for adding items to PO via barcode * Allocate with barcode * Add new string --- lib/api.dart | 4 + lib/barcode/barcode.dart | 128 ++---------- lib/barcode/handler.dart | 2 +- lib/barcode/purchase_order.dart | 203 ++++++++++++++++++++ lib/l10n/app_en.arb | 3 + lib/widget/order/purchase_order_detail.dart | 22 ++- lib/widget/order/purchase_order_list.dart | 1 + lib/widget/stock/location_display.dart | 1 + 8 files changed, 250 insertions(+), 114 deletions(-) create mode 100644 lib/barcode/purchase_order.dart diff --git a/lib/api.dart b/lib/api.dart index 28f85f3..00833f0 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -330,8 +330,12 @@ class InvenTreeAPI { // Does the server support extra fields on stock adjustment actions? bool get supportsStockAdjustExtraFields => isConnected() && apiVersion >= 133; + // Does the server support receiving items against a PO using barcodes? bool get supportsBarcodePOReceiveEndpoint => isConnected() && apiVersion >= 139; + // Does the server support adding line items to a PO using barcodes? + bool get supportsBarcodePOAddLineEndpoint => isConnected() && apiVersion >= 153; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 4ea044e..91e600c 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -2,12 +2,13 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/order/sales_order_detail.dart"; import "package:one_context/one_context.dart"; import "package:inventree/api.dart"; -import "package:inventree/api_form.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -166,6 +167,16 @@ class BarcodeScanHandler extends BarcodeHandler { } } + // Response when a SalesOrder instance is scanned + Future handleSalesOrder(int pk) async { + var order = await InvenTreeSalesOrder().get(pk); + + if (order is InvenTreeSalesOrder) { + OneContext().pop(); + OneContext().push(MaterialPageRoute( + builder: (context) => SalesOrderDetailWidget(order))); + } + } @override Future onBarcodeMatched(Map data) async { @@ -184,6 +195,7 @@ class BarcodeScanHandler extends BarcodeHandler { if (InvenTreeAPI().supportsOrderBarcodes) { validModels.add("purchaseorder"); + validModels.add("salesorder"); } for (var key in validModels) { @@ -219,6 +231,10 @@ class BarcodeScanHandler extends BarcodeHandler { case "purchaseorder": await handlePurchaseOrder(pk); return; + case "salesorder": + await handleSalesOrder(pk); + return; + // TODO: Handle manufacturer part default: // Fall through to failure state break; @@ -478,116 +494,6 @@ class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { } -/* - * Barcode handler class for scanning a supplier barcode to receive a part - * - * - The class can be initialized by optionally passing a valid, placed PurchaseOrder object - * - Expects to scan supplier barcode, possibly containing order_number and quantity - * - If location or quantity information wasn't provided, show a form to fill it in - */ -class POReceiveBarcodeHandler extends BarcodeHandler { - - POReceiveBarcodeHandler({this.purchaseOrder, this.location}); - - InvenTreePurchaseOrder? purchaseOrder; - InvenTreeStockLocation? location; - - @override - String getOverlayText(BuildContext context) => L10().barcodeReceivePart; - - @override - Future processBarcode(String barcode, - {String url = "barcode/po-receive/", - Map extra_data = const {}}) { - - final po_extra_data = { - "purchase_order": purchaseOrder?.pk, - "location": location?.pk, - ...extra_data, - }; - - return super.processBarcode(barcode, url: url, extra_data: po_extra_data); - } - - @override - Future onBarcodeMatched(Map data) async { - if (!data.containsKey("lineitem")) { - return onBarcodeUnknown(data); - } - - barcodeSuccessTone(); - showSnackIcon(L10().receivedItem, success: true); - } - - @override - Future onBarcodeUnhandled(Map data) async { - if (!data.containsKey("action_required") || !data.containsKey("lineitem")) { - return super.onBarcodeUnhandled(data); - } - - final lineItemData = data["lineitem"] as Map; - if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { - barcodeFailureTone(); - showSnackIcon(L10().missingData, success: false); - } - - // Construct fields to receive - Map fields = { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - "value": lineItemData["pk"] as int, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": lineItemData["quantity"] as double?, - }, - "status": { - "parent": "items", - "nested": true, - }, - "location": { - "value": lineItemData["location"] as int?, - }, - "barcode": { - "parent": "items", - "nested": true, - "hidden": true, - "type": "barcode", - "value": data["barcode_data"] as String, - } - }; - - final context = OneContext().context!; - final purchase_order_pk = lineItemData["purchase_order"]; - final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; - - launchApiForm( - context, - L10().receiveItem, - receive_url, - fields, - method: "POST", - icon: FontAwesomeIcons.rightToBracket, - onSuccess: (data) async { - showSnackIcon(L10().receivedItem, success: true); - } - ); - } - - @override - Future onBarcodeUnknown(Map data) async { - barcodeFailureTone(); - showSnackIcon( - data["error"] as String? ?? L10().barcodeError, - success: false - ); - } -} - - /* * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) */ diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index 5048f63..3dae484 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -41,7 +41,7 @@ class BarcodeHandler { barcodeFailureTone(); showSnackIcon( - L10().barcodeNoMatch, + (data["error"] ?? L10().barcodeNoMatch) as String, success: false, icon: Icons.qr_code, ); diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart new file mode 100644 index 0000000..3069da2 --- /dev/null +++ b/lib/barcode/purchase_order.dart @@ -0,0 +1,203 @@ +import "package:flutter/material.dart"; + +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:one_context/one_context.dart"; + +import "package:inventree/l10.dart"; +import "package:inventree/api_form.dart"; + +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/tones.dart"; + +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/stock.dart"; + +import "package:inventree/widget/snacks.dart"; + +/* + * Barcode handler class for scanning a supplier barcode to receive a part + * + * - The class can be initialized by optionally passing a valid, placed PurchaseOrder object + * - Expects to scan supplier barcode, possibly containing order_number and quantity + * - If location or quantity information wasn't provided, show a form to fill it in + */ +class POReceiveBarcodeHandler extends BarcodeHandler { + + POReceiveBarcodeHandler({this.purchaseOrder, this.location}); + + InvenTreePurchaseOrder? purchaseOrder; + InvenTreeStockLocation? location; + + @override + String getOverlayText(BuildContext context) => L10().barcodeReceivePart; + + @override + Future processBarcode(String barcode, + {String url = "barcode/po-receive/", + Map extra_data = const {}}) { + + final po_extra_data = { + "purchase_order": purchaseOrder?.pk, + "location": location?.pk, + ...extra_data, + }; + + return super.processBarcode(barcode, url: url, extra_data: po_extra_data); + } + + @override + Future onBarcodeMatched(Map data) async { + if (!data.containsKey("lineitem")) { + return onBarcodeUnknown(data); + } + + barcodeSuccessTone(); + showSnackIcon(L10().receivedItem, success: true); + } + + @override + Future onBarcodeUnhandled(Map data) async { + if (!data.containsKey("action_required") || !data.containsKey("lineitem")) { + return super.onBarcodeUnhandled(data); + } + + final lineItemData = data["lineitem"] as Map; + if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { + barcodeFailureTone(); + showSnackIcon(L10().missingData, success: false); + } + + // Construct fields to receive + Map fields = { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + "value": lineItemData["pk"] as int, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": lineItemData["quantity"] as double?, + }, + "status": { + "parent": "items", + "nested": true, + }, + "location": { + "value": lineItemData["location"] as int?, + }, + "barcode": { + "parent": "items", + "nested": true, + "hidden": true, + "type": "barcode", + "value": data["barcode_data"] as String, + } + }; + + final context = OneContext().context!; + final purchase_order_pk = lineItemData["purchase_order"]; + final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; + + launchApiForm( + context, + L10().receiveItem, + receive_url, + fields, + method: "POST", + icon: FontAwesomeIcons.rightToBracket, + onSuccess: (data) async { + showSnackIcon(L10().receivedItem, success: true); + } + ); + } + + @override + Future onBarcodeUnknown(Map data) async { + barcodeFailureTone(); + showSnackIcon( + data["error"] as String? ?? L10().barcodeError, + success: false + ); + } +} + + +/* + * Barcode handler to add a line item to a purchase order + */ +class POAllocateBarcodeHandler extends BarcodeHandler { + + POAllocateBarcodeHandler({this.purchaseOrder}); + + InvenTreePurchaseOrder? purchaseOrder; + + @override + String getOverlayText(BuildContext context) => L10().scanSupplierPart; + + @override + Future processBarcode(String barcode, { + String url = "barcode/po-allocate/", + Map extra_data = const {}} + ) { + + final po_extra_data = { + "purchase_order": purchaseOrder?.pk, + ...extra_data, + }; + + return super.processBarcode( + barcode, + url: url, + extra_data: po_extra_data, + ); + } + + @override + Future onBarcodeMatched(Map data) async { + // Server must respond with a suppliertpart instance + if (!data.containsKey("supplierpart")) { + return onBarcodeUnknown(data); + } + + dynamic supplier_part = data["supplierpart"]; + + int supplier_part_pk = -1; + + if (supplier_part is Map) { + supplier_part_pk = (supplier_part["pk"] ?? -1) as int; + } else { + return onBarcodeUnknown(data); + } + + // Dispose of the barcode scanner + if (OneContext.hasContext) { + OneContext().pop(); + } + + final context = OneContext().context!; + + var fields = InvenTreePOLineItem().formFields(); + + fields["order"]?["value"] = purchaseOrder!.pk; + fields["part"]?["hidden"] = false; + fields["part"]?["value"] = supplier_part_pk; + + InvenTreePOLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (data) async {}, + ); + } + + @override + Future onBarcodeUnhandled(Map data) async { + + print("onBarcodeUnhandled:"); + print(data.toString()); + + super.onBarcodeUnhandled(data); + } +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 4ca99a6..e26cfab 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1057,6 +1057,9 @@ "@scanBarcode": { }, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", "@scanIntoLocation": {}, diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 13cb7a4..ae7606a 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -6,6 +6,7 @@ import "package:inventree/widget/order/po_line_list.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/purchase_order.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -173,7 +174,7 @@ class _PurchaseOrderDetailState extends RefreshableState barcodeButtons(BuildContext context) { List actions = []; - if (api.supportsBarcodePOReceiveEndpoint) { + if (api.supportsBarcodePOReceiveEndpoint && widget.order.isPlaced) { actions.add( SpeedDialChild( child: Icon(Icons.barcode_reader), @@ -182,12 +183,29 @@ class _PurchaseOrderDetailState extends RefreshableState Date: Tue, 21 Nov 2023 00:13:40 +1100 Subject: [PATCH 445/746] Update app release notes (#459) --- assets/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 5063db6..52563ac 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Adds option for "single shot" barcode scanning with camera - Fixes bug when removing entire quantity of a stock item - Add line items to purchase orders directly from the app +- Add line items to purchase order using barcode scanner ### 0.13.0 - October 2023 From eb1be30df4f003ecb89c9b7658659b0397662e5e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 21 Nov 2023 08:23:09 +1100 Subject: [PATCH 446/746] Fix display of sales order completion status (#460) --- lib/inventree/orders.dart | 4 ++++ lib/widget/order/sales_order_detail.dart | 15 +++------------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart index 0595b2d..25b97d7 100644 --- a/lib/inventree/orders.dart +++ b/lib/inventree/orders.dart @@ -26,6 +26,10 @@ class InvenTreeOrder extends InvenTreeModel { int get lineItemCount => getInt("line_items", backup: 0); + int get completedLineItemCount => getInt("completed_lines", backup: 0); + + bool get complete => completedLineItemCount >= lineItemCount; + bool get overdue => getBool("overdue"); String get reference => getString("reference"); diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 73422da..d64070f 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -37,7 +37,6 @@ class _SalesOrderDetailState extends RefreshableState { List lines = []; bool supportsProjectCodes = false; - int completedLines = 0; int attachmentCount = 0; @override @@ -114,14 +113,6 @@ class _SalesOrderDetailState extends RefreshableState { supportsProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED"); - completedLines = 0; - - for (var line in lines) { - if (line.isComplete) { - completedLines += 1; - } - } - InvenTreeSalesOrderAttachment().count(filters: { "order": widget.order.pk.toString() }).then((int value) { @@ -219,16 +210,16 @@ class _SalesOrderDetailState extends RefreshableState { )); } - Color lineColor = completedLines < widget.order.lineItemCount ? COLOR_WARNING : COLOR_SUCCESS; + Color lineColor = widget.order.complete ? COLOR_WARNING : COLOR_SUCCESS; tiles.add(ListTile( title: Text(L10().lineItems), subtitle: ProgressBar( - completedLines.toDouble(), + widget.order.completedLineItemCount.toDouble(), maximum: widget.order.lineItemCount.toDouble() ), leading: FaIcon(FontAwesomeIcons.clipboardCheck), - trailing: Text("${completedLines} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), + trailing: Text("${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), )); // TODO: total price From 1ec1a867d93458ddb5be83bdb731defd23dfe6c8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 22 Nov 2023 00:14:55 +1100 Subject: [PATCH 447/746] Add part to sales order via barcode scan (#461) * Add part to sales order via barcode scan * Update release notes * Remove unused imports --- assets/release_notes.md | 2 + lib/barcode/purchase_order.dart | 1 - lib/barcode/sales_order.dart | 81 ++++++++++++++++++++++++ lib/inventree/sales_order.dart | 6 +- lib/l10n/app_en.arb | 6 ++ lib/widget/order/sales_order_detail.dart | 17 ++++- 6 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 lib/barcode/sales_order.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 52563ac..58fb5f1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -7,6 +7,8 @@ - Fixes bug when removing entire quantity of a stock item - Add line items to purchase orders directly from the app - Add line items to purchase order using barcode scanner +- Add line items to sales orders directly from the app +- Add line items to sales order using barcode scanner ### 0.13.0 - October 2023 diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart index 3069da2..8fe67b8 100644 --- a/lib/barcode/purchase_order.dart +++ b/lib/barcode/purchase_order.dart @@ -188,7 +188,6 @@ class POAllocateBarcodeHandler extends BarcodeHandler { context, L10().lineItemAdd, fields: fields, - onSuccess: (data) async {}, ); } diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart new file mode 100644 index 0000000..d485f8f --- /dev/null +++ b/lib/barcode/sales_order.dart @@ -0,0 +1,81 @@ +import "package:flutter/material.dart"; + +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:one_context/one_context.dart"; + +import "package:inventree/l10.dart"; + +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/tones.dart"; + +import "package:inventree/widget/snacks.dart"; + + +/* + * Barcode handler class for scanning a new part into a SalesOrder + */ + +class SOAddItemBarcodeHandler extends BarcodeHandler { + + SOAddItemBarcodeHandler({this.salesOrder}); + + InvenTreeSalesOrder? salesOrder; + + @override + String getOverlayText(BuildContext context) => L10().barcodeScanPart; + + @override + Future onBarcodeMatched(Map data) async { + + // Extract the part ID from the returned data + int part_id = -1; + + if (data.containsKey("part")) { + part_id = (data["part"] ?? {} as Map)["pk"] as int; + } + + if (part_id <= 0) { + return onBarcodeUnknown(data); + } + + // Request the part from the server + var part = await InvenTreePart().get(part_id); + + if (part is InvenTreePart) { + + if (part.isSalable) { + // Dispose of the barcode scanner + if (OneContext.hasContext) { + OneContext().pop(); + } + + final context = OneContext().context!; + + var fields = InvenTreeSOLineItem().formFields(); + + fields["order"]?["value"] = salesOrder!.pk; + fields["order"]?["hidden"] = true; + + fields["part"]?["value"] = part.pk; + fields["part"]?["hidden"] = false; + + InvenTreeSOLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + ); + + } else { + barcodeFailureTone(); + showSnackIcon(L10().partNotSalable, success: false); + } + + } else { + // Failed to fetch part + return onBarcodeUnknown(data); + } + + } + +} \ No newline at end of file diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 1225cb8..4cbc1ab 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -118,7 +118,11 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { "order": { "hidden": true, }, - "part": {}, + "part": { + "filters": { + "salable": true, + } + }, "quantity": {}, "reference": {}, "notes": {}, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e26cfab..b8afdd5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -112,6 +112,9 @@ "barcodeNotAssigned": "Barcode not assigned", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, @@ -766,6 +769,9 @@ "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", "@partsNone": {}, diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index d64070f..2a489ac 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -2,6 +2,8 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/order/so_line_list.dart"; @@ -101,7 +103,20 @@ class _SalesOrderDetailState extends RefreshableState { List barcodeButtons(BuildContext context) { List actions = []; - // TODO + if (widget.order.isOpen && InvenTreeSOLineItem().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().lineItemAdd, + onTap: () async { + scanBarcode( + context, + handler: SOAddItemBarcodeHandler(salesOrder: widget.order), + ); + } + ) + ); + } return actions; } From 70d0d4de9332387d5af37d3780c4144b65a8ff23 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Nov 2023 22:09:39 +1100 Subject: [PATCH 448/746] Change rendering of part parameter (#463) Closes https://github.com/inventree/inventree-app/issues/358 --- lib/widget/part/part_parameter_widget.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/widget/part/part_parameter_widget.dart b/lib/widget/part/part_parameter_widget.dart index d2f19d5..ea7e7df 100644 --- a/lib/widget/part/part_parameter_widget.dart +++ b/lib/widget/part/part_parameter_widget.dart @@ -113,8 +113,14 @@ class _PaginatedParameterState extends PaginatedSearchState Date: Mon, 27 Nov 2023 22:51:20 +1100 Subject: [PATCH 449/746] Sales order allocation (#464) * New string * Typo fix * Add model for SalesOrderShipment * Add placeholder button to sales order item * Create a new shipment from the sales order detail view * Fix API URL * Add paginated shipment list * Upate colors * Add API form for allocation of stock to sales order * Build out sales order line detail widge * Use unallocated quantity * Update release notes * linting fix --- assets/release_notes.md | 2 +- lib/api_form.dart | 21 +++++ lib/inventree/sales_order.dart | 67 +++++++++++++- lib/l10n/app_en.arb | 12 +++ lib/widget/order/sales_order_detail.dart | 37 +++++++- lib/widget/order/so_line_detail.dart | 110 +++++++++++++++++++++-- lib/widget/order/so_line_list.dart | 2 +- lib/widget/order/so_shipment_list.dart | 55 ++++++++++++ 8 files changed, 293 insertions(+), 13 deletions(-) create mode 100644 lib/widget/order/so_shipment_list.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 58fb5f1..5c767a7 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -9,7 +9,7 @@ - Add line items to purchase order using barcode scanner - Add line items to sales orders directly from the app - Add line items to sales order using barcode scanner - +- Allocate stock items against existing sales orders ### 0.13.0 - October 2023 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index 043eedb..97b685b 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -12,6 +12,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/tones.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; @@ -591,6 +592,8 @@ class APIFormField { switch (model) { case "supplierpart": return InvenTreeSupplierPart().defaultListFilters(); + case "stockitem": + return InvenTreeStockItem().defaultListFilters(); } return {}; @@ -658,6 +661,16 @@ class APIFormField { style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), ) : null, ); + case "stockitem": + var item = InvenTreeStockItem.fromJson(data); + + return ListTile( + title: Text( + item.partName, + ), + leading: InvenTreeAPI().getThumbnail(item.partThumbnail), + trailing: Text(item.quantityString()), + ); case "stocklocation": var loc = InvenTreeStockLocation.fromJson(data); @@ -672,6 +685,14 @@ class APIFormField { style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), ) : null, ); + case "salesordershipment": + var shipment = InvenTreeSalesOrderShipment.fromJson(data); + + return ListTile( + title: Text(shipment.reference), + subtitle: Text(shipment.tracking_number), + trailing: shipment.shipped ? Text(shipment.shipment_date!) : null, + ); case "owner": String name = (data["name"] ?? "") as String; bool isGroup = (data["label"] ?? "") == "group"; diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 4cbc1ab..709ddce 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -26,6 +26,8 @@ class InvenTreeSalesOrder extends InvenTreeOrder { @override List get rolesRequired => ["sales_order"]; + String get allocate_url => "${url}allocate/"; + @override Map> formFields() { Map> fields = { @@ -148,10 +150,32 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { bool get isAllocated => allocated >= quantity; + double get allocatedRatio { + if (quantity <= 0 || allocated <= 0) { + return 0; + } + + return allocated / quantity; + } + + double get unallocatedQuantity { + double unallocated = quantity - allocated; + + if (unallocated < 0) { + unallocated = 0; + } + + return unallocated; + } + + String get allocatedString => simpleNumberString(allocated) + " / " + simpleNumberString(quantity); + double get shipped => getDouble("shipped"); double get outstanding => quantity - shipped; + double get availableStock => getDouble("available_stock"); + double get progressRatio { if (quantity <= 0 || shipped <= 0) { return 0; @@ -173,6 +197,47 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { } +/* + * Class representing a sales order shipment + */ +class InvenTreeSalesOrderShipment extends InvenTreeModel { + + InvenTreeSalesOrderShipment() : super(); + + InvenTreeSalesOrderShipment.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrderShipment.fromJson(json); + + @override + String get URL => "/order/so/shipment/"; + + @override + Map> formFields() { + Map> fields = { + "order": {}, + "reference": {}, + "tracking_number": {}, + "invoice_number": {}, + "link": {}, + }; + + return fields; + } + + String get reference => getString("reference"); + + String get tracking_number => getString("tracking_number"); + + String get invoice_number => getString("invoice_number"); + + String? get shipment_date => getString("shipment_date"); + + bool get shipped => shipment_date != null && shipment_date!.isNotEmpty; +} + + + /* * Class representing an attachment file against a SalesOrder object */ @@ -189,6 +254,6 @@ class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "order"; @override - String get URL => "order/po/attachment/"; + String get URL => "order/so/attachment/"; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b8afdd5..231a79e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -47,6 +47,12 @@ "appDetails": "App Details", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, @@ -1182,6 +1188,12 @@ "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", "@shipped": {}, diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 2a489ac..0f09961 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -7,6 +7,7 @@ import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/order/so_line_list.dart"; +import "package:inventree/widget/order/so_shipment_list.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; @@ -62,6 +63,25 @@ class _SalesOrderDetailState extends RefreshableState { return actions; } + // Add a new shipment against this sales order + Future _addShipment(BuildContext context) async { + + var fields = InvenTreeSalesOrderShipment().formFields(); + + fields["order"]?["value"] = widget.order.pk; + fields["order"]?["hidden"] = true; + + InvenTreeSalesOrderShipment().createForm( + context, + L10().shipmentAdd, + fields: fields, + onSuccess: (result) async { + refresh(context); + } + ); + + } + // Add a new line item to this sales order Future _addLineItem(BuildContext context) async { var fields = InvenTreeSOLineItem().formFields(); @@ -94,6 +114,16 @@ class _SalesOrderDetailState extends RefreshableState { } ) ); + + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circlePlus), + label: L10().shipmentAdd, + onTap: () async { + _addShipment(context); + } + ) + ); } return actions; @@ -225,7 +255,7 @@ class _SalesOrderDetailState extends RefreshableState { )); } - Color lineColor = widget.order.complete ? COLOR_WARNING : COLOR_SUCCESS; + Color lineColor = widget.order.complete ? COLOR_SUCCESS : COLOR_WARNING; tiles.add(ListTile( title: Text(L10().lineItems), @@ -292,8 +322,7 @@ class _SalesOrderDetailState extends RefreshableState { return [ Tab(text: L10().details), Tab(text: L10().lineItems), - // TODO: Add in the "shipped items" tab - // Tab(text: L10().shipped) + Tab(text: L10().shipments), ]; } @@ -302,7 +331,7 @@ class _SalesOrderDetailState extends RefreshableState { return [ ListView(children: orderTiles(context)), PaginatedSOLineList({"order": widget.order.pk.toString()}), - // Center(), // TODO: Delivered stock + PaginatedSOShipmentList({"order": widget.order.pk.toString()}), ]; } diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index e0ddd89..b5d88e7 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -3,21 +3,24 @@ /* * Widget for displaying detail view of a single SalesOrderLineItem */ + import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/app_colors.dart"; -import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/sales_order.dart"; + import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/part/part_detail.dart"; - -import "package:inventree/helpers.dart"; import "package:inventree/widget/snacks.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/api_form.dart"; + class SoLineDetailWidget extends StatefulWidget { @@ -35,6 +38,8 @@ class _SOLineDetailWidgetState extends RefreshableState { _SOLineDetailWidgetState(); + InvenTreeSalesOrder? order; + @override String getAppBarTitle() => L10().lineItem; @@ -55,6 +60,53 @@ class _SOLineDetailWidgetState extends RefreshableState { return actions; } + Future _allocateStock(BuildContext context) async { + + if (order == null) { + return; + } + + Map fields = { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + "value": widget.item.pk, + }, + "stock_item": { + "parent": "items", + "nested": true, + "filters": { + "part": widget.item.partId, + "in_stock": true, + } + }, + "quantity": { + "parent": "items", + "nested": true, + "value": widget.item.unallocatedQuantity, + }, + "shipment": { + "filters": { + "order": order!.pk.toString(), + } + }, + }; + + launchApiForm( + context, + L10().allocateStock, + order!.allocate_url, + fields, + method: "POST", + icon: FontAwesomeIcons.rightToBracket, + onSuccess: (data) async { + refresh(context); + } + ); + + } + Future _editLineItem(BuildContext context) async { var fields = widget.item.formFields(); @@ -76,13 +128,35 @@ class _SOLineDetailWidgetState extends RefreshableState { @override List actionButtons(BuildContext context) { - // TODO - return []; + + List buttons = []; + + if (order != null && order!.isOpen) { + buttons.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.rightToBracket, color: Colors.blue), + label: L10().allocateStock, + onTap: () async { + _allocateStock(context); + } + ) + ); + } + + return buttons; } @override Future request(BuildContext context) async { await widget.item.reload(); + + final so = await InvenTreeSalesOrder().get(widget.item.orderId); + + if (mounted) { + setState(() { + order = (so is InvenTreeSalesOrder ? so : null); + }); + } } @override @@ -108,6 +182,30 @@ class _SOLineDetailWidgetState extends RefreshableState { ) ); + // Available quantity + tiles.add( + ListTile( + title: Text(L10().availableStock), + leading: FaIcon(FontAwesomeIcons.boxesStacked), + trailing: Text(simpleNumberString(widget.item.availableStock)) + ) + ); + + // Allocated quantity + tiles.add( + ListTile( + leading: FaIcon(FontAwesomeIcons.clipboardCheck), + title: Text(L10().allocated), + subtitle: ProgressBar(widget.item.allocatedRatio), + trailing: Text( + widget.item.allocatedString, + style: TextStyle( + color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING + ) + ) + ) + ); + // Shipped quantity tiles.add( ListTile( diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart index 6d7e1ac..11ba227 100644 --- a/lib/widget/order/so_line_list.dart +++ b/lib/widget/order/so_line_list.dart @@ -63,7 +63,7 @@ class _PaginatedSOLineListState extends PaginatedSearchState filters) : super(filters: filters); + + @override + String get searchTitle => L10().shipments; + + @override + _PaginatedSOShipmentListState createState() => _PaginatedSOShipmentListState(); +} + + +class _PaginatedSOShipmentListState extends PaginatedSearchState { + + _PaginatedSOShipmentListState() : super(); + + @override + String get prefix => "so_shipment_"; + + @override + Map get orderingOptions => {}; + + @override + Map> get filterOptions => {}; + + @override + Future requestPage(int limit, int offset, Map params) async { + final page = await InvenTreeSalesOrderShipment().listPaginated(limit, offset, filters: params); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + + InvenTreeSalesOrderShipment shipment = model as InvenTreeSalesOrderShipment; + + return ListTile( + title: Text(shipment.reference), + subtitle: Text(shipment.tracking_number), + leading: shipment.shipped ? FaIcon(FontAwesomeIcons.calendarCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.calendarXmark, color: COLOR_WARNING), + trailing: shipment.shipped ? Text(shipment.shipment_date ?? "") : null + ); + + } +} \ No newline at end of file From edde9a95857e1ab77c80d7ffe0a6b06afe074813 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 12 Dec 2023 10:47:39 +1100 Subject: [PATCH 450/746] Update credits.md (#465) --- assets/credits.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/credits.md b/assets/credits.md index 401c357..abffb6d 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -6,6 +6,7 @@ Thanks to the following contributors, for their work building this app! - [Guusggg](https://github.com/Guusggg) - [GoryMoon](https://github.com/GoryMoon) - [simonkuehling](https://github.com/simonkuehling) +- [Bobbe](https://github.com/30350n) -------- From 571b49184684c34df3c51ff7b4deb024c7eaf89b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 13 Dec 2023 23:49:55 +1100 Subject: [PATCH 451/746] Sales order barcode (#466) * Add barcode handler for allocating stock to sales order * Refactor sales order allocation fields * Improve barcode handling * Handle barcode scan from sales order line detail view * Remove debug statements --- lib/api.dart | 3 + lib/barcode/sales_order.dart | 95 ++++++++++++++++++++++++ lib/inventree/sales_order.dart | 23 ++++++ lib/widget/order/sales_order_detail.dart | 17 +++++ lib/widget/order/so_line_detail.dart | 66 +++++++++------- 5 files changed, 179 insertions(+), 25 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 00833f0..e2e1f1d 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -336,6 +336,9 @@ class InvenTreeAPI { // Does the server support adding line items to a PO using barcodes? bool get supportsBarcodePOAddLineEndpoint => isConnected() && apiVersion >= 153; + // Does the server support allocating stock to sales order using barcodes? + bool get supportsBarcodeSOAllocateEndpoint => isConnected() && apiVersion >= 160; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart index d485f8f..69583d9 100644 --- a/lib/barcode/sales_order.dart +++ b/lib/barcode/sales_order.dart @@ -1,4 +1,6 @@ import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api_form.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/sales_order.dart"; @@ -77,5 +79,98 @@ class SOAddItemBarcodeHandler extends BarcodeHandler { } } +} + +class SOAllocateStockHandler extends BarcodeHandler { + + SOAllocateStockHandler({this.salesOrder, this.lineItem, this.shipment}); + + InvenTreeSalesOrder? salesOrder; + InvenTreeSOLineItem? lineItem; + InvenTreeSalesOrderShipment? shipment; + + @override + String getOverlayText(BuildContext context) => L10().allocateStock; + + @override + Future processBarcode(String barcode, + { + String url = "barcode/so-allocate/", + Map extra_data = const {}}) { + + final so_extra_data = { + "sales_order": salesOrder?.pk, + "shipment": shipment?.pk, + "line": lineItem?.pk, + ...extra_data + }; + + return super.processBarcode(barcode, url: url, extra_data: so_extra_data); + } + + @override + Future onBarcodeMatched(Map data) async { + if (!data.containsKey("line_item")) { + return onBarcodeUnknown(data); + } + + barcodeSuccessTone(); + showSnackIcon(L10().allocated, success: true); + } + + @override + Future onBarcodeUnhandled(Map data) async { + + if (!data.containsKey("action_required") || !data.containsKey("line_item")) { + return super.onBarcodeUnhandled(data); + } + + // Prompt user for extra information to create the allocation + var fields = InvenTreeSOLineItem().allocateFormFields(); + + // Update fields with data gathered from the API response + fields["line_item"]?["value"] = data["line_item"]; + + Map stock_filters = { + "in_stock": true, + "available": true, + }; + + if (data.containsKey("part")) { + stock_filters["part"] = data["part"]; + } + + fields["stock_item"]?["filters"] = stock_filters; + fields["stock_item"]?["value"] = data["stock_item"]; + + fields["quantity"]?["value"] = data["quantity"]; + + fields["shipment"]?["value"] = data["shipment"]; + fields["shipment"]?["filters"] = { + "order": salesOrder!.pk.toString() + }; + + final context = OneContext().context!; + + launchApiForm( + context, + L10().allocateStock, + salesOrder!.allocate_url, + fields, + method: "POST", + icon: FontAwesomeIcons.rightToBracket, + onSuccess: (data) async { + showSnackIcon(L10().allocated, success: true); + }); + } + + @override + Future onBarcodeUnknown(Map data) async { + barcodeFailureTone(); + showSnackIcon( + data["error"] as String? ?? L10().barcodeError, + success: false + ); + } } \ No newline at end of file diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 709ddce..b65ad61 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -132,6 +132,29 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { }; } + Map> allocateFormFields() { + + return { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + }, + "stock_item": { + "parent": "items", + "nested": true, + "filters": {}, + }, + "quantity": { + "parent": "items", + "nested": true, + }, + "shipment": { + "filters": {} + } + }; + } + @override Map defaultGetFilters() { return { diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 0f09961..bca7e51 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -146,6 +146,23 @@ class _SalesOrderDetailState extends RefreshableState { } ) ); + + if (api.supportsBarcodeSOAllocateEndpoint) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.rightToBracket), + label: L10().allocateStock, + onTap: () async { + scanBarcode( + context, + handler: SOAllocateStockHandler( + salesOrder: widget.order, + ) + ); + } + ) + ); + } } return actions; diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index b5d88e7..a416898 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -7,6 +7,8 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/sales_order.dart"; @@ -66,31 +68,17 @@ class _SOLineDetailWidgetState extends RefreshableState { return; } - Map fields = { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - "value": widget.item.pk, - }, - "stock_item": { - "parent": "items", - "nested": true, - "filters": { - "part": widget.item.partId, - "in_stock": true, - } - }, - "quantity": { - "parent": "items", - "nested": true, - "value": widget.item.unallocatedQuantity, - }, - "shipment": { - "filters": { - "order": order!.pk.toString(), - } - }, + var fields = InvenTreeSOLineItem().allocateFormFields(); + + fields["line_item"]?["value"] = widget.item.pk.toString(); + fields["stock_item"]?["filters"] = { + "in_stock": true, + "available": true, + "part": widget.item.partId.toString() + }; + fields["quantity"]?["value"] = widget.item.unallocatedQuantity.toString(); + fields["shipment"]?["filters"] = { + "order": order!.pk.toString() }; launchApiForm( @@ -146,6 +134,34 @@ class _SOLineDetailWidgetState extends RefreshableState { return buttons; } + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (order != null && order!.isOpen && InvenTreeSOLineItem().canCreate) { + + if (api.supportsBarcodeSOAllocateEndpoint) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.rightToBracket), + label: L10().allocateStock, + onTap: () async { + scanBarcode( + context, + handler: SOAllocateStockHandler( + salesOrder: order, + lineItem: widget.item + ) + ); + } + ) + ); + } + } + + return actions; + } + @override Future request(BuildContext context) async { await widget.item.reload(); From 4ef2e43bf3c7fbfbb69ba1dd6925d99ecb812208 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 14 Dec 2023 00:14:29 +1100 Subject: [PATCH 452/746] Update version info (#467) --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 5c767a7..c220bd0 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,4 +1,4 @@ -### 0.14.0 - November 2023 +### 0.14.0 - December 2023 --- - Adds support for Sales Orders diff --git a/pubspec.yaml b/pubspec.yaml index db7cc6c..67f7ceb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.14.0+77 +version: 0.14.0+78 environment: sdk: ">=2.19.5 <3.13.0" From d152475de4bd8936c8af73b8a59a9db3338f22cd Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Jan 2024 23:24:40 +1100 Subject: [PATCH 453/746] Catch errors (#469) * Catch error comparing dropdown items * Update version number and release notes * Data conversion * Catch error when loading image from network * Suppress error reporting for statusCode -1 --- assets/release_notes.md | 5 +++++ lib/api.dart | 15 ++++++++++----- lib/api_form.dart | 17 +++++++++++++++-- lib/inventree/model.dart | 20 +++++++++++--------- pubspec.lock | 36 ++++++++++-------------------------- pubspec.yaml | 4 ++-- 6 files changed, 53 insertions(+), 44 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index c220bd0..e5eb9c1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.14.1 - January 2024 +--- + +- Squashing bugs + ### 0.14.0 - December 2023 --- diff --git a/lib/api.dart b/lib/api.dart index e2e1f1d..841962b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1452,11 +1452,16 @@ class InvenTreeAPI { } } - return getImage( - imageUrl, - width: size, - height: size - ); + try { + return getImage( + imageUrl, + width: size, + height: size + ); + } catch (error, stackTrace) { + sentryReportError("_getThumbnail", error, stackTrace); + return null; + } } /* diff --git a/lib/api_form.dart b/lib/api_form.dart index 97b685b..31e5d3e 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -582,7 +582,16 @@ class APIFormField { return false; } - return item["pk"].toString() == selectedItem["pk"].toString(); + bool result = false; + + try { + result = item["pk"].toString() == selectedItem["pk"].toString(); + } catch (error) { + // Catch any conversion errors + result = false; + } + + return result; }); } @@ -606,7 +615,11 @@ class APIFormField { Map data = {}; try { - data = Map.from((item ?? {}) as Map); + if (item is Map) { + data = Map.from(item); + } else { + data = {}; + } } catch (error, stackTrace) { data = {}; diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 63bcc50..a28e5d6 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -629,15 +629,17 @@ class InvenTreeModel { if (!response.isValid() || response.data == null || response.data is! Map) { - // Report error - reportModelError( - "InvenTreeModel.getModel() returned invalid response", - response, - context: { - "filters": filters.toString(), - "pk": pk, - } - ); + if (response.statusCode != -1) { + // Report error + reportModelError( + "InvenTreeModel.getModel() returned invalid response", + response, + context: { + "filters": filters.toString(), + "pk": pk, + } + ); + } showServerError( url, diff --git a/pubspec.lock b/pubspec.lock index c4d2bc8..26fe112 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -125,26 +125,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" url: "https://pub.dev" source: hosted - version: "3.2.3" + version: "3.3.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "4.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.1" camera: dependency: "direct main" description: @@ -374,22 +374,14 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_blurhash: - dependency: transitive - description: - name: flutter_blurhash - sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" - url: "https://pub.dev" - source: hosted - version: "0.7.0" flutter_cache_manager: dependency: "direct main" description: name: flutter_cache_manager - sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" flutter_launcher_icons: dependency: "direct dev" description: @@ -689,10 +681,10 @@ packages: dependency: transitive description: name: octo_image - sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.0" one_context: dependency: "direct main" description: @@ -789,14 +781,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.6" - pedantic: - dependency: transitive - description: - name: pedantic - sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" - url: "https://pub.dev" - source: hosted - version: "1.11.1" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 67f7ceb..c09f3c8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.14.0+78 +version: 0.14.1+79 environment: sdk: ">=2.19.5 <3.13.0" @@ -9,7 +9,7 @@ environment: dependencies: adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) audioplayers: ^4.1.0 # Play audio files - cached_network_image: ^3.2.3 # Download and cache remote images + cached_network_image: ^3.3.1 # Download and cache remote images camera: ^0.10.3 # Camera cupertino_icons: ^1.0.3 currency_formatter: ^2.0.1 From 1d41d229caf51050c3fb8f278db5b3793ba19a5f Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Jan 2024 00:31:10 +1100 Subject: [PATCH 454/746] Error report updates (#470) * Prevent error reporting for certain status codes - These error codes indicate that there is something wrong with the server setup - Outside scope * Bump version --- assets/release_notes.md | 5 +++++ lib/api.dart | 8 +++++++- pubspec.yaml | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e5eb9c1..11731db 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.14.2 - January 2024 +--- + +- Updated error reporting + ### 0.14.1 - January 2024 --- diff --git a/lib/api.dart b/lib/api.dart index 841962b..3d91da8 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -950,7 +950,7 @@ class InvenTreeAPI { response.data = json.decode(jsondata); // Report a server-side error - if (response.statusCode >= 500) { + if (response.statusCode == 500) { sentryReportMessage( "Server error in uploadFile()", context: { @@ -1247,6 +1247,7 @@ class InvenTreeAPI { // Some server errors are not ones for us to worry about! switch (_response.statusCode) { case 502: // Bad gateway + case 503: // Service unavailable case 504: // Gateway timeout break; default: // Any other error code @@ -1318,6 +1319,11 @@ class InvenTreeAPI { case 404: // Ignore for unauthorized pages break; + case 502: + case 503: + case 504: + // Ignore for server errors + break; default: sentryReportMessage( "Error decoding JSON response from server", diff --git a/pubspec.yaml b/pubspec.yaml index c09f3c8..165b298 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.14.1+79 +version: 0.14.2+80 environment: sdk: ">=2.19.5 <3.13.0" From a889c4adbe4d56a780ece4a0f5f5c0a116d84601 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 28 Feb 2024 16:23:46 +1100 Subject: [PATCH 455/746] Filter fix (#473) * Add check for "null" top level locations and categories * Fix API - Top level location and category broken after API 174 - Ref: https://github.com/inventree/InvenTree/pull/6536 --- assets/release_notes.md | 4 +++- lib/api.dart | 3 +++ lib/widget/part/category_display.dart | 14 +++++++++++--- lib/widget/stock/location_display.dart | 15 ++++++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 11731db..a920d6a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,7 +1,9 @@ -### 0.14.2 - January 2024 +### 0.14.2 - February 2024 --- - Updated error reporting +- Support for updated server API endpoints +- Updated translations ### 0.14.1 - January 2024 --- diff --git a/lib/api.dart b/lib/api.dart index 3d91da8..7028bea 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -339,6 +339,9 @@ class InvenTreeAPI { // Does the server support allocating stock to sales order using barcodes? bool get supportsBarcodeSOAllocateEndpoint => isConnected() && apiVersion >= 160; + // Does the server support "null" top-level filtering for PartCategory and StockLocation endpoints? + bool get supportsNullTopLevelFiltering => isConnected() && apiVersion < 174; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart index c399cef..35be18c 100644 --- a/lib/widget/part/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -200,13 +200,21 @@ class _CategoryDisplayState extends RefreshableState { // Construct the "details" panel List detailTiles() { + Map filters = {}; + + int? parent = widget.category?.pk; + + if (parent != null) { + filters["parent"] = parent.toString(); + } else if (api.supportsNullTopLevelFiltering) { + filters["parent"] = "null"; + } + List tiles = [ getCategoryDescriptionCard(), Expanded( child: PaginatedPartCategoryList( - { - "parent": widget.category?.pk.toString() ?? "null" - }, + filters, title: L10().subcategories, ), flex: 10, diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 8b6a912..f31940c 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -393,13 +393,22 @@ class _LocationDisplayState extends RefreshableState { // Construct the "details" panel List detailTiles() { + + Map filters = {}; + + int? parent = location?.pk; + + if (parent != null) { + filters["parent"] = parent.toString(); + } else if (api.supportsNullTopLevelFiltering) { + filters["parent"] = "null"; + } + List tiles = [ locationDescriptionCard(), Expanded( child: PaginatedStockLocationList( - { - "parent": location?.pk.toString() ?? "null", - }, + filters, title: L10().sublocations, ), flex: 10, From b02dc5bac7aef43d526c92fc366f2327bcd81de7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 6 Mar 2024 21:09:06 +1100 Subject: [PATCH 456/746] Simplify DSN file (#475) * Add checks for empty sentry DSN * Add default DSN key * Fix CI workflows --- .github/workflows/android.yaml | 1 - .github/workflows/ci.yaml | 1 - .github/workflows/ios.yaml | 1 - .gitignore | 3 --- lib/dsn.dart | 7 +++++++ lib/dummy_dsn.dart | 3 --- lib/inventree/sentry.dart | 9 +++++++++ lib/main.dart | 16 +++++++++------- 8 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 lib/dsn.dart delete mode 100644 lib/dummy_dsn.dart diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 9481c5c..0699224 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -37,5 +37,4 @@ jobs: - name: Build for Android run: | flutter pub get - cp lib/dummy_dsn.dart lib/dsn.dart flutter build apk --debug diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4e3e371..ada4375 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -43,7 +43,6 @@ jobs: python3 collect_translations.py - name: Static Analysis Tests run: | - cp lib/dummy_dsn.dart lib/dsn.dart python3 find_dart_files.py flutter pub get flutter analyze diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 65c92a0..f6bf24b 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -38,5 +38,4 @@ jobs: pod repo update pod install cd .. - cp lib/dummy_dsn.dart lib/dsn.dart flutter build ios --release --no-codesign --no-tree-shake-icons diff --git a/.gitignore b/.gitignore index dd7fc90..96b3528 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,6 @@ coverage/* test/coverage_helper_test.dart InvenTreeSettings.db -# Sentry API key -lib/dsn.dart - # App signing key android/key.properties diff --git a/lib/dsn.dart b/lib/dsn.dart new file mode 100644 index 0000000..39092c8 --- /dev/null +++ b/lib/dsn.dart @@ -0,0 +1,7 @@ + +/* + * For integration with sentry.io, fill out the SENTRY_DSN_KEY value below. + * This should be set to a valid DSN key, from your sentry.io account + * + */ +String SENTRY_DSN_KEY = "https://fea705aa4b8e4c598dcf9b146b3d1b86@o378676.ingest.sentry.io/5202450"; \ No newline at end of file diff --git a/lib/dummy_dsn.dart b/lib/dummy_dsn.dart deleted file mode 100644 index d53bb6f..0000000 --- a/lib/dummy_dsn.dart +++ /dev/null @@ -1,3 +0,0 @@ -// Dummy DSN to use for unit testing, etc - -const String SENTRY_DSN_KEY = "https://12345678901234567890@abcdef.ingest.sentry.io/11223344"; \ No newline at end of file diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 4ca9cf4..7484d71 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -6,6 +6,7 @@ import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/dsn.dart"; import "package:inventree/preferences.dart"; Future> getDeviceInfo() async { @@ -85,6 +86,10 @@ bool isInDebugMode() { Future sentryReportMessage(String message, {Map? context}) async { + if (SENTRY_DSN_KEY.isEmpty) { + return false; + } + final server_info = getServerInfo(); final app_info = await getAppInfo(); final device_info = await getDeviceInfo(); @@ -164,6 +169,10 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr return; } + if (SENTRY_DSN_KEY.isEmpty) { + return; + } + final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; if (!upload) { diff --git a/lib/main.dart b/lib/main.dart index 3a7d2f4..9359449 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,13 +34,15 @@ Future main() async { String release = "${pkg}@${version}:${build}"; - await Sentry.init((options) { - options.dsn = SENTRY_DSN_KEY; - options.release = release; - options.environment = isInDebugMode() ? "debug" : "release"; - options.diagnosticLevel = SentryLevel.debug; - options.attachStacktrace = true; - }); + if (SENTRY_DSN_KEY.isNotEmpty) { + await Sentry.init((options) { + options.dsn = SENTRY_DSN_KEY; + options.release = release; + options.environment = isInDebugMode() ? "debug" : "release"; + options.diagnosticLevel = SentryLevel.debug; + options.attachStacktrace = true; + }); + } // Pass any flutter errors off to the Sentry reporting context! FlutterError.onError = (FlutterErrorDetails details) async { From 4ae28d60a189fe849168c4d902ec4e1c9f37b1e3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 6 Mar 2024 21:19:25 +1100 Subject: [PATCH 457/746] Readme updates (#476) * Update README.md - Add developer docs * Remove RELEASE.md --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ RELEASE.md | 47 ----------------------------------------------- 2 files changed, 41 insertions(+), 47 deletions(-) delete mode 100644 RELEASE.md diff --git a/README.md b/README.md index 00ec0c7..d59af46 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,44 @@ Written in the [Flutter](https://flutter.dev/) environment, the app provides nat ## User Documentation User documentation for the InvenTree mobile app can be found [within the InvenTree documentation](https://inventree.readthedocs.io/en/latest/app/app/). + +## Developer Documentation + +For developers looking to contribute to the project, we use Flutter for app development. The project has been tested in Android Studio (on both Windows and Mac) and also VSCode. + +### Invoke Tasks + +We use the [invoke](https://www.pyinvoke.org) to run some core tasks - you will need python and invoke installed on your local system. + +### Getting Started + +Initial project setup (after you have installed all required dev tools) is as follows: + +Install required flutter packages: +``` +flutter pub get +``` + +Generate initial translation files: + +``` +invoke translate +``` + +You should now be ready to debug on a connected or emulated device! + +### Building Release Versions + +Building release versions for target platforms (either android or iOS) is simplified using invoke: + +Build Android release: + +``` +invoke android +``` + +Build iOS release: + +``` +invoke ios +``` \ No newline at end of file diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 2fedfc6..0000000 --- a/RELEASE.md +++ /dev/null @@ -1,47 +0,0 @@ -# Release Process - -## Android Play Store - -[Reference](https://flutter.dev/docs/deployment/android#signing-the-app) - -### Key File - -Add a file `key.properties` under the android/ directory - -### Increment Build Number - -Make sure that the build number is incremented every time (or it will be rejected by Play Store). - -### Copy Translations - -Ensure that the translation files have been updated, and copied into the correct directory!! - -``` -cd lib/l10n -python collect_translations.py -``` - -### Build Appbundle - -`flutter build appbundle` - -### Upload Appbundle - -Upload the appbundle file to the Android developer website. - -## Apple Store - -Ref: https://flutter.dev/docs/deployment/ios - -### Build ipa - -``` -flutter clean -flutter build ipa --release --no-tree-shake-icons -``` - -### Validate and Distribute - -- Open `./build/ios/archive/Runner.xcarchive` in Xcode -- Run "Validate App" -- Run "Distribute App" \ No newline at end of file From 3f60b52a68eee6c04e43f32a31dac6a7416f4fbc Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 14 Apr 2024 07:35:04 +1000 Subject: [PATCH 458/746] New Crowdin updates (#482) * New translations app_en.arb (French) * New translations app_en.arb (Czech) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Swedish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 90 ++++++++++- lib/l10n/de_DE/app_de_DE.arb | 50 +++++- lib/l10n/fi_FI/app_fi_FI.arb | 10 ++ lib/l10n/fr_FR/app_fr_FR.arb | 66 +++++++- lib/l10n/hu_HU/app_hu_HU.arb | 58 +++++++ lib/l10n/lv_LV/app_lv_LV.arb | 7 + lib/l10n/no_NO/app_no_NO.arb | 90 +++++++++++ lib/l10n/pl_PL/app_pl_PL.arb | 52 +++++++ lib/l10n/pt_BR/app_pt_BR.arb | 58 +++++++ lib/l10n/ru_RU/app_ru_RU.arb | 62 +++++++- lib/l10n/sk_SK/app_sk_SK.arb | 7 + lib/l10n/sr_CS/app_sr_CS.arb | 7 + lib/l10n/sv_SE/app_sv_SE.arb | 18 ++- lib/l10n/vi_VN/app_vi_VN.arb | 80 ++++++++++ lib/l10n/zh_CN/app_zh_CN.arb | 290 +++++++++++++++++++---------------- 15 files changed, 806 insertions(+), 139 deletions(-) create mode 100644 lib/l10n/lv_LV/app_lv_LV.arb create mode 100644 lib/l10n/sk_SK/app_sk_SK.arb create mode 100644 lib/l10n/sr_CS/app_sr_CS.arb diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 2b44549..8a826fc 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -54,8 +54,14 @@ "@attachmentSelect": {}, "attention": "Upozornění", "@attention": {}, + "available": "K dispozici", + "@available": {}, "availableStock": "Dostupné zásoby", "@availableStock": {}, + "barcodes": "Čárové kódy", + "@barcodes": {}, + "barcodeSettings": "Nastavení čárových kódů", + "@barcodeSettings": {}, "barcodeAssign": "Přiřadit čárový kód", "@barcodeAssign": {}, "barcodeAssignDetail": "Naskenovat vlastní čárový kód", @@ -72,15 +78,32 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Čárový kód nebyl přiřazen", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Naskenovat čárový kód pro získání dílu", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Skenování čárových kódů pozastaveno", "@barodeScanPaused": {}, + "barcodeScanPause": "Klepnutím nebo podržením pozastavíte skenování", + "@barcodeScanPause": {}, "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", "@barcodeScanAssign": {}, - "barcodeScanGeneral": "Naskenuj čárový kód InvenTree", + "barcodeScanController": "Vstup skeneru", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Vyberte zdroj pro skenování kódu", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Prodleva prohledání čárového kódu", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Prodleva mezi skenováním čárových kódů", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Naskenovat čárový kód InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Skenovat skladové položky do tohoto umístění", "@barcodeScanInItems": {}, "barcodeScanLocation": "Skenovat skladové místo", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Režim jednoho skenování", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pozastavit skenování čárového kódu po každém skenování", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Naskenováno do umístění", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Položka není naskenována v", @@ -105,6 +128,10 @@ "@build": {}, "building": "Sestavení", "@building": {}, + "cameraInternal": "Interní kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Použít interní kameru pro čtení čárových kódů", + "@cameraInternalDetail": {}, "cancel": "Zrušit", "@cancel": { "description": "Cancel" @@ -143,8 +170,12 @@ }, "credits": "Poděkování", "@credits": {}, + "customer": "Zákazník", + "@customer": {}, "customers": "Zákazníci", "@customers": {}, + "customerReference": "Číslo objednávky", + "@customerReference": {}, "damaged": "Poškozeno", "@damaged": {}, "darkMode": "Tmavý motiv", @@ -185,6 +216,8 @@ "@editLocation": {}, "editNotes": "Upravit poznámky", "@editNotes": {}, + "editParameter": "Upravit parametr", + "@editParameter": {}, "editPart": "Upravit díl", "@editPart": { "description": "edit part" @@ -237,6 +270,10 @@ "@filterComponent": {}, "filterComponentDetail": "Zobrazit díly komponentu", "@filterComponentDetail": {}, + "filterExternal": "Externí", + "@filterExternal": {}, + "filterExternalDetail": "Zobrazit zásoby na externích lokacích", + "@filterExternalDetail": {}, "filterInStock": "Na skladě", "@filterInStock": {}, "filterInStockDetail": "Zobrazit díly, které jsou skladem", @@ -278,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", "@homeShowPoDescription": {}, + "homeShowSo": "Zobrazit prodejní objednávky", + "@homeShowSo": {}, + "homeShowSoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Odebírané díly", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Zobrazit odebírané díly na domovské obrazovce", @@ -346,8 +387,14 @@ "@issueOrder": {}, "itemInLocation": "Položka je již umístěna", "@itemInLocation": {}, + "itemDeleted": "Položka byla odebrána", + "@itemDeleted": {}, "keywords": "Klíčová slova", "@keywords": {}, + "labelPrinting": "Tisk štítku", + "@labelPrinting": {}, + "labelPrintingDetail": "Povolit tisk štítku", + "@labelPrintingDetail": {}, "labelTemplate": "Šablona štítku", "@labelTemplate": {}, "language": "Jazyk", @@ -362,6 +409,8 @@ "@lastUpdated": {}, "level": "Úroveň", "@level": {}, + "lineItemAdd": "Přidat položku", + "@lineItemAdd": {}, "lineItem": "Řádek položky", "@lineItem": {}, "lineItems": "Položky", @@ -380,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Skladové místo bylo aktualizováno", "@locationUpdated": {}, + "login": "Přihlášení", + "@login": {}, + "loginEnter": "Zadejte přihlašovací údaje", + "@loginEnter": {}, + "loginEnterDetails": "Uživatelské jméno a heslo nejsou uloženy lokálně", + "@loginEnterDetails": {}, "link": "Odkaz", "@link": {}, "lost": "Ztraceno", @@ -418,8 +473,24 @@ "@onOrder": {}, "onOrderDetails": "Položky momentálně v objednávce", "@onOrderDetails": {}, + "orientation": "Orientace obrazovky", + "@orientation": {}, + "orientationDetail": "Orientace obrazovky (vyžaduje restart)", + "@orientationDetail": {}, + "orientationLandscape": "Na šířku", + "@orientationLandscape": {}, + "orientationPortrait": "Na výšku", + "@orientationPortrait": {}, + "orientationSystem": "Systém", + "@orientationSystem": {}, "outstanding": "Nevyřízené", "@outstanding": {}, + "outstandingOrderDetail": "Zobrazit nevyřízené objednávky", + "@outstandingOrderDetail": {}, + "overdue": "Po termínu splatnosti", + "@overdue": {}, + "overdueDetail": "Zobrazit objednávky po splatnosti", + "@overdueDetail": {}, "packaging": "Balení", "@packaging": {}, "packageName": "Název balíčku", @@ -506,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Odstranit profil serveru", "@profileDelete": {}, + "profileLogout": "Odhlásit profil", + "@profileLogout": {}, "profileName": "Název profilu", "@profileName": {}, "profileNone": "Žádné profily nejsou k dispozici", @@ -628,9 +701,16 @@ }, "returned": "Vráceno", "@returned": {}, + "salesOrder": "Prodejní objednávka", + "@salesOrder": {}, "salesOrders": "Prodejní objednávky", "@salesOrders": {}, + "salesOrderCreate": "Nová prodejní objednávka", "@saleOrderCreate": {}, + "salesOrderEdit": "Upravit prodejní objednávku", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Objednávka prodeje byla aktualizována", + "@salesOrderUpdated": {}, "save": "Uložit", "@save": { "description": "Save" @@ -641,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Skenovat tuto položku do umístění", "@scanIntoLocationDetail": {}, + "scannerExternal": "Externí skener", + "@scannerExternal": {}, + "scannerExternalDetail": "Použít externí skener pro čtení čárových kódů (klínový režim)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Skenovat přijaté díly", + "@scanReceivedParts": {}, "search": "Hledat", "@search": { "description": "search" @@ -709,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server není vybrán", "@serverNotSelected": {}, + "shipped": "Odesláno", + "@shipped": {}, "sku": "Číslo zboží (SKU)", "@sku": {}, "sounds": "Zvuky", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index f192f48..096ca43 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode nicht zugewiesen", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Barcode scannen um Teil zu empfangen", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode-Scannen angehalten", "@barodeScanPaused": {}, + "barcodeScanPause": "Tippen oder halten um das Scannen anzuhalten", + "@barcodeScanPause": {}, "barcodeScanAssign": "Scannen um Barcode zuzuweisen", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner-Eingang", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Barcode-Scanner Eingangsquelle auswählen", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barcode Scan-Verzögerung", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Verzögerung zwischen Barcode-Scans", @@ -91,11 +100,15 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Lagerort scannen", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Einzel-Scanmodus", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Barcode-Scanner nach jedem Scan anhalten", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Artikel zu Lagerort hinzugefügt", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artikel nicht eingescannt", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Artikel scannen", + "barcodeScanItem": "Lagerartikel scannen", "@barcodeScanItem": {}, "barcodeTones": "Barcode-Ton", "@barcodeTones": {}, @@ -157,8 +170,12 @@ }, "credits": "Danksagungen", "@credits": {}, + "customer": "Kunde", + "@customer": {}, "customers": "Kunden", "@customers": {}, + "customerReference": "Kundenreferenz", + "@customerReference": {}, "damaged": "Beschädigt", "@damaged": {}, "darkMode": "Dunkles Design", @@ -298,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", "@homeShowPoDescription": {}, + "homeShowSo": "Aufträge anzeigen", + "@homeShowSo": {}, + "homeShowSoDescription": "Verkaufsknopf auf dem Startbildschirm anzeigen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Abonnierte Teile", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", @@ -366,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "Artikel ist bereits in diesem Lagerort", "@itemInLocation": {}, + "itemDeleted": "Element wurde gelöscht", + "@itemDeleted": {}, "keywords": "Schlüsselwörter", "@keywords": {}, "labelPrinting": "Etikettendruck", @@ -386,6 +409,8 @@ "@lastUpdated": {}, "level": "Ebene", "@level": {}, + "lineItemAdd": "Position hinzufügen", + "@lineItemAdd": {}, "lineItem": "Position", "@lineItem": {}, "lineItems": "Positionen", @@ -404,6 +429,10 @@ "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", "@locationUpdated": {}, + "login": "Anmelden", + "@login": {}, + "loginEnter": "Anmeldedaten eingeben", + "@loginEnter": {}, "loginEnterDetails": "Benutzername und Passwort werden nicht lokal gespeichert", "@loginEnterDetails": {}, "link": "Link", @@ -456,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "Ausstehend", "@outstanding": {}, + "outstandingOrderDetail": "Offene Aufträge anzeigen", + "@outstandingOrderDetail": {}, + "overdue": "Überfällig", + "@overdue": {}, + "overdueDetail": "Überfällige Aufträge anzeigen", + "@overdueDetail": {}, "packaging": "Paket", "@packaging": {}, "packageName": "Paket-Name", @@ -666,9 +701,16 @@ }, "returned": "Retourniert", "@returned": {}, + "salesOrder": "Auftrag", + "@salesOrder": {}, "salesOrders": "Kundenauftrag", "@salesOrders": {}, + "salesOrderCreate": "Neuer Auftrag", "@saleOrderCreate": {}, + "salesOrderEdit": "Auftrag bearbeiten", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Auftrag aktualisiert", + "@salesOrderUpdated": {}, "save": "Speichern", "@save": { "description": "Save" @@ -683,6 +725,8 @@ "@scannerExternal": {}, "scannerExternalDetail": "Benutze externen Scanner um Barcodes zu lesen", "@scannerExternalDetail": {}, + "scanReceivedParts": "Empfangene Teile scannen", + "@scanReceivedParts": {}, "search": "Suchen", "@search": { "description": "search" @@ -751,7 +795,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, - "sku": "Artikelnummer", + "shipped": "Versandt", + "@shipped": {}, + "sku": "Bestellnummer", "@sku": {}, "sounds": "Töne", "@sounds": {}, diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 8de61c1..2b29640 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -52,6 +52,12 @@ "@attachmentSelect": {}, "attention": "Huomio", "@attention": {}, + "available": "Saatavilla", + "@available": {}, + "barcodes": "Viivakoodit", + "@barcodes": {}, + "barcodeSettings": "Viivakoodi Asetukset", + "@barcodeSettings": {}, "barcodeAssign": "Aseta viivakoodi", "@barcodeAssign": {}, "barcodeAssigned": "Viivakoodi asetettu", @@ -127,10 +133,14 @@ "@editLocation": {}, "editNotes": "Muokkaa merkintää", "@editNotes": {}, + "editParameter": "Muokkaa Parametria", + "@editParameter": {}, "editPart": "Muokkaa osaa", "@editPart": { "description": "edit part" }, + "editLineItem": "Muokkaa listan riviä", + "@editLineItem": {}, "enterPassword": "Syötä salasana", "@enterPassword": {}, "enterUsername": "Syötä käyttäjätunnus", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index ebce2f8..fa5fce3 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -38,7 +38,7 @@ "@appReleaseNotes": {}, "appSettings": "Réglages de l'application", "@appSettings": {}, - "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", + "appSettingsDetails": "Configuration des paramètres de l’application InvenTree", "@appSettingsDetails": {}, "attachments": "Pieces jointes", "@attachments": {}, @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Code-barres non assigné", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Scannez le code-barres pour recevoir la pièce", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Scan de code-barres en pause", "@barodeScanPaused": {}, + "barcodeScanPause": "Appuyez ou maintenez pour mettre en pause le scan", + "@barcodeScanPause": {}, "barcodeScanAssign": "Scanner pour attribuer un code-barres", "@barcodeScanAssign": {}, + "barcodeScanController": "Saisie du scanner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Sélectionnez la source d'entrée du scanner de code-barres", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Délai de Numérisation des Codes-barres", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Délai entre deux scans de code-barres", @@ -91,6 +100,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Scanner la localisation du stock", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Mode Scanne unique", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Suspendre le scanner de code-barres après chaque scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Scanné vers l'emplacement", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Item non scanné dans", @@ -115,6 +128,10 @@ "@build": {}, "building": "Assemblage en cours", "@building": {}, + "cameraInternal": "Caméra interne", + "@cameraInternal": {}, + "cameraInternalDetail": "Utiliser la caméra interne pour lire les codes à barres", + "@cameraInternalDetail": {}, "cancel": "Annuler", "@cancel": { "description": "Cancel" @@ -153,8 +170,12 @@ }, "credits": "Crédits", "@credits": {}, + "customer": "Client", + "@customer": {}, "customers": "Clients", "@customers": {}, + "customerReference": "Référence client", + "@customerReference": {}, "damaged": "Endommagé", "@damaged": {}, "darkMode": "Mode Sombre", @@ -203,6 +224,8 @@ }, "editItem": "Editer l'article en stock", "@editItem": {}, + "editLineItem": "Modifier l'élément de la ligne", + "@editLineItem": {}, "enterPassword": "Saisissez le mot de passe", "@enterPassword": {}, "enterUsername": "Saisissez le nom d'utilisateur", @@ -292,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Afficher le bouton de l'ordre d'achat sur l'écran d'accueil", "@homeShowPoDescription": {}, + "homeShowSo": "Afficher les commandes de vente", + "@homeShowSo": {}, + "homeShowSoDescription": "Afficher le bouton des commandes sur l'écran d'accueil", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Pièces suivies", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", @@ -360,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "Article déjà dans l'emplacement", "@itemInLocation": {}, + "itemDeleted": "L'article a été supprimé", + "@itemDeleted": {}, "keywords": "Mots clés", "@keywords": {}, "labelPrinting": "Impression étiquettes", @@ -380,10 +409,14 @@ "@lastUpdated": {}, "level": "Niveau", "@level": {}, + "lineItemAdd": "Ajouter une ligne", + "@lineItemAdd": {}, "lineItem": "Position", "@lineItem": {}, "lineItems": "Position", "@lineItems": {}, + "lineItemUpdated": "Article mis à jour", + "@lineItemUpdated": {}, "locateItem": "Localiser l'article en stock", "@locateItem": {}, "locateLocation": "Localiser l'emplacement du stock", @@ -396,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Emplacement du stock mis à jour", "@locationUpdated": {}, + "login": "Se connecter", + "@login": {}, + "loginEnter": "Saisir les informations de connexion", + "@loginEnter": {}, + "loginEnterDetails": "Le nom d'utilisateur et le mot de passe ne sont pas stockés localement", + "@loginEnterDetails": {}, "link": "Lien", "@link": {}, "lost": "Perdu", @@ -446,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "En attente", "@outstanding": {}, + "outstandingOrderDetail": "Afficher les commandes en cours", + "@outstandingOrderDetail": {}, + "overdue": "En retard", + "@overdue": {}, + "overdueDetail": "Afficher les commandes en retard", + "@overdueDetail": {}, "packaging": "Emballage", "@packaging": {}, "packageName": "Nom du package", @@ -532,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Supprimer le profil du serveur", "@profileDelete": {}, + "profileLogout": "Déconnexion du profil", + "@profileLogout": {}, "profileName": "Nom du profil", "@profileName": {}, "profileNone": "Aucun profil disponible", @@ -654,9 +701,16 @@ }, "returned": "Retourné", "@returned": {}, + "salesOrder": "Commandes", + "@salesOrder": {}, "salesOrders": "Ventes", "@salesOrders": {}, + "salesOrderCreate": "Nouvelle commande", "@saleOrderCreate": {}, + "salesOrderEdit": "Modifier la commande", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Commande mise à jour", + "@salesOrderUpdated": {}, "save": "Enregistrer", "@save": { "description": "Save" @@ -667,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scannez cet élément à l'emplacement", "@scanIntoLocationDetail": {}, + "scannerExternal": "Scanner externe", + "@scannerExternal": {}, + "scannerExternalDetail": "Utiliser un scanner externe pour lire les codes-barres (mode biseau)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scanner les pièces reçues", + "@scanReceivedParts": {}, "search": "Rechercher", "@search": { "description": "search" @@ -735,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Serveur non sélectionné", "@serverNotSelected": {}, + "shipped": "Expédié", + "@shipped": {}, "sku": "UGS", "@sku": {}, "sounds": "Sons", @@ -847,6 +909,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Afficher les résultats du test des articles en stock", + "@testResultsDetail": {}, "testResultAdd": "Ajouter un résultat de test", "@testResultAdd": {}, "testResultNone": "Aucun résultat de test", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 00ce57d..a3c2620 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Olvasd le a vonalkódot a bevételezéshez", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Vonalkód olvasás megállítva", "@barodeScanPaused": {}, + "barcodeScanPause": "Kattints vagy tartsd lenyomva a beolvasás felfüggesztéséhez", + "@barcodeScanPause": {}, "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", "@barcodeScanAssign": {}, + "barcodeScanController": "Vonalkód bemenet", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Válassz vonalkód olvasó bemenetet", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Vonalkód olvasási késleltetés", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Vonalkód olvasások közti késleltetés", @@ -91,6 +100,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Hely beolvasása", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Egyszeri olvasás", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Minden olvasás után megállítás", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Beolvasva az adott helyre", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "A tétel nincs beolvasva ide", @@ -115,6 +128,10 @@ "@build": {}, "building": "Gyártásban", "@building": {}, + "cameraInternal": "Belső kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Beépített kamera használata vonalkódolvasásra", + "@cameraInternalDetail": {}, "cancel": "Mégsem", "@cancel": { "description": "Cancel" @@ -153,8 +170,12 @@ }, "credits": "Közreműködők", "@credits": {}, + "customer": "Vevő", + "@customer": {}, "customers": "Vevők", "@customers": {}, + "customerReference": "Vevői azonosító", + "@customerReference": {}, "damaged": "Sérült", "@damaged": {}, "darkMode": "Sötét mód", @@ -294,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", "@homeShowPoDescription": {}, + "homeShowSo": "Vevői rendelések megmutatása", + "@homeShowSo": {}, + "homeShowSoDescription": "Értékesítési rendelések gomb megjelenítése a főoldalon", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Értesítésre beállított alkatrészek", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Alkatrész értesítések megjelenítése a főoldalon", @@ -362,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "A tétel már a megadott helyen van", "@itemInLocation": {}, + "itemDeleted": "Termék el lett távolítva", + "@itemDeleted": {}, "keywords": "Kulcsszavak", "@keywords": {}, "labelPrinting": "Címke nyomtatás", @@ -382,6 +409,8 @@ "@lastUpdated": {}, "level": "Szint", "@level": {}, + "lineItemAdd": "Sortétel hozzáadása", + "@lineItemAdd": {}, "lineItem": "Sortétel", "@lineItem": {}, "lineItems": "Sortételek", @@ -400,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Készlet hely adatai frissítve", "@locationUpdated": {}, + "login": "Bejelentkezés", + "@login": {}, + "loginEnter": "Bejelentkezési adatok megadása", + "@loginEnter": {}, + "loginEnterDetails": "A felhasználónév és jelszó nincs helyben tárolva", + "@loginEnterDetails": {}, "link": "Link", "@link": {}, "lost": "Elveszett", @@ -450,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "Kintlévő", "@outstanding": {}, + "outstandingOrderDetail": "Kintlévő rendelések megjelenítése", + "@outstandingOrderDetail": {}, + "overdue": "Késésben", + "@overdue": {}, + "overdueDetail": "Késésben lévő rendelések megjelenítése", + "@overdueDetail": {}, "packaging": "Csomagolás", "@packaging": {}, "packageName": "Csomag neve", @@ -536,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Kiszolgáló profil törlése", "@profileDelete": {}, + "profileLogout": "Kijelentkezés", + "@profileLogout": {}, "profileName": "Profil neve", "@profileName": {}, "profileNone": "Nincsenek profilok", @@ -658,9 +701,16 @@ }, "returned": "Visszaküldve", "@returned": {}, + "salesOrder": "Vevői rendelés", + "@salesOrder": {}, "salesOrders": "Vevői rendelések", "@salesOrders": {}, + "salesOrderCreate": "Új vevői rendelés", "@saleOrderCreate": {}, + "salesOrderEdit": "Vevői rendelés szerkesztése", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Vevői rendelés frissítve", + "@salesOrderUpdated": {}, "save": "Mentés", "@save": { "description": "Save" @@ -671,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Készlet bevételezése erre a helyre", "@scanIntoLocationDetail": {}, + "scannerExternal": "Külső vonalkód olvasó", + "@scannerExternal": {}, + "scannerExternalDetail": "Külső olvasó használata vonalkódokhoz (billentyűzet elé beékelődő mód)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Bevételezett alkatrészek szkennelése", + "@scanReceivedParts": {}, "search": "Keresés", "@search": { "description": "search" @@ -739,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, + "shipped": "Kiszállítva", + "@shipped": {}, "sku": "SKU", "@sku": {}, "sounds": "Hangok", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb new file mode 100644 index 0000000..e4c0e9e --- /dev/null +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -0,0 +1,7 @@ +{ + "@@locale": "lv", + "@barodeScanPaused": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} +} \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 6488ce2..be5fac4 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -54,8 +54,14 @@ "@attachmentSelect": {}, "attention": "Merknad", "@attention": {}, + "available": "Tilgjengelig", + "@available": {}, "availableStock": "Tilgjengelig lagerbeholdning", "@availableStock": {}, + "barcodes": "Strekkoder", + "@barcodes": {}, + "barcodeSettings": "Strekkodeinnstillinger", + "@barcodeSettings": {}, "barcodeAssign": "Tildel Strekkode", "@barcodeAssign": {}, "barcodeAssignDetail": "Skann egendefinert strekkode for å tildele", @@ -72,15 +78,32 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Strekkode ikke tildelt", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Skann strekkode for å motta del", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Skanning satt på pause", "@barodeScanPaused": {}, + "barcodeScanPause": "Trykk eller hold for å pause skanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Skann for å tildele strekkode", "@barcodeScanAssign": {}, + "barcodeScanController": "Skanner input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Velg strekkodeleser inngangskilde", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Skanneforsinkelse for strekkode", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Forsinkelse mellom strekkodeskanninger", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Skann en InvenTree-strekkode", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Skann lagervarer til denne plasseringen", "@barcodeScanInItems": {}, "barcodeScanLocation": "Skann lagerplassering", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Enkel skann-modus", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause strekkodeleser etter hver skanning", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Skannet til plassering", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artikkelen ble ikke skannet inn", @@ -105,6 +128,10 @@ "@build": {}, "building": "Produserer", "@building": {}, + "cameraInternal": "Internt kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Bruk internt kamera til å lese strekkoder", + "@cameraInternalDetail": {}, "cancel": "Avbryt", "@cancel": { "description": "Cancel" @@ -143,8 +170,12 @@ }, "credits": "Krediteringer", "@credits": {}, + "customer": "Kunde", + "@customer": {}, "customers": "Kunder", "@customers": {}, + "customerReference": "Kundereferanse", + "@customerReference": {}, "damaged": "Skadet", "@damaged": {}, "darkMode": "Mørk Modus", @@ -185,6 +216,8 @@ "@editLocation": {}, "editNotes": "Rediger notater", "@editNotes": {}, + "editParameter": "Rediger Parameter", + "@editParameter": {}, "editPart": "Rediger del", "@editPart": { "description": "edit part" @@ -237,6 +270,10 @@ "@filterComponent": {}, "filterComponentDetail": "Vis komponentdeler", "@filterComponentDetail": {}, + "filterExternal": "Ekstern", + "@filterExternal": {}, + "filterExternalDetail": "Vis lagerbeholdning ved eksterne plasseringer", + "@filterExternalDetail": {}, "filterInStock": "På lager", "@filterInStock": {}, "filterInStockDetail": "Vis deler som har lagerbeholdning", @@ -278,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Vis innkjøpsordre-knappen på startside", "@homeShowPoDescription": {}, + "homeShowSo": "Vis salgsordrer", + "@homeShowSo": {}, + "homeShowSoDescription": "Vis salgsordre-knappen på startside", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Abonnerte deler", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Vis abonnerte deler på startside", @@ -346,8 +387,14 @@ "@issueOrder": {}, "itemInLocation": "Artikkelen er allerede i plasseringen", "@itemInLocation": {}, + "itemDeleted": "Elementet har blitt fjernet", + "@itemDeleted": {}, "keywords": "Nøkkelord", "@keywords": {}, + "labelPrinting": "Etikettutskrift", + "@labelPrinting": {}, + "labelPrintingDetail": "Aktiver etikettutskrift", + "@labelPrintingDetail": {}, "labelTemplate": "Etikettmal", "@labelTemplate": {}, "language": "Språk", @@ -362,6 +409,8 @@ "@lastUpdated": {}, "level": "Nivå", "@level": {}, + "lineItemAdd": "Legg til linjeelement", + "@lineItemAdd": {}, "lineItem": "Ordrelinje", "@lineItem": {}, "lineItems": "Ordrelinjer", @@ -380,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Lagerplassering oppdatert", "@locationUpdated": {}, + "login": "Logg inn", + "@login": {}, + "loginEnter": "Skriv inn innloggingsdetaljer", + "@loginEnter": {}, + "loginEnterDetails": "Brukernavn og passord lagres ikke lokalt", + "@loginEnterDetails": {}, "link": "Lenke", "@link": {}, "lost": "Tapt", @@ -418,8 +473,24 @@ "@onOrder": {}, "onOrderDetails": "Artikler i bestilling for øyeblikket", "@onOrderDetails": {}, + "orientation": "Skjermorientering", + "@orientation": {}, + "orientationDetail": "Skjermretning (krever omstart)", + "@orientationDetail": {}, + "orientationLandscape": "Liggende", + "@orientationLandscape": {}, + "orientationPortrait": "Stående", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, "outstanding": "Utestående", "@outstanding": {}, + "outstandingOrderDetail": "Vis utestående ordre", + "@outstandingOrderDetail": {}, + "overdue": "Forfalt", + "@overdue": {}, + "overdueDetail": "Vis forfalte ordrer", + "@overdueDetail": {}, "packaging": "Emballasje", "@packaging": {}, "packageName": "Pakkenavn", @@ -506,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Slett serverprofil", "@profileDelete": {}, + "profileLogout": "Logg ut profil", + "@profileLogout": {}, "profileName": "Profilnavn", "@profileName": {}, "profileNone": "Ingen profiler tilgjengelig", @@ -628,9 +701,16 @@ }, "returned": "Returnert", "@returned": {}, + "salesOrder": "Salgsordre", + "@salesOrder": {}, "salesOrders": "Salgsordre", "@salesOrders": {}, + "salesOrderCreate": "Ny salgsordre", "@saleOrderCreate": {}, + "salesOrderEdit": "Rediger salgsordre", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Salgsordre oppdatert", + "@salesOrderUpdated": {}, "save": "Lagre", "@save": { "description": "Save" @@ -641,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Skann artikkelen til plassering", "@scanIntoLocationDetail": {}, + "scannerExternal": "Ekstern skanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Bruk ekstern skanner til å lese strekkoder (kilemodus)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Skann mottatte deler", + "@scanReceivedParts": {}, "search": "Søk", "@search": { "description": "search" @@ -709,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, + "shipped": "Sendt", + "@shipped": {}, "sku": "SKU-kode", "@sku": {}, "sounds": "Lyder", @@ -821,6 +909,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Vis testresultater for lagervare", + "@testResultsDetail": {}, "testResultAdd": "Legg til testresultat", "@testResultAdd": {}, "testResultNone": "Ingen testresultater", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 0a29762..1faf7b2 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1,5 +1,13 @@ { "@@locale": "pl", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, "about": "O nas", "@about": {}, "accountDetails": "Szczegóły konta", @@ -40,10 +48,20 @@ }, "attachmentNone": "Nie znaleziono załączników", "@attachmentNone": {}, + "attachmentNoneDetail": "Nie znaleziono załączników", + "@attachmentNoneDetail": {}, "attachmentSelect": "Wybierz załącznik", "@attachmentSelect": {}, "attention": "Uwaga", "@attention": {}, + "available": "Dostępne", + "@available": {}, + "availableStock": "Dostępne zasoby", + "@availableStock": {}, + "barcodes": "Kody kreskowe", + "@barcodes": {}, + "barcodeSettings": "Ustawienia kodu kreskowego", + "@barcodeSettings": {}, "barcodeAssign": "Przypisz kod kreskowy", "@barcodeAssign": {}, "barcodeAssigned": "Kod kreskowy przypisany", @@ -81,6 +99,8 @@ "@batchCode": {}, "billOfMaterials": "Zestawienie materiałów", "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, "build": "Budowa", "@build": {}, "building": "Budowanie", @@ -89,6 +109,8 @@ "@cancel": { "description": "Cancel" }, + "cancelOrder": "Anuluj zamówienie", + "@cancelOrder": {}, "category": "Kategoria", "@category": {}, "categoryCreate": "Nowa Kategoria", @@ -121,10 +143,16 @@ }, "credits": "Podziękowania", "@credits": {}, + "customer": "Klient", + "@customer": {}, "customers": "Klienci", "@customers": {}, "damaged": "Uszkodzone", "@damaged": {}, + "darkMode": "Tryb ciemny", + "@darkMode": {}, + "darkModeEnable": "Włącz tryb ciemny", + "@darkModeEnable": {}, "delete": "Usuń", "@delete": {}, "deletePart": "Usuń Komponent", @@ -189,6 +217,12 @@ "@feedbackError": {}, "feedbackSuccess": "Opinia przesłana", "@feedbackSuccess": {}, + "filterInStock": "Na stanie", + "@filterInStock": {}, + "filterTemplate": "Szablon", + "@filterTemplate": {}, + "filterVirtual": "Wirtualny", + "@filterVirtual": {}, "formatException": "Wyjątek formatowania", "@formatException": {}, "formatExceptionJson": "Wyjątek formatu danych JSON", @@ -293,6 +327,8 @@ "@notes": { "description": "Notes" }, + "notifications": "Powiadomienia", + "@notifications": {}, "noResponse": "Brak odpowiedzi od serwera", "@noResponse": {}, "noResults": "Brak wyników", @@ -307,6 +343,8 @@ "@onOrder": {}, "onOrderDetails": "Pozycje obecnie w zamówieniu", "@onOrderDetails": {}, + "orientationSystem": "System", + "@orientationSystem": {}, "packaging": "Opakowanie", "@packaging": {}, "packageName": "Nazwa pakietu", @@ -365,6 +403,14 @@ "@permissionRequired": {}, "printLabel": "Drukuj etykietę", "@printLabel": {}, + "plugin": "Wtyczka", + "@plugin": {}, + "pluginPrinter": "Drukarka", + "@pluginPrinter": {}, + "pluginSupport": "Wsparcie wtyczek włączone", + "@pluginSupport": {}, + "pluginSupportDetail": "Serwer obsługuje niestandardowe wtyczki", + "@pluginSupportDetail": {}, "printLabelFailure": "Drukowanie etykiet nie powiodło się", "@printLabelFailure": {}, "printLabelSuccess": "Etykieta wysłana do drukarki", @@ -379,6 +425,8 @@ "@profileEdit": {}, "profileDelete": "Usuń profil serwera", "@profileDelete": {}, + "profileLogout": "Wyloguj się", + "@profileLogout": {}, "profileName": "Nazwa Profilu", "@profileName": {}, "profileNone": "Brak dostępnych profili", @@ -387,6 +435,8 @@ "@profileNotSelected": {}, "profileSelect": "Wybierz serwer InvenTree", "@profileSelect": {}, + "profileSelectOrCreate": "Wybierz serwer lub utwórz nowy profil", + "@profileSelectOrCreate": {}, "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", "@profileTapToCreate": {}, "purchaseOrder": "Zlecenie Zakupu", @@ -562,6 +612,8 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Odtwarzaj dźwięk podczas błędu serwera", "@soundOnServerError": {}, + "status": "Status", + "@status": {}, "statusCode": "Kod statusu", "@statusCode": {}, "stock": "Stan", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 83e075c..9f4477b 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Digitalize o código de barras para receber a parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Escaneamento de código de barras pausado", "@barodeScanPaused": {}, + "barcodeScanPause": "Toque ou segure para pausar o escaneamento", + "@barcodeScanPause": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, + "barcodeScanController": "Entrada do leitor", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Selecione a fonte de entrada do leitor de código de barras", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Atraso na leitura de Código de Barras", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Atraso entre leituras de código de barras", @@ -91,6 +100,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear Local do Estoque", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Modo de Escaneamento Individual", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pausar leitor de código de barras após cada digitalização", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado no local", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "O item não foi digitalizado no", @@ -115,6 +128,10 @@ "@build": {}, "building": "Produzindo", "@building": {}, + "cameraInternal": "Câmera Interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Usar câmera interna para ler códigos de barras", + "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" @@ -153,8 +170,12 @@ }, "credits": "Créditos", "@credits": {}, + "customer": "Cliente", + "@customer": {}, "customers": "Clientes", "@customers": {}, + "customerReference": "Referência do Cliente", + "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, "darkMode": "Modo Escuro", @@ -294,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botão de ordem de compra na tela inicial", "@homeShowPoDescription": {}, + "homeShowSo": "Mostrar Pedidos de Venda", + "@homeShowSo": {}, + "homeShowSoDescription": "Mostrar Pedidos de Venda na tela inicial", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Peças subscritas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar peças subscritas na tela inicial", @@ -362,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "Item ja na localizacao", "@itemInLocation": {}, + "itemDeleted": "O item foi removido", + "@itemDeleted": {}, "keywords": "Palavras chave", "@keywords": {}, "labelPrinting": "Impressão de Etiqueta", @@ -382,6 +409,8 @@ "@lastUpdated": {}, "level": "Nível", "@level": {}, + "lineItemAdd": "Adicionar item de linha", + "@lineItemAdd": {}, "lineItem": "Linha do item", "@lineItem": {}, "lineItems": "Linhas do item", @@ -400,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Localizacao no estoque atualizada", "@locationUpdated": {}, + "login": "Entrar", + "@login": {}, + "loginEnter": "Inserir detalhes de acesso", + "@loginEnter": {}, + "loginEnterDetails": "Nome de usuário e senha não são armazenados localmente", + "@loginEnterDetails": {}, "link": "Link", "@link": {}, "lost": "Perdido", @@ -450,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "Pendente", "@outstanding": {}, + "outstandingOrderDetail": "Mostrar pedidos pendentes", + "@outstandingOrderDetail": {}, + "overdue": "Em atraso", + "@overdue": {}, + "overdueDetail": "Mostrar pedidos atrasados", + "@overdueDetail": {}, "packaging": "Embalagem", "@packaging": {}, "packageName": "Nome do pacote", @@ -536,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Apagar perfil do Servidor", "@profileDelete": {}, + "profileLogout": "Desconectar Perfil", + "@profileLogout": {}, "profileName": "Nome do Perfil", "@profileName": {}, "profileNone": "Nenhum perfil disponível", @@ -658,9 +701,16 @@ }, "returned": "Retornado", "@returned": {}, + "salesOrder": "Pedido de Venda", + "@salesOrder": {}, "salesOrders": "Pedido de vendas", "@salesOrders": {}, + "salesOrderCreate": "Novo Pedido de Venda", "@saleOrderCreate": {}, + "salesOrderEdit": "Editar Pedidos de Venda", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Pedido de venda atualizado", + "@salesOrderUpdated": {}, "save": "Salvar", "@save": { "description": "Save" @@ -671,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Digitalize este item no local", "@scanIntoLocationDetail": {}, + "scannerExternal": "Leitor externo", + "@scannerExternal": {}, + "scannerExternalDetail": "Usar leitor externo para ler códigos de barras (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Escanear Partes Recebidas", + "@scanReceivedParts": {}, "search": "Buscar", "@search": { "description": "search" @@ -739,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor não selecionado", "@serverNotSelected": {}, + "shipped": "Enviado", + "@shipped": {}, "sku": "Código (SKU)", "@sku": {}, "sounds": "Sons", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index dc29c2b..0ccffdc 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Штрих-код не назначен", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Отсканируйте штрих-код для получения детали", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Сканирование штрих-кода приостановлено", "@barodeScanPaused": {}, + "barcodeScanPause": "Нажмите или удерживайте, чтобы приостановить сканирование", + "@barcodeScanPause": {}, "barcodeScanAssign": "Сканировать для присвоения штрих-кода", "@barcodeScanAssign": {}, + "barcodeScanController": "Источник сканера", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Выберите источник сканера штрих-кода", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Задержка сканирования штрих-кода", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Задержка между сканированием штрих-кодов", @@ -91,6 +100,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Сканировать местоположение склада", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Режим одиночного сканирования", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Приостановить сканер штрих-кода после каждого сканирования", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Сканирование на место", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Элемент не просканирован в", @@ -115,6 +128,10 @@ "@build": {}, "building": "Построение", "@building": {}, + "cameraInternal": "Внутренняя камера", + "@cameraInternal": {}, + "cameraInternalDetail": "Использовать внутреннюю камеру для чтения штрих-кодов", + "@cameraInternalDetail": {}, "cancel": "Отменить", "@cancel": { "description": "Cancel" @@ -153,8 +170,12 @@ }, "credits": "Авторы", "@credits": {}, + "customer": "Клиент", + "@customer": {}, "customers": "Покупатели", "@customers": {}, + "customerReference": "Артикул клиента", + "@customerReference": {}, "damaged": "Поврежденный", "@damaged": {}, "darkMode": "Тёмная тема", @@ -201,7 +222,7 @@ "@editPart": { "description": "edit part" }, - "editItem": "Отредактированный товар", + "editItem": "Складская позиция", "@editItem": {}, "editLineItem": "Изменить позицию", "@editLineItem": {}, @@ -294,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Показывать кнопку заказа на главном экране", "@homeShowPoDescription": {}, + "homeShowSo": "Показать заказы на продажу", + "@homeShowSo": {}, + "homeShowSoDescription": "Показывать кнопку заказов на продажу на главном экране", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Детали с включёнными уведомлениями", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Показывать детали, на которые включены уведомления, на главной странице", @@ -362,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "Элемент уже находится на месте", "@itemInLocation": {}, + "itemDeleted": "Позиция была удалена", + "@itemDeleted": {}, "keywords": "Ключевые слова", "@keywords": {}, "labelPrinting": "Печать этикеток", @@ -382,6 +409,8 @@ "@lastUpdated": {}, "level": "Уровень", "@level": {}, + "lineItemAdd": "Добавить позицию", + "@lineItemAdd": {}, "lineItem": "Элемент строки", "@lineItem": {}, "lineItems": "Элементы строки", @@ -400,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Расположение склада обновлено", "@locationUpdated": {}, + "login": "Войти", + "@login": {}, + "loginEnter": "Введите данные для входа", + "@loginEnter": {}, + "loginEnterDetails": "Логин и пароль не хранятся локально", + "@loginEnterDetails": {}, "link": "Ссылка", "@link": {}, "lost": "Потерян", @@ -450,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "Не оплачено", "@outstanding": {}, + "outstandingOrderDetail": "Показать невыполненные заказы", + "@outstandingOrderDetail": {}, + "overdue": "Просрочено", + "@overdue": {}, + "overdueDetail": "Показывать просроченные заказы", + "@overdueDetail": {}, "packaging": "Упаковка", "@packaging": {}, "packageName": "Название упаковки", @@ -536,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Удалить профиль сервера", "@profileDelete": {}, + "profileLogout": "Выйти из аккаунта", + "@profileLogout": {}, "profileName": "Имя профиля", "@profileName": {}, "profileNone": "Нет доступных профилей", @@ -658,9 +701,16 @@ }, "returned": "Возвращено", "@returned": {}, + "salesOrder": "Заказы на продажу", + "@salesOrder": {}, "salesOrders": "Заказы на продажу", "@salesOrders": {}, + "salesOrderCreate": "Новый заказ на продажу", "@saleOrderCreate": {}, + "salesOrderEdit": "Редактировать заказ на продажу", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Заказ на продажу обновлен", + "@salesOrderUpdated": {}, "save": "Сохранить", "@save": { "description": "Save" @@ -671,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Отсканировать этот компонент в местоположение", "@scanIntoLocationDetail": {}, + "scannerExternal": "Внешний сканер", + "@scannerExternal": {}, + "scannerExternalDetail": "Использовать внешний сканер для чтения штрих-кодов (клик-режим)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Сканирование принятых деталей", + "@scanReceivedParts": {}, "search": "Поиск", "@search": { "description": "search" @@ -739,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не выбран", "@serverNotSelected": {}, + "shipped": "Отгружено", + "@shipped": {}, "sku": "SKU", "@sku": {}, "sounds": "Звуки", @@ -785,7 +843,7 @@ "@stockItemUpdated": {}, "stockItemsNotAvailable": "Нет доступных складских позиций", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Заметки складской позиции", + "stockItemNotes": "Записи складской позиции", "@stockItemNotes": {}, "stockItemUpdateSuccess": "Складская позиция обновлена", "@stockItemUpdateSuccess": {}, diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb new file mode 100644 index 0000000..2dc50ee --- /dev/null +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -0,0 +1,7 @@ +{ + "@@locale": "sk", + "@barodeScanPaused": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} +} \ No newline at end of file diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb new file mode 100644 index 0000000..799ed5c --- /dev/null +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -0,0 +1,7 @@ +{ + "@@locale": "sr-CS", + "@barodeScanPaused": {}, + "@homeShowSubscsribedDescription": {}, + "@homeShowSupplierDescription": {}, + "@saleOrderCreate": {} +} \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 90058eb..84921e4 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -26,7 +26,7 @@ "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "Adress", "@address": {}, "appAbout": "Om InvenTree", "@appAbout": {}, @@ -50,7 +50,7 @@ "@attachmentNone": {}, "attachmentNoneDetail": "Inga bilagor hittades", "@attachmentNoneDetail": {}, - "attachmentSelect": "Välj bilagor", + "attachmentSelect": "Välj bilaga", "@attachmentSelect": {}, "attention": "Obs!", "@attention": {}, @@ -93,13 +93,13 @@ "@description": {}, "downloadError": "Nedladdningsfel", "@downloadError": {}, - "edit": "Ändra", + "edit": "Redigera", "@edit": { "description": "edit" }, - "editCategory": "Ändra Kategori", + "editCategory": "Redigera kategori", "@editCategory": {}, - "editLocation": "Ändra plats", + "editLocation": "Redigera plats", "@editLocation": {}, "editNotes": "Redigera anteckningar", "@editNotes": {}, @@ -139,10 +139,16 @@ "@includeSubcategoriesDetail": {}, "keywords": "Nyckelord", "@keywords": {}, + "language": "Språk", + "@language": {}, + "languageSelect": "Välj språk", + "@languageSelect": {}, "lastUpdated": "Senast uppdaterad", "@lastUpdated": {}, "manufacturers": "Tillverkare", "@manufacturers": {}, + "name": "Namn", + "@name": {}, "notes": "Anteckningar", "@notes": { "description": "Notes" @@ -168,6 +174,8 @@ "@searching": {}, "serialNumbers": "Serienummer", "@serialNumbers": {}, + "settings": "Inställningar", + "@settings": {}, "status": "Status", "@status": {}, "statusCode": "Statuskod", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 35d5f3a..5aa165e 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -78,9 +78,18 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Mã vạch chưa được quét", "@barcodeNotAssigned": {}, + "barcodeReceivePart": "Quét mã vạch để nhận sản phẩm", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Quét mã vạch đã bị dừng", "@barodeScanPaused": {}, + "barcodeScanPause": "Nhấp hoặc giữ để dừng quét", + "@barcodeScanPause": {}, "barcodeScanAssign": "Quét để gán mã vạch", "@barcodeScanAssign": {}, + "barcodeScanController": "Đầu vào máy quét", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Chọn nguồn đầu vào máy quét mã vạch", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Độ trễ quét mã vạch", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Thời gian trễ giữa lần quét mã vạch", @@ -91,6 +100,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Quét vị trí kho hàng", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Chế độ quét đơn", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Dừng máy sau mỗi lần quét", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Đã quét vào vị trí", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Item không được quét vào", @@ -115,6 +128,10 @@ "@build": {}, "building": "Tòa nhà", "@building": {}, + "cameraInternal": "Camera nội bộ", + "@cameraInternal": {}, + "cameraInternalDetail": "Sử dụng camera nội bộ để đọc mã vạch", + "@cameraInternalDetail": {}, "cancel": "Hủy bỏ", "@cancel": { "description": "Cancel" @@ -153,8 +170,12 @@ }, "credits": "Tín dụng", "@credits": {}, + "customer": "Khách hàng", + "@customer": {}, "customers": "Khách hàng", "@customers": {}, + "customerReference": "Tham chiếu khách hàng", + "@customerReference": {}, "damaged": "Bị hỏng", "@damaged": {}, "darkMode": "Chế độ tối", @@ -257,6 +278,10 @@ "@filterInStock": {}, "filterInStockDetail": "Hiển thị các mặt hàng có trong kho", "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Hiển thị hàng hóa theo sê ri", + "@filterSerializedDetail": {}, "filterTemplate": "Mẫu", "@filterTemplate": {}, "filterTemplateDetail": "Hiển thị các phần template", @@ -267,6 +292,8 @@ "@filterTrackableDetail": {}, "filterVirtual": "Ảo", "@filterVirtual": {}, + "filterVirtualDetail": "Hiện sản phẩm ảo", + "@filterVirtualDetail": {}, "filteringOptions": "Tùy chọn bộ lọc", "@filteringOptions": {}, "formatException": "Định dạng ngoại lệ", @@ -288,6 +315,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Hiển thị đơn hàng mới tại màn hình chính", "@homeShowPoDescription": {}, + "homeShowSo": "Hiện đơn hàng bán", + "@homeShowSo": {}, + "homeShowSoDescription": "Hiện nút đơn hàng bán tại màn hình trang chủ", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Đăng kí phụ kiện", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Hiển thị các phần đã đăng kí trên màn hình chính", @@ -330,16 +361,22 @@ "@inProduction": {}, "inProductionDetail": "Mặt hàng này đang được sản xuất tại kho", "@inProductionDetail": {}, + "internalPart": "Sản phẩm nội bộ", + "@internalPart": {}, "invalidHost": "Tên máy chủ không hợp lệ", "@invalidHost": {}, "invalidHostDetails": "Tên máy chủ được cung cấp không hợp lệ", "@invalidHostDetails": {}, "invalidPart": "Phụ kiện không hợp lệ", "@invalidPart": {}, + "invalidPartCategory": "Danh mục sản phẩm không hợp lệ", + "@invalidPartCategory": {}, "invalidStockLocation": "Vị trí kho không hợp lệ", "@invalidStockLocation": {}, "invalidStockItem": "Kho hàng không hợp lệ", "@invalidStockItem": {}, + "invalidSupplierPart": "Sản phẩm nhà cung cấp không hợp lệ", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Tên người dùng / mật khẩu không hợp lệ", "@invalidUsernamePassword": {}, "issue": "Vấn đề", @@ -350,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "Vị trí mục đã có", "@itemInLocation": {}, + "itemDeleted": "Hàng hóa đã bị xóa", + "@itemDeleted": {}, "keywords": "Từ khóa", "@keywords": {}, "labelPrinting": "In nhãn mã vạch", @@ -370,6 +409,8 @@ "@lastUpdated": {}, "level": "Cấp độ", "@level": {}, + "lineItemAdd": "Thêm hạng mục", + "@lineItemAdd": {}, "lineItem": "Sản phẩm", "@lineItem": {}, "lineItems": "Sản phẩm", @@ -388,6 +429,12 @@ "@locationNotSet": {}, "locationUpdated": "Cập nhật vị trí kho hàng", "@locationUpdated": {}, + "login": "Đăng nhập", + "@login": {}, + "loginEnter": "Điền thông tin đăng nhập", + "@loginEnter": {}, + "loginEnterDetails": "Tên đăng nhập và mật khẩu không được lưu nội bộ", + "@loginEnterDetails": {}, "link": "Liên kết", "@link": {}, "lost": "Mất", @@ -438,6 +485,12 @@ "@orientationSystem": {}, "outstanding": "Nổi bật", "@outstanding": {}, + "outstandingOrderDetail": "Hiện đơn hàng nổi bật", + "@outstandingOrderDetail": {}, + "overdue": "Quá hạn", + "@overdue": {}, + "overdueDetail": "Hiện đơn hàng quá hạn", + "@overdueDetail": {}, "packaging": "Đóng gói", "@packaging": {}, "packageName": "Tên gói", @@ -478,6 +531,12 @@ "@partsStarredNone": {}, "partSuppliers": "Nhà cung cấp phụ kiện", "@partSuppliers": {}, + "partCategory": "Danh mục sản phẩm", + "@partCategory": {}, + "partCategoryTopLevel": "Danh mục sản phẩm cấp đầu", + "@partCategoryTopLevel": {}, + "partCategories": "Danh mục sản phẩm", + "@partCategories": {}, "partDetails": "Chi tiết phụ kiện", "@partDetails": {}, "partNotes": "Ghi chú phụ kiện", @@ -518,6 +577,8 @@ "@profileEdit": {}, "profileDelete": "Xóa cấu hình máy chủ", "@profileDelete": {}, + "profileLogout": "Thoát hồ sơ", + "@profileLogout": {}, "profileName": "Tên hồ sơ", "@profileName": {}, "profileNone": "Không có sẵn profile", @@ -640,9 +701,16 @@ }, "returned": "Trả lại", "@returned": {}, + "salesOrder": "Đơn hàng bán", + "@salesOrder": {}, "salesOrders": "Đơn đặt hàng", "@salesOrders": {}, + "salesOrderCreate": "Đơn hàng bán mới", "@saleOrderCreate": {}, + "salesOrderEdit": "Sửa đơn hàng bán", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Đơn hàng bán đã được cập nhật", + "@salesOrderUpdated": {}, "save": "Lưu lại", "@save": { "description": "Save" @@ -653,6 +721,12 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Quét mặt hàng này vào điểm bán", "@scanIntoLocationDetail": {}, + "scannerExternal": "Máy quét bên ngoài", + "@scannerExternal": {}, + "scannerExternalDetail": "Sử dụng máy quét bên ngoài để đọc mã vạch (chế độ nêm)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Quét sản phẩm đã nhận", + "@scanReceivedParts": {}, "search": "Tìm kiếm", "@search": { "description": "search" @@ -721,6 +795,8 @@ "@serverNotConnected": {}, "serverNotSelected": "Chưa chọn máy chủ", "@serverNotSelected": {}, + "shipped": "Đã vận chuyển", + "@shipped": {}, "sku": "Mã sản phẩm", "@sku": {}, "sounds": "Âm thanh", @@ -821,6 +897,8 @@ "@takePicture": {}, "targetDate": "Ngày", "@targetDate": {}, + "templatePart": "Sản phẩm mẫu cha", + "@templatePart": {}, "testName": "Kiểm tra tên", "@testName": {}, "testPassedOrFailed": "Kiểm thử thất bại", @@ -887,6 +965,8 @@ "@uploadSuccess": {}, "usedIn": "Sử dụng trong", "@usedIn": {}, + "usedInDetails": "Sự lắp ráp cần sản phẩm này", + "@usedInDetails": {}, "username": "Tên người dùng", "@username": {}, "usernameEmpty": "Tên người dùng không được để trống", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index d70b094..571de89 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -16,7 +16,7 @@ "@actions": { "description": "" }, - "actionsNone": "无可用操作", + "actionsNone": "没有可用的操作", "@actionsNone": {}, "add": "添加", "@add": { @@ -30,15 +30,15 @@ "@address": {}, "appAbout": "关于 InventTree", "@appAbout": {}, - "appCredits": "附加应用信用点", + "appCredits": "额外 app 凭据", "@appCredits": {}, "appDetails": "应用详情", "@appDetails": {}, - "appReleaseNotes": "显示应用发布说明", + "appReleaseNotes": "显示应用发布笔记", "@appReleaseNotes": {}, "appSettings": "应用设置", "@appSettings": {}, - "appSettingsDetails": "配置 InventTree 应用设置", + "appSettingsDetails": "配置 InventTree app 设置项", "@appSettingsDetails": {}, "attachments": "附件", "@attachments": {}, @@ -48,7 +48,7 @@ }, "attachmentNone": "找不到附件。", "@attachmentNone": {}, - "attachmentNoneDetail": "找不到附件。", + "attachmentNoneDetail": "未找到附件", "@attachmentNoneDetail": {}, "attachmentSelect": "选择附件", "@attachmentSelect": {}, @@ -62,52 +62,59 @@ "@barcodes": {}, "barcodeSettings": "条形码设置", "@barcodeSettings": {}, - "barcodeAssign": "分配条码", + "barcodeAssign": "分配条形码", "@barcodeAssign": {}, - "barcodeAssignDetail": "扫描自定义条形码进行分配", + "barcodeAssignDetail": "扫描定制条形码以分配", "@barcodeAssignDetail": {}, - "barcodeAssigned": "条码已分配", + "barcodeAssigned": "条形码已分配", "@barcodeAssigned": {}, "barcodeError": "条形码扫描出错", "@barcodeError": {}, - "barcodeInUse": "条码已经被分配", + "barcodeInUse": "条形码已经被分配", "@barcodeInUse": {}, - "barcodeMissingHash": "响应缺少条码哈希数据", + "barcodeMissingHash": "响应中缺少条形码的哈希数据", "@barcodeMissingHash": {}, - "barcodeNoMatch": "无匹配条码", + "barcodeNoMatch": "无匹配条形码", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "未分配条码", + "barcodeNotAssigned": "未分配条形码", "@barcodeNotAssigned": {}, - "barcodeReceivePart": "扫描条形码以接收部件", + "barcodeReceivePart": "扫描条形码以接收零件", "@barcodeReceivePart": {}, + "barcodeScanPaused": "条形码扫描已暂停", "@barodeScanPaused": {}, - "barcodeScanAssign": "扫描以分配条码", + "barcodeScanPause": "点击或按住以暂停扫描", + "@barcodeScanPause": {}, + "barcodeScanAssign": "扫描以分配条形码", "@barcodeScanAssign": {}, "barcodeScanController": "扫描仪输入", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "选择条码扫描输入源", + "barcodeScanControllerDetail": "选择条码枪的输入源", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "条形码扫描延迟", + "barcodeScanDelay": "条形码扫描延迟设置", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "条形码扫描之间的延迟", + "barcodeScanDelayDetail": "两次条形码扫描之间的延迟时间", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "扫描 InvenTree 条码", + "barcodeScanGeneral": "扫描 InvenTree 条形码", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "扫描库存物品到此位置", + "barcodeScanInItems": "将库存项扫描进这个位置", "@barcodeScanInItems": {}, "barcodeScanLocation": "扫描库存地点", "@barcodeScanLocation": {}, + "barcodeScanSingle": "单次扫描模式", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "每次扫描后暂停一下条码枪", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "已扫描至位置", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "未扫描到物品", "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "扫描库存项", "@barcodeScanItem": {}, - "barcodeTones": "扫码音调", + "barcodeTones": "条形码的音调", "@barcodeTones": {}, - "barcodeUnassign": "取消分配条码", + "barcodeUnassign": "取消分配条形码", "@barcodeUnassign": {}, - "barcodeUnknown": "无法识别条码", + "barcodeUnknown": "无法识别条形码", "@barcodeUnknown": {}, "batchCode": "批量编码", "@batchCode": {}, @@ -119,11 +126,11 @@ "@bomEnable": {}, "build": "生产", "@build": {}, - "building": "正在生成", + "building": "正在构建", "@building": {}, "cameraInternal": "内置相机", "@cameraInternal": {}, - "cameraInternalDetail": "使用内部摄像头读取条形码", + "cameraInternalDetail": "使用内置相机读取条形码", "@cameraInternalDetail": {}, "cancel": "取消", "@cancel": { @@ -131,13 +138,13 @@ }, "cancelOrder": "取消订单", "@cancelOrder": {}, - "category": "分类", + "category": "类别", "@category": {}, - "categoryCreate": "新建分类", + "categoryCreate": "新建类别", "@categoryCreate": {}, - "categoryCreateDetail": "新建商品类别", + "categoryCreateDetail": "新建零件类别", "@categoryCreateDetail": {}, - "categoryUpdated": "部件类别已更新", + "categoryUpdated": "零件类别已更新", "@categoryUpdated": {}, "company": "公司", "@company": {}, @@ -145,11 +152,11 @@ "@companyEdit": {}, "companyNoResults": "没有符合查询的公司", "@companyNoResults": {}, - "companyUpdated": "公司信息已更新", + "companyUpdated": "公司详情已更新", "@companyUpdated": {}, "companies": "公司", "@companies": {}, - "configureServer": "配置服务器设置", + "configureServer": "配置服务器的设置", "@configureServer": {}, "connectionRefused": "连接被拒绝", "@connectionRefused": {}, @@ -163,21 +170,25 @@ }, "credits": "致谢", "@credits": {}, + "customer": "客户", + "@customer": {}, "customers": "客户信息", "@customers": {}, + "customerReference": "客户指引", + "@customerReference": {}, "damaged": "破损", "@damaged": {}, - "darkMode": "暗色模式", + "darkMode": "暗黑模式", "@darkMode": {}, - "darkModeEnable": "启用暗色模式", + "darkModeEnable": "启用暗黑模式", "@darkModeEnable": {}, "delete": "删除", "@delete": {}, - "deleteFailed": "删除失败", + "deleteFailed": "删除操作失败", "@deleteFailed": {}, - "deletePart": "删除部件", + "deletePart": "删除零件", "@deletePart": {}, - "deletePartDetail": "从数据库中删除这个部件", + "deletePartDetail": "从数据库中删除此零件", "@deletePartDetail": {}, "deleteSuccess": "删除操作成功", "@deleteSuccess": {}, @@ -199,7 +210,7 @@ "@edit": { "description": "edit" }, - "editCategory": "编辑分类", + "editCategory": "编辑类别", "@editCategory": {}, "editLocation": "编辑位置", "@editLocation": {}, @@ -207,13 +218,13 @@ "@editNotes": {}, "editParameter": "编辑参数", "@editParameter": {}, - "editPart": "编辑部件", + "editPart": "编辑零件", "@editPart": { "description": "edit part" }, - "editItem": "编辑库存物品", + "editItem": "编辑库存项", "@editItem": {}, - "editLineItem": "编辑列表条目", + "editLineItem": "编辑行项目", "@editLineItem": {}, "enterPassword": "输入密码", "@enterPassword": {}, @@ -223,13 +234,13 @@ "@error": { "description": "Error" }, - "errorCreate": "创建数据库记录时出现了一个错误", + "errorCreate": "创建数据库条目时出错", "@errorCreate": {}, - "errorDelete": "删除数据库记录时出现了一个错误", + "errorDelete": "删除数据库条目时出错", "@errorDelete": {}, "errorDetails": "c w错误详情", "@errorDetails": {}, - "errorFetch": "从服务器获取数据时出现了一个错误", + "errorFetch": "从服务器获取数据时出错", "@errorFetch": {}, "errorUserRoles": "从服务器请求用户角色时出错", "@errorUserRoles": {}, @@ -247,47 +258,47 @@ "@feedbackError": {}, "feedbackSuccess": "反馈已提交", "@feedbackSuccess": {}, - "filterActive": "启用", + "filterActive": "已激活", "@filterActive": {}, - "filterActiveDetail": "显示启用部件", + "filterActiveDetail": "显示激活零件", "@filterActiveDetail": {}, "filterAssembly": "已装配", "@filterAssembly": {}, - "filterAssemblyDetail": "显示已装配的部件", + "filterAssemblyDetail": "显示已装配的零件", "@filterAssemblyDetail": {}, "filterComponent": "组件", "@filterComponent": {}, - "filterComponentDetail": "显示组件部分", + "filterComponentDetail": "显示元件零件", "@filterComponentDetail": {}, - "filterExternal": "外部的", + "filterExternal": "外部", "@filterExternal": {}, - "filterExternalDetail": "显示外部仓储地点的库存", + "filterExternalDetail": "显示外部仓库的库存", "@filterExternalDetail": {}, - "filterInStock": "库存充足", + "filterInStock": "有库存", "@filterInStock": {}, - "filterInStockDetail": "显示有库存的部分", + "filterInStockDetail": "显示有库存的零件", "@filterInStockDetail": {}, "filterSerialized": "已序列化", "@filterSerialized": {}, - "filterSerializedDetail": "显示序列化的库存物品", + "filterSerializedDetail": "显示已序列化的库存物品", "@filterSerializedDetail": {}, "filterTemplate": "模板", "@filterTemplate": {}, - "filterTemplateDetail": "显示模板部件", + "filterTemplateDetail": "显示模板零件", "@filterTemplateDetail": {}, "filterTrackable": "可追踪", "@filterTrackable": {}, - "filterTrackableDetail": "显示可跟踪部件", + "filterTrackableDetail": "显示可追踪的零件", "@filterTrackableDetail": {}, "filterVirtual": "虚拟", "@filterVirtual": {}, - "filterVirtualDetail": "显示虚拟部件", + "filterVirtualDetail": "显示虚拟零件", "@filterVirtualDetail": {}, "filteringOptions": "过滤选项", "@filteringOptions": {}, "formatException": "格式异常", "@formatException": {}, - "formatExceptionJson": "JSON数据格式异常", + "formatExceptionJson": "JSON 数据格式异常", "@formatExceptionJson": {}, "formError": "表单错误", "@formError": {}, @@ -304,9 +315,13 @@ "@homeShowPo": {}, "homeShowPoDescription": "在主屏幕上显示订单按钮", "@homeShowPoDescription": {}, - "homeShowSubscribed": "订阅的商品", + "homeShowSo": "显示销售订单", + "@homeShowSo": {}, + "homeShowSoDescription": "在主屏幕上显示销售订单按钮", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "已订阅的零件", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "在主屏幕上显示订阅的商品", + "homeShowSubscribedDescription": "在主屏幕上显示已订阅的零件", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "显示供应商", "@homeShowSuppliers": {}, @@ -314,37 +329,37 @@ "@homeShowSupplierDescription": {}, "homeShowManufacturers": "显示制造商", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "在主屏幕显示制造商按钮", + "homeShowManufacturersDescription": "在主屏幕上显示制造商按钮", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "显示顾客", + "homeShowCustomers": "显示客户", "@homeShowCustomers": {}, "homeShowCustomersDescription": "在主屏幕上显示客户按钮", "@homeShowCustomersDescription": {}, "imageUploadFailure": "图片上传失败", "@imageUploadFailure": {}, - "imageUploadSuccess": "图片上传", + "imageUploadSuccess": "图片已上传", "@imageUploadSuccess": {}, - "inactive": "非活跃的", + "inactive": "未激活", "@inactive": {}, - "inactiveDetail": "这一部分被标记为非活动部分", + "inactiveDetail": "此零件已被标为未激活", "@inactiveDetail": {}, "includeSubcategories": "包含子类别", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "显示子类别的结果", + "includeSubcategoriesDetail": "显示子类别中的结果", "@includeSubcategoriesDetail": {}, - "includeSublocations": "包括子地点", + "includeSublocations": "包括次级位置", "@includeSublocations": {}, - "includeSublocationsDetail": "显示子位置的结果", + "includeSublocationsDetail": "显示次级位置中的结果", "@includeSublocationsDetail": {}, - "incompleteDetails": "不完整的个人资料详细信息", + "incompleteDetails": "不完整的配置文件详细信息", "@incompleteDetails": {}, - "internalPartNumber": "内部部件号", + "internalPartNumber": "内部零件号", "@internalPartNumber": {}, "info": "信息", "@info": {}, - "inProduction": "正在生产", + "inProduction": "生产中的", "@inProduction": {}, - "inProductionDetail": "库存品正在生产", + "inProductionDetail": "该库存物品正在生产中", "@inProductionDetail": {}, "internalPart": "内部零件", "@internalPart": {}, @@ -352,15 +367,15 @@ "@invalidHost": {}, "invalidHostDetails": "提供的主机名无效", "@invalidHostDetails": {}, - "invalidPart": "无效部件", + "invalidPart": "无效零件", "@invalidPart": {}, - "invalidPartCategory": "无效部件分类", + "invalidPartCategory": "无效零件类别", "@invalidPartCategory": {}, - "invalidStockLocation": "无效库存位置", + "invalidStockLocation": "无效库存地点", "@invalidStockLocation": {}, "invalidStockItem": "无效库存项", "@invalidStockItem": {}, - "invalidSupplierPart": "无效的供应商部件", + "invalidSupplierPart": "无效的供应商零件", "@invalidSupplierPart": {}, "invalidUsernamePassword": "无效的用户名密码组合", "@invalidUsernamePassword": {}, @@ -372,6 +387,8 @@ "@issueOrder": {}, "itemInLocation": "物品已就位", "@itemInLocation": {}, + "itemDeleted": "项目已移除", + "@itemDeleted": {}, "keywords": "关键词", "@keywords": {}, "labelPrinting": "打印标签", @@ -392,11 +409,13 @@ "@lastUpdated": {}, "level": "级", "@level": {}, - "lineItem": "行条目", + "lineItemAdd": "添加行项目", + "@lineItemAdd": {}, + "lineItem": "行项目", "@lineItem": {}, - "lineItems": "行条目", + "lineItems": "行项目", "@lineItems": {}, - "lineItemUpdated": "行条目已更新", + "lineItemUpdated": "行项目已更新", "@lineItemUpdated": {}, "locateItem": "定位库存项", "@locateItem": {}, @@ -404,11 +423,11 @@ "@locateLocation": {}, "locationCreate": "新建仓储位置", "@locationCreate": {}, - "locationCreateDetail": "创建新库存位置", + "locationCreateDetail": "创建新库存地点", "@locationCreateDetail": {}, "locationNotSet": "没有指定仓储位置", "@locationNotSet": {}, - "locationUpdated": "库存位置已更新", + "locationUpdated": "库存地点已更新", "@locationUpdated": {}, "login": "登入", "@login": {}, @@ -466,57 +485,63 @@ "@orientationSystem": {}, "outstanding": "未完成", "@outstanding": {}, + "outstandingOrderDetail": "显示未完成的订单", + "@outstandingOrderDetail": {}, + "overdue": "逾期", + "@overdue": {}, + "overdueDetail": "显示逾期订单", + "@overdueDetail": {}, "packaging": "打包", "@packaging": {}, "packageName": "包名", "@packageName": {}, "parameters": "参数", "@parameters": {}, - "parametersSettingDetail": "显示商品参数", + "parametersSettingDetail": "显示零件参数", "@parametersSettingDetail": {}, - "parent": "父级", + "parent": "上级", "@parent": {}, - "parentCategory": "父类别", + "parentCategory": "上级类别", "@parentCategory": {}, - "parentLocation": "父位置", + "parentLocation": "上级地点", "@parentLocation": {}, - "part": "部件", + "part": "零件", "@part": { "description": "Part (single)" }, - "partCreate": "新商品", + "partCreate": "新零件", "@partCreate": {}, - "partCreateDetail": "在此类别中创建新的商品", + "partCreateDetail": "在此类别中创建新的零件", "@partCreateDetail": {}, - "partEdited": "商品已更新", + "partEdited": "零件已更新", "@partEdited": {}, - "parts": "部件", + "parts": "零件", "@parts": { "description": "Part (multiple)" }, - "partsNone": "无商品", + "partsNone": "无零件", "@partsNone": {}, - "partNoResults": "没有匹配查询的商品", + "partNoResults": "没有匹配查询的零件", "@partNoResults": {}, - "partSettings": "商品设置", + "partSettings": "零件设置", "@partSettings": {}, - "partsStarred": "订阅的商品", + "partsStarred": "订阅的零件", "@partsStarred": {}, "partsStarredNone": "没有可用的带星号零件", "@partsStarredNone": {}, - "partSuppliers": "配件供货商", + "partSuppliers": "零件供应商", "@partSuppliers": {}, - "partCategory": "部件分类", + "partCategory": "零件类别", "@partCategory": {}, "partCategoryTopLevel": "上一级零件类别", "@partCategoryTopLevel": {}, - "partCategories": "部件分类", + "partCategories": "零件类别", "@partCategories": {}, - "partDetails": "部件详情", + "partDetails": "零件详情", "@partDetails": {}, - "partNotes": "部件注释", + "partNotes": "零件注释", "@partNotes": {}, - "partStock": "部件库存", + "partStock": "零件库存", "@partStock": { "description": "part stock" }, @@ -524,7 +549,7 @@ "@password": {}, "passwordEmpty": "密码不能为空", "@passwordEmpty": {}, - "permissionAccountDenied": "您的帐户没有执行此操作所需的权限", + "permissionAccountDenied": "您的账户没有执行此操作所需的权限", "@permissionAccountDenied": {}, "permissionRequired": "需要授权:", "@permissionRequired": {}, @@ -570,13 +595,13 @@ "@projectCode": {}, "purchaseOrder": "采购订单", "@purchaseOrder": {}, - "purchaseOrderCreate": "新订购单", + "purchaseOrderCreate": "新采购订单", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "编辑采购订单", "@purchaseOrderEdit": {}, "purchaseOrders": "采购订单", "@purchaseOrders": {}, - "purchaseOrderUpdated": "订单已更新", + "purchaseOrderUpdated": "采购订单已更新", "@purchaseOrderUpdated": {}, "purchasePrice": "采购价格", "@purchasePrice": {}, @@ -602,7 +627,7 @@ "@receivedFilterDetail": {}, "receiveItem": "接收条目", "@receiveItem": {}, - "receivedItem": "收到的库存物品", + "receivedItem": "收到的库存项", "@receivedItem": {}, "reference": "参考", "@reference": {}, @@ -624,7 +649,7 @@ }, "reportBug": "反馈问题", "@reportBug": {}, - "reportBugDescription": "提交 bug 报告 (需要 GitHub 帐户)", + "reportBugDescription": "提交 bug 报告 (需要 GitHub 账户)", "@reportBugDescription": {}, "results": "结果", "@results": {}, @@ -676,14 +701,21 @@ }, "returned": "已退回", "@returned": {}, + "salesOrder": "销售订单", + "@salesOrder": {}, "salesOrders": "销售订单", "@salesOrders": {}, + "salesOrderCreate": "新的销售订单", "@saleOrderCreate": {}, + "salesOrderEdit": "编辑销售订单", + "@salesOrderEdit": {}, + "salesOrderUpdated": "销售订单已更新", + "@salesOrderUpdated": {}, "save": "保存", "@save": { "description": "Save" }, - "scanBarcode": "扫描条码", + "scanBarcode": "扫描条形码", "@scanBarcode": {}, "scanIntoLocation": "已扫描至位置", "@scanIntoLocation": {}, @@ -693,7 +725,7 @@ "@scannerExternal": {}, "scannerExternalDetail": "使用外部扫描仪读取条形码 (分割模式)", "@scannerExternalDetail": {}, - "scanReceivedParts": "扫描收到的部件", + "scanReceivedParts": "扫描收到的零件", "@scanReceivedParts": {}, "search": "搜索", "@search": { @@ -703,7 +735,7 @@ "@searching": {}, "searchLocation": "搜索仓储位置", "@searchLocation": {}, - "searchParts": "搜索部件", + "searchParts": "搜索零件", "@searchParts": {}, "searchStock": "搜索库存", "@searchStock": {}, @@ -763,7 +795,9 @@ "@serverNotConnected": {}, "serverNotSelected": "未选定服务器", "@serverNotSelected": {}, - "sku": "存货单位(SKU)", + "shipped": "已配送", + "@shipped": {}, + "sku": "库存单位 (SKU)", "@sku": {}, "sounds": "声音", "@sounds": {}, @@ -789,25 +823,25 @@ "@stockItems": {}, "stockItemCreate": "新建库存项", "@stockItemCreate": {}, - "stockItemCreateDetail": "在此位置创建新的库存项目", + "stockItemCreateDetail": "在此位置创建新的库存项", "@stockItemCreateDetail": {}, - "stockItemDelete": "删除库存项目", + "stockItemDelete": "删除库存项", "@stockItemDelete": {}, "stockItemDeleteConfirm": "确定要删除此库存项吗?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "无法删除库存项目", + "stockItemDeleteFailure": "无法删除库存项", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "库存项目已删除", + "stockItemDeleteSuccess": "库存项已删除", "@stockItemDeleteSuccess": {}, "stockItemHistory": "库存历史记录", "@stockItemHistory": {}, "stockItemHistoryDetail": "显示历史库存追踪信息", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "已转移的库存物品", + "stockItemTransferred": "已转移的库存项", "@stockItemTransferred": {}, - "stockItemUpdated": "库存项目已更新", + "stockItemUpdated": "库存项已更新", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "没有可用的库存项目", + "stockItemsNotAvailable": "没有可用的库存项", "@stockItemsNotAvailable": {}, "stockItemNotes": "库存项注释", "@stockItemNotes": {}, @@ -815,13 +849,13 @@ "@stockItemUpdateSuccess": {}, "stockItemUpdateFailure": "库存项更新失败", "@stockItemUpdateFailure": {}, - "stockLocation": "库存位置", + "stockLocation": "库存地点", "@stockLocation": { "description": "stock location" }, - "stockLocations": "库存位置", + "stockLocations": "库存地点", "@stockLocations": {}, - "stockTopLevel": "顶级库存位置", + "stockTopLevel": "顶级库存地点", "@stockTopLevel": {}, "strictHttps": "使用严格的 HTTPS", "@strictHttps": {}, @@ -841,29 +875,29 @@ "@sublocationNoneDetail": {}, "submitFeedback": "提交反馈", "@submitFeedback": {}, - "suppliedParts": "供应商商品", + "suppliedParts": "供应商零件", "@suppliedParts": {}, "supplier": "供应商", "@supplier": {}, - "supplierPart": "供应商商品", + "supplierPart": "供应商零件", "@supplierPart": {}, - "supplierPartEdit": "编辑供应商商品", + "supplierPartEdit": "编辑供应商零件", "@supplierPartEdit": {}, - "supplierPartNumber": "供应商配件编号", + "supplierPartNumber": "供应商零件编号", "@supplierPartNumber": {}, - "supplierPartUpdated": "供应商部件已更新", + "supplierPartUpdated": "供应商零件已更新", "@supplierPartUpdated": {}, - "supplierParts": "供应商商品", + "supplierParts": "供应商零件", "@supplierParts": {}, "suppliers": "供应商", "@suppliers": {}, - "supplierReference": "供应商参号:", + "supplierReference": "供应商参考", "@supplierReference": {}, "takePicture": "拍照", "@takePicture": {}, "targetDate": "预计日期", "@targetDate": {}, - "templatePart": "父模板部件", + "templatePart": "上级模板零件", "@templatePart": {}, "testName": "测试名", "@testName": {}, @@ -909,9 +943,9 @@ }, "transferStockDetail": "将物品转移到另一个位置", "@transferStockDetail": {}, - "transferStockLocation": "转移库存位置", + "transferStockLocation": "转移库存地点", "@transferStockLocation": {}, - "transferStockLocationDetail": "将此存货位置转移到另一个存货位置", + "transferStockLocationDetail": "将此库存地点转移到另一个", "@transferStockLocationDetail": {}, "translate": "转移", "@translate": {}, @@ -931,7 +965,7 @@ "@uploadSuccess": {}, "usedIn": "用途", "@usedIn": {}, - "usedInDetails": "需要此部分的组件。", + "usedInDetails": "需要此零件的装配体", "@usedInDetails": {}, "username": "用户名", "@username": {}, @@ -949,7 +983,7 @@ "@variants": {}, "version": "版本", "@version": {}, - "viewSupplierPart": "查看供应商部件", + "viewSupplierPart": "查看供应商零件", "@viewSupplierPart": {}, "website": "网站", "@website": {} From 0e658febe2587133f1bb678dd044727bf770e712 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 17 Apr 2024 21:26:09 +1000 Subject: [PATCH 459/746] New Crowdin updates (#483) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Czech) --- lib/l10n/bg_BG/app_bg_BG.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/cs_CZ/app_cs_CZ.arb | 14 + lib/l10n/da_DK/app_da_DK.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/de_DE/app_de_DE.arb | 14 + lib/l10n/el_GR/app_el_GR.arb | 969 ++++++++++++++++++++++++++++++++- lib/l10n/es_ES/app_es_ES.arb | 156 ++++++ lib/l10n/es_MX/app_es_MX.arb | 72 +++ lib/l10n/fa_IR/app_fa_IR.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/fi_FI/app_fi_FI.arb | 524 ++++++++++++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 14 + lib/l10n/he_IL/app_he_IL.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/hi_IN/app_hi_IN.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/hu_HU/app_hu_HU.arb | 14 + lib/l10n/id_ID/app_id_ID.arb | 981 ++++++++++++++++++++++++++++++++++ lib/l10n/it_IT/app_it_IT.arb | 126 +++++ lib/l10n/ja_JP/app_ja_JP.arb | 293 ++++++++++ lib/l10n/ko_KR/app_ko_KR.arb | 901 +++++++++++++++++++++++++++++++ lib/l10n/lv_LV/app_lv_LV.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/nl_NL/app_nl_NL.arb | 72 +++ lib/l10n/no_NO/app_no_NO.arb | 14 + lib/l10n/pl_PL/app_pl_PL.arb | 235 ++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 14 + lib/l10n/pt_PT/app_pt_PT.arb | 801 +++++++++++++++++++++++++++- lib/l10n/ru_RU/app_ru_RU.arb | 14 + lib/l10n/sk_SK/app_sk_SK.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/sl_SI/app_sl_SI.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/sr_CS/app_sr_CS.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/sv_SE/app_sv_SE.arb | 813 +++++++++++++++++++++++++++- lib/l10n/th_TH/app_th_TH.arb | 999 ++++++++++++++++++++++++++++++++++- lib/l10n/tr_TR/app_tr_TR.arb | 108 ++++ lib/l10n/vi_VN/app_vi_VN.arb | 14 + lib/l10n/zh_CN/app_zh_CN.arb | 16 +- lib/l10n/zh_TW/app_zh_TW.arb | 814 +++++++++++++++++++++++++++- 33 files changed, 16966 insertions(+), 17 deletions(-) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 0087450..83726ea 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -1,7 +1,1004 @@ { "@@locale": "bg", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 8a826fc..3bd17c3 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Informace o aplikaci", "@appDetails": {}, + "allocated": "Přiděleno", + "@allocated": {}, + "allocateStock": "Přidělit zásoby", + "@allocateStock": {}, "appReleaseNotes": "Zobrazit poznámky k verzi aplikace", "@appReleaseNotes": {}, "appSettings": "Nastavení aplikace", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Čárový kód nebyl přiřazen", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Naskenovat čárový kód", + "@barcodeScanPart": {}, "barcodeReceivePart": "Naskenovat čárový kód pro získání dílu", "@barcodeReceivePart": {}, "barcodeScanPaused": "Skenování čárových kódů pozastaveno", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Žádné díly", "@partsNone": {}, "partNoResults": "Žádné díly neodpovídají dotazu", @@ -717,6 +725,8 @@ }, "scanBarcode": "Skenovat čarový kód", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Skenovat umístění", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Skenovat tuto položku do umístění", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Server není vybrán", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Odesláno", "@shipped": {}, "sku": "Číslo zboží (SKU)", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 8c7ae32..3150f91 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -1,7 +1,1004 @@ { "@@locale": "da", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 096ca43..ebcf0a8 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "App-Informationen", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "App-Versionshinweise anzeigen", "@appReleaseNotes": {}, "appSettings": "App-Einstellungen", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode nicht zugewiesen", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Barcode scannen um Teil zu empfangen", "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode-Scannen angehalten", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Keine Teile", "@partsNone": {}, "partNoResults": "Keine Teile entsprechen der Anfrage", @@ -717,6 +725,8 @@ }, "scanBarcode": "Barcode scannen", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "In Lagerorten buchen", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Artikel per Scan zu Lagerort hinzufügen", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Versandt", "@shipped": {}, "sku": "Bestellnummer", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index a7e442f..484a908 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -4,34 +4,1001 @@ "@appTitle": { "description": "InvenTree application title string" }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, "accountDetails": "Λεπτομέρειες Λογαριασμού", "@accountDetails": {}, "actions": "Ενέργειες", "@actions": { "description": "" }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, "address": "Διεύθυνση", "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, "appSettings": "Ρυθμίσεις Εφαρμογής", "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, "attachments": "Συνημμένα", "@attachments": {}, "attachImage": "Επισύναψη Εικόνας", "@attachImage": { "description": "Attach an image" }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, "attachmentNoneDetail": "Δεν βρέθηκαν συνημμένα", "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, "attention": "Προσοχή", "@attention": {}, + "available": "Available", + "@available": {}, "availableStock": "Διαθέσιμο Απόθεμα", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, "barcodeAssign": "Αντιστοίχιση Barcode", "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, "categoryCreate": "Νέα Κατηγορία", "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 025a854..cf36269 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Detalles de la app", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, "appSettings": "Ajustes de aplicación", @@ -54,8 +58,14 @@ "@attachmentSelect": {}, "attention": "Atención", "@attention": {}, + "available": "Available", + "@available": {}, "availableStock": "Inventario Disponible", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, "barcodeAssign": "Asignar código de barras", "@barcodeAssign": {}, "barcodeAssignDetail": "Escanear código de barras personalizado para asignar", @@ -72,15 +82,34 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escanear un código de barras de InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Escanear artículos de inventario en esta ubicación", "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear a la ubicación de Inventario", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artículo no escaneado en", @@ -105,10 +134,16 @@ "@build": {}, "building": "Construyendo", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, "category": "Categoria", "@category": {}, "categoryCreate": "Nueva Categoría", @@ -141,10 +176,18 @@ }, "credits": "Créditos", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Clientes", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, "delete": "Eliminar", "@delete": {}, "deleteFailed": "Operación de borrado fallida", @@ -179,12 +222,16 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "Editar Pieza", "@editPart": { "description": "edit part" }, "editItem": "Editar artículo de stock", "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, "enterPassword": "Introduzca contraseña", "@enterPassword": {}, "enterUsername": "Introduzca su nombre de usuario", @@ -201,6 +248,10 @@ "@errorDetails": {}, "errorFetch": "Error obteniendo datos del servidor", "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, "errorReporting": "Reporte de errores", "@errorReporting": {}, "errorReportUpload": "Subir Reportes de Error", @@ -225,6 +276,10 @@ "@filterComponent": {}, "filterComponentDetail": "Mostrar piezas del componente", "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "En Existencia", "@filterInStock": {}, "filterInStockDetail": "Mostrar piezas que tienen existencias", @@ -266,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Piezas Destacadas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar piezas destacadas en la pantalla de inicio", @@ -308,6 +367,8 @@ "@inProduction": {}, "inProductionDetail": "El artículo de inventario está en producción", "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, "invalidHost": "Nombre de host no válido", "@invalidHost": {}, "invalidHostDetails": "Este nombre de host no es válido", @@ -320,14 +381,26 @@ "@invalidStockLocation": {}, "invalidStockItem": "Artículo de stock inválido", "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación de nombre de usuario / contraseña no válida", "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, "issueDate": "Fecha de problema", "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Palabras claves", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, "labelTemplate": "Plantilla de etiqueta", "@labelTemplate": {}, "language": "Idioma", @@ -342,10 +415,14 @@ "@lastUpdated": {}, "level": "Nivel", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Artículo del pedido", "@lineItem": {}, "lineItems": "Ítems de línea", "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, "locateItem": "Localizar artículo de stock", "@locateItem": {}, "locateLocation": "Localizar ubicación de stock", @@ -358,10 +435,20 @@ "@locationNotSet": {}, "locationUpdated": "Ubicación de stock actualizada", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "Enlace", "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, "manufacturers": "Fabricantes", "@manufacturers": {}, "missingData": "Faltan datos", @@ -392,6 +479,24 @@ "@onOrder": {}, "onOrderDetails": "Artículos actualmente en pedido", "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Empaquetado", "@packaging": {}, "packageName": "Nombre del paquete", @@ -420,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Sin piezas", "@partsNone": {}, "partNoResults": "No hay piezas que coincidan", @@ -478,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Borrar perfil del servidor", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Nombre de Perfil", "@profileName": {}, "profileNone": "No hay perfiles disponibles", @@ -490,8 +599,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Toca para crear o seleccionar un perfil", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, "purchaseOrders": "Ordenes de compra", @@ -518,6 +631,8 @@ "@queryNoResults": {}, "received": "Recibido", "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, "receiveItem": "Artículo recibido", "@receiveItem": {}, "receivedItem": "Artículo de Stock recibido", @@ -594,19 +709,34 @@ }, "returned": "Devuelto", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Guardar", "@save": { "description": "Save" }, "scanBarcode": "Escanear código de barras", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Escanear en la ubicación", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Escanear este item en la ubicación", "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Buscar", "@search": { "description": "search" @@ -631,6 +761,8 @@ "@send": {}, "serialNumber": "Número de serie", "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, "server": "Servidor", "@server": {}, "serverAddress": "Dirección del servidor", @@ -673,6 +805,14 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Sonidos", "@sounds": {}, "soundOnBarcodeAction": "Reproducir tono audible en la acción de código de barras", @@ -753,6 +893,16 @@ "@suppliedParts": {}, "supplier": "Proveedor", "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, "suppliers": "Proveedores", "@suppliers": {}, "supplierReference": "Referencia del proveedor", @@ -773,6 +923,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, "testResultAdd": "Añadir Resultado de Prueba", "@testResultAdd": {}, "testResultNone": "No hay resultados de la prueba", @@ -793,6 +945,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Falta el token de acceso de la respuesta", "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" @@ -811,6 +965,8 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, "units": "Unidades", "@units": {}, "unknownResponse": "Respuesta desconocida", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index ad7ad4e..c72542f 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Detalles de la app", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, "appSettings": "Ajustes de aplicación", @@ -78,9 +82,20 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Retraso de escaneo de código de barras", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Retraso entre escaneos de código de barras", @@ -91,6 +106,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear ubicación de Inventario", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artículo no escaneado en", @@ -115,6 +134,10 @@ "@build": {}, "building": "Construyendo", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" @@ -153,8 +176,12 @@ }, "credits": "Créditos", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Clientes", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, "darkMode": "Modo Oscuro", @@ -294,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Partes Suscritas", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostrar las partes suscritas en la página principal", @@ -362,6 +393,8 @@ "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Palabras claves", "@keywords": {}, "labelPrinting": "Impresión de etiquetas", @@ -382,6 +415,8 @@ "@lastUpdated": {}, "level": "Nivel", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Artículo del pedido", "@lineItem": {}, "lineItems": "Artículos de Línea", @@ -400,6 +435,12 @@ "@locationNotSet": {}, "locationUpdated": "Ubicación de inventario actualizada", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "Vincular", "@link": {}, "lost": "Perdido", @@ -450,6 +491,12 @@ "@orientationSystem": {}, "outstanding": "Pendiente", "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Embalaje", "@packaging": {}, "packageName": "Nombre de Paquete", @@ -478,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Sin Partes", "@partsNone": {}, "partNoResults": "No hay partes que coincidan", @@ -536,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Eliminar perfil del servidor", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Nombre de perfil", "@profileName": {}, "profileNone": "No hay perfiles disponibles", @@ -658,19 +709,34 @@ }, "returned": "Devuelto", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Guardar", "@save": { "description": "Save" }, "scanBarcode": "Escanear código de barras", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Escanear a la ubicación", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Escanear este artículo en su ubicación", "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Buscar", "@search": { "description": "search" @@ -739,6 +805,12 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, "sku": "SKU", "@sku": {}, "sounds": "Sonidos", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index e62cd93..5f61ecd 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,7 +1,1004 @@ { "@@locale": "fa", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 2b29640..53e6818 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -30,8 +30,14 @@ "@address": {}, "appAbout": "Tietoja InvenTree:stä", "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, "appDetails": "Sovelluksen tiedot", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Näytä sovelluksen julkaisutiedot", "@appReleaseNotes": {}, "appSettings": "Sovelluksen asetukset", @@ -54,21 +60,84 @@ "@attention": {}, "available": "Saatavilla", "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, "barcodes": "Viivakoodit", "@barcodes": {}, "barcodeSettings": "Viivakoodi Asetukset", "@barcodeSettings": {}, "barcodeAssign": "Aseta viivakoodi", "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, "barcodeAssigned": "Viivakoodi asetettu", "@barcodeAssigned": {}, "barcodeError": "Viivakoodin skannausvirhe", "@barcodeError": {}, "barcodeInUse": "Viivakoodi on jo käytössä", "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, "barcodeUnknown": "Viivakoodia ei tunnistettu", "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Peruuta", "@cancel": { "description": "Cancel" @@ -79,10 +148,16 @@ "@category": {}, "categoryCreate": "Uusi kategoria", "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, "company": "Yritys", "@company": {}, "companyEdit": "Muokkaa yritystä", "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, "companyUpdated": "Yrityksen tiedot päivitetty", "@companyUpdated": {}, "companies": "Yritykset", @@ -91,8 +166,22 @@ "@configureServer": {}, "connectionRefused": "Yhteys evätty", "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Asiakkaat", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Vahingoittunut", "@damaged": {}, "darkMode": "Tumma tila", @@ -139,6 +228,8 @@ "@editPart": { "description": "edit part" }, + "editItem": "Edit Stock Item", + "@editItem": {}, "editLineItem": "Muokkaa listan riviä", "@editLineItem": {}, "enterPassword": "Syötä salasana", @@ -155,6 +246,12 @@ "@errorDelete": {}, "errorDetails": "Virheen tiedot", "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, "errorReporting": "Virheen raportointi", "@errorReporting": {}, "errorReportUpload": "Lähetä virheraportit", @@ -169,12 +266,48 @@ "@feedbackSuccess": {}, "filterActive": "Aktiivinen", "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, "filterComponent": "Komponentti", "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "Varastossa", "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, "filterVirtual": "Virtuaalinen", "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, "history": "Historia", "@history": { "description": "history" @@ -182,38 +315,148 @@ "home": "Koti", "@homeScreen": {}, "homeScreen": "Aloitusnäyttö", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, "internalPartNumber": "Sisäinen osanumero", "@internalPartNumber": {}, + "info": "Info", + "@info": {}, "inProduction": "Tuotannossa", "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, "invalidHost": "Virheellinen isäntänimi", "@invalidHost": {}, "invalidHostDetails": "Annettu isäntänimi ei kelpaa", "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Virheellinen käyttäjätunnuksen / salasanan yhdistelmä", "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Avainsanat", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, "language": "Kieli", "@language": {}, "languageDefault": "Järjestelmän oletuskieli", "@languageDefault": {}, "languageSelect": "Valitse kieli", "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, "lastUpdated": "Päivitetty viimeksi", "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, "locationCreate": "Uusi sijainti", "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, "locationNotSet": "Sijaintia ei ole määritetty", "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, "manufacturer": "Valmistaja", "@manufacturer": {}, "manufacturers": "Valmistajat", "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, "name": "Nimi", "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, "notes": "Merkinnät", "@notes": { "description": "Notes" @@ -222,10 +465,52 @@ "@notifications": {}, "notificationsEmpty": "Ei lukemattomia ilmoituksia", "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, "noResults": "Ei tuloksia", "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, "numberInvalid": "Virheellinen numero", "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, "part": "Osa", "@part": { "description": "Part (single)" @@ -240,16 +525,34 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Ei osia", "@partsNone": {}, "partNoResults": "Ei hakua vastaavia osia", "@partNoResults": {}, "partSettings": "Osan asetukset", "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, "partDetails": "Osan tiedot", "@partDetails": {}, "partNotes": "Osan muistiinpanot", "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, "password": "Salasana", "@password": {}, "passwordEmpty": "Salasana ei voi olla tyhjä", @@ -258,12 +561,20 @@ "@permissionAccountDenied": {}, "permissionRequired": "Käyttöoikeus vaaditaan", "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, "plugin": "Laajennus", "@plugin": {}, "pluginPrinter": "Tulostin", "@pluginPrinter": {}, "pluginSupport": "Laajennusten tuki käytössä", "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, "profile": "Profiili", "@profile": {}, "profileAdd": "Lisää palvelinprofiili", @@ -274,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Poista palvelinprofiili", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Profiilin nimi", "@profileName": {}, "profileNone": "Profiileja ei saatavilla", @@ -286,6 +599,20 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Napauta luodaksesi tai valitaksesi profiilin", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, "quantity": "Määrä", "@quantity": { "description": "Quantity" @@ -298,10 +625,18 @@ "@quantityInvalid": {}, "quantityPositive": "Määrän on oltava positiivinen", "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, "received": "Vastaanotettu", "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, "receiveItem": "Vastaanota tuote", "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, "reference": "Viite", "@reference": {}, "refresh": "Päivitä", @@ -316,33 +651,100 @@ "@remove": { "description": "remove" }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, "reportBug": "Ilmoita virheestä", "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, "results": "Tulokset", "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, "required": "Vaaditaan", "@required": { "description": "This field is required" }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, "response403": "Lupa evätty", "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, "response500": "Palvelimen sisäinen virhe", "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, "response503": "Palvelu ei ole saatavilla", "@response503": {}, "response504": "Yhdyskäytävän aikakatkaisu", "@response504": {}, "response505": "HTTP-versiota ei tueta", "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, "responseUnknown": "Tuntematon vastaus", "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Tallenna", "@save": { "description": "Save" }, "scanBarcode": "Skannaa viivakoodi", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, "searchParts": "Etsi osia", "@searchParts": {}, "searchStock": "Etsi varastosta", @@ -397,12 +799,26 @@ "@serverStart": {}, "settings": "Asetukset", "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, "serverNotSelected": "Palvelinta ei ole valittu", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, "sku": "SKU", "@sku": {}, "sounds": "Äänet", "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, "status": "Tila", "@status": {}, "statusCode": "Tilakoodi", @@ -411,6 +827,8 @@ "@stock": { "description": "stock" }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, "stockItem": "Varastotuote", "@stockItem": { "description": "stock item title" @@ -419,12 +837,20 @@ "@stockItems": {}, "stockItemCreate": "Uusi varastotuote", "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, "stockItemDelete": "Poista varastotuote", "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, "stockItemDeleteSuccess": "Varastotuote poistettu", "@stockItemDeleteSuccess": {}, "stockItemHistory": "Varastohistoria", "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, "stockItemTransferred": "Varastotuote siirretty", "@stockItemTransferred": {}, "stockItemUpdated": "Varastotuote päivitetty", @@ -443,24 +869,118 @@ }, "stockLocations": "Varastosijainnit", "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, "strictHttps": "Käytä tiukkaa HTTPS:ää", "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, "supplier": "Toimittaja", "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, "takePicture": "Ota kuva", "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, "timeout": "Aikakatkaisu", "@timeout": { "description": "" }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, "transfer": "Siirrä", "@transfer": { "description": "transfer" }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, "translate": "Käännä", "@translate": {}, "translateHelp": "Auta kääntämään InvenTree-sovellusta", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, "username": "Käyttäjätunnus", "@username": {}, "usernameEmpty": "Käyttäjätunnus ei voi olla tyhjä", @@ -473,8 +993,12 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Arvo vaaditaan", "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, "version": "Versio", "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, "website": "Sivusto", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index fa5fce3..7cf5a4c 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Détails de l'application", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Afficher les notes de version de l'application", "@appReleaseNotes": {}, "appSettings": "Réglages de l'application", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Code-barres non assigné", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Scannez le code-barres pour recevoir la pièce", "@barcodeReceivePart": {}, "barcodeScanPaused": "Scan de code-barres en pause", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Aucune pièces", "@partsNone": {}, "partNoResults": "Pas de pièces correspondant à la requête", @@ -717,6 +725,8 @@ }, "scanBarcode": "Scanner un code-barres", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Scanner vers l'emplacement", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scannez cet élément à l'emplacement", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Serveur non sélectionné", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Expédié", "@shipped": {}, "sku": "UGS", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 7882200..fec5213 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -1,7 +1,1004 @@ { "@@locale": "he", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 9d605f6..17cb49d 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -1,7 +1,1004 @@ { "@@locale": "hi", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index a3c2620..320116f 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "App részletek", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Kiadási közlemények", "@appReleaseNotes": {}, "appSettings": "Alkalmazásbeállítások", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Olvasd le a vonalkódot a bevételezéshez", "@barcodeReceivePart": {}, "barcodeScanPaused": "Vonalkód olvasás megállítva", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Nincsenek alkatrészek", "@partsNone": {}, "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", @@ -717,6 +725,8 @@ }, "scanBarcode": "Vonalkód beolvasása", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Beolvasás helyre", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Készlet bevételezése erre a helyre", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Kiszállítva", "@shipped": {}, "sku": "SKU", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index c70fee0..1c1ee8f 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -1,23 +1,1004 @@ { "@@locale": "id", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, "imageUploadSuccess": "Gambar telah diunggah", "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Simpan", "@save": { "description": "Save" }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Suara", "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, "status": "Status", "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, "testResultUploadPass": "Hasil tes telah diunggah", "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, "uploadSuccess": "Berkas telah diunggah", "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, "website": "Situs", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index d0176e2..5e6e2b3 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Dettagli App", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Mostra le note di rilascio dell'app", "@appReleaseNotes": {}, "appSettings": "Impostazioni App", @@ -54,8 +58,14 @@ "@attachmentSelect": {}, "attention": "Attenzione", "@attention": {}, + "available": "Available", + "@available": {}, "availableStock": "Giacenza Disponibile", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, "barcodeAssign": "Assegna Codice A Barre", "@barcodeAssign": {}, "barcodeAssignDetail": "Scansiona codice a barre personalizzato da assegnare", @@ -72,15 +82,34 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Codice a barre non assegnato", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Scansiona per assegnare codice a barre", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scansiona gli elementi in magazzino in questa ubicazione", "@barcodeScanInItems": {}, "barcodeScanLocation": "Scansiona Ubicazione magazzino", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Scansionato nell'ubicazione", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", @@ -105,6 +134,10 @@ "@build": {}, "building": "In Costruzione", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Annulla", "@cancel": { "description": "Cancel" @@ -143,8 +176,12 @@ }, "credits": "Riconoscimenti", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Clienti", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Danneggiato", "@damaged": {}, "darkMode": "Modalità Scura", @@ -185,6 +222,8 @@ "@editLocation": {}, "editNotes": "Modifica Note", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "Modifica Articolo", "@editPart": { "description": "edit part" @@ -237,6 +276,10 @@ "@filterComponent": {}, "filterComponentDetail": "Mostra componenti articoli", "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "In Giacenza", "@filterInStock": {}, "filterInStockDetail": "Mostra articoli che sono in giacenza", @@ -278,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Articoli Sottoscritti", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Mostra gli articoli sottoscritti sulla schermata home", @@ -346,8 +393,14 @@ "@issueOrder": {}, "itemInLocation": "Elemento già in posizione", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Parole Chiave", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, "labelTemplate": "Modello Etichetta", "@labelTemplate": {}, "language": "Lingua", @@ -362,6 +415,8 @@ "@lastUpdated": {}, "level": "Livello", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Elemento Riga", "@lineItem": {}, "lineItems": "Elementi riga", @@ -380,10 +435,20 @@ "@locationNotSet": {}, "locationUpdated": "Ubicazione di magazzino aggiornata", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "Collegamento", "@link": {}, "lost": "Perso", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, "manufacturers": "Produttori", "@manufacturers": {}, "missingData": "Dati mancanti", @@ -414,6 +479,24 @@ "@onOrder": {}, "onOrderDetails": "Articoli attualmente in ordine", "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Confezionamento", "@packaging": {}, "packageName": "Nome pacchetto", @@ -442,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Nessun Articolo", "@partsNone": {}, "partNoResults": "Nessun articolo corrispondente alla ricerca", @@ -500,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Elimina Profilo Del Server", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Nome Profilo", "@profileName": {}, "profileNone": "Nessun profilo disponibile", @@ -512,8 +599,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Tocca per creare o selezionare un profilo", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, "purchaseOrder": "Ordine d'acquisto", "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifica ordine d'acquisto", "@purchaseOrderEdit": {}, "purchaseOrders": "Ordini d'acquisto", @@ -540,6 +631,8 @@ "@queryNoResults": {}, "received": "Ricevuto", "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, "receiveItem": "Ricevi Articolo", "@receiveItem": {}, "receivedItem": "Elemento del magazzino ricevuto", @@ -616,19 +709,34 @@ }, "returned": "Restituito", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Ordini di vendita", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Salva", "@save": { "description": "Save" }, "scanBarcode": "Scansiona codice a barre", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Scansiona nell'ubicazione", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scansiona questo elemento nell'ubicazione", "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Cerca", "@search": { "description": "search" @@ -653,6 +761,8 @@ "@send": {}, "serialNumber": "Numero seriale", "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, "server": "Server", "@server": {}, "serverAddress": "Indirizzo del server", @@ -695,6 +805,14 @@ "@serverNotConnected": {}, "serverNotSelected": "Server non selezionato", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Audio", "@sounds": {}, "soundOnBarcodeAction": "Riproduci un tono sonoro all'azione del codice a barre", @@ -779,6 +897,8 @@ "@supplierPart": {}, "supplierPartEdit": "Modifica Fornitore Articolo", "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, "supplierPartUpdated": "Articolo Fornitore Aggiornato", "@supplierPartUpdated": {}, "supplierParts": "Articoli Fornitore", @@ -803,6 +923,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, "testResultAdd": "Aggiungi Risultato Test", "@testResultAdd": {}, "testResultNone": "Nessun Risultato Del Test", @@ -823,6 +945,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, "transfer": "Trasferisci", "@transfer": { "description": "transfer" @@ -841,6 +965,8 @@ "@translate": {}, "translateHelp": "Aiuta a tradurre l'app InvenTree", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, "units": "Unità", "@units": {}, "unknownResponse": "Risposta Sconosciuta", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 14ecb4b..cc082bb 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -1,5 +1,9 @@ { "@@locale": "ja", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, "ok": "はい", "@ok": { "description": "OK" @@ -30,6 +34,10 @@ "@appCredits": {}, "appDetails": "アプリ詳細", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "アプリのリリースノートを表示", "@appReleaseNotes": {}, "appSettings": "アプリ設定", @@ -50,12 +58,18 @@ "@attachmentSelect": {}, "attention": "注意", "@attention": {}, + "available": "Available", + "@available": {}, "availableStock": "在庫あり", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, "barcodeSettings": "バーコード設定", "@barcodeSettings": {}, "barcodeAssign": "バーコードを割り当てる", "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, "barcodeAssigned": "バーコードが割り当てられました", "@barcodeAssigned": {}, "barcodeError": "バーコードのスキャンエラー", @@ -68,33 +82,68 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "バーコードが割り当てられていません", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "スキャンしてバーコードを割り当てます", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "InvenTree バーコードをスキャンする", "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, "barcodeScanLocation": "在庫場所をスキャン", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "在庫アイテムをスキャン", "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, "barcodeUnassign": "バーコードの割り当てを解除", "@barcodeUnassign": {}, "barcodeUnknown": "バーコードが認識されません", "@barcodeUnknown": {}, "batchCode": "一括処理コード", "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, "build": "ビルド", "@build": {}, "building": "ビルド", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "キャンセル", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, "category": "カテゴリ", "@category": {}, "categoryCreate": "新規カテゴリ", @@ -127,16 +176,28 @@ }, "credits": "謝辞", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "顧客", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "破損", "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, "delete": "削除", "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, "deletePart": "部品を削除", "@deletePart": {}, "deletePartDetail": "データベースからこの部品を削除します", "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, "description": "説明", "@description": {}, "destroyed": "破壊", @@ -161,12 +222,16 @@ "@editLocation": {}, "editNotes": "メモを編集", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "パートの編集", "@editPart": { "description": "edit part" }, "editItem": "在庫商品を編集", "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, "enterPassword": "パスワードを入力してください", "@enterPassword": {}, "enterUsername": "ユーザー名を入力してください", @@ -183,6 +248,10 @@ "@errorDetails": {}, "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, "errorReporting": "エラー報告", "@errorReporting": {}, "errorReportUpload": "エラー報告をアップロード", @@ -207,16 +276,32 @@ "@filterComponent": {}, "filterComponentDetail": "コンポーネントパーツを表示", "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "在庫あり", "@filterInStock": {}, "filterInStockDetail": "在庫があるパーツを表示", "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, "filterTemplate": "テンプレート", "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, "filterVirtual": "仮想", "@filterVirtual": {}, "filterVirtualDetail": "仮想パーツを表示", "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, "formatException": "フォーマットの例外エラー", "@formatException": {}, "formatExceptionJson": "JSONデータフォーマット例外エラー", @@ -234,8 +319,15 @@ "@homeScreenSettings": {}, "homeShowPo": "注文書を表示", "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "購読済みのパーツ", "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "仕入先を表示", "@homeShowSuppliers": {}, @@ -259,8 +351,12 @@ "@inactiveDetail": {}, "includeSubcategories": "サブカテゴリを含む", "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, "includeSublocations": "サブ在庫場所を含める", "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, "incompleteDetails": "不完全なプロフィールの詳細", "@incompleteDetails": {}, "internalPartNumber": "内部パーツ番号", @@ -271,6 +367,8 @@ "@inProduction": {}, "inProductionDetail": "この在庫品は生産中です", "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, "invalidHost": "無効なホスト名", "@invalidHost": {}, "invalidHostDetails": "このホスト名は無効です。", @@ -283,22 +381,52 @@ "@invalidStockLocation": {}, "invalidStockItem": "無効な在庫アイテム", "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, "issueDate": "発行日", "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, "itemInLocation": "アイテムは既に在庫場所にあります", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "キーワード", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, "language": "言語設定", "@language": {}, "languageDefault": "システムのデフォルト言語", "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, "lastUpdated": "最終更新", "@lastUpdated": {}, "level": "残量", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, "locationCreate": "新しい場所", "@locationCreate": {}, "locationCreateDetail": "新しい在庫場所を作成", @@ -307,10 +435,22 @@ "@locationNotSet": {}, "locationUpdated": "在庫場所を更新しました", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "リンク", "@link": {}, "lost": "損失", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, "missingData": "データ消失", "@missingData": {}, "name": "名前", @@ -321,6 +461,10 @@ "@notes": { "description": "Notes" }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, "noResponse": "サーバーからの応答がありません", "@noResponse": {}, "noResults": "一致する結果なし", @@ -333,10 +477,34 @@ "@numberInvalid": {}, "onOrder": "注文中", "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "梱包中", "@packaging": {}, "packageName": "パッケージ名", "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, "parent": "親", "@parent": {}, "parentCategory": "親カテゴリ", @@ -347,16 +515,30 @@ "@part": { "description": "Part (single)" }, + "partCreate": "New Part", + "@partCreate": {}, "partCreateDetail": "このカテゴリに新しいパーツを作成", "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, "parts": "パーツ", "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "パーツがありません", "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, "partsStarredNone": "お気に入りのパーツはありません", "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, "partCategory": "パーツカテゴリー", "@partCategory": {}, "partCategoryTopLevel": "トップレベルのパーツカテゴリ", @@ -383,6 +565,12 @@ "@printLabel": {}, "plugin": "プラグイン", "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, "printLabelFailure": "ラベルの印刷に失敗しました", "@printLabelFailure": {}, "printLabelSuccess": "ラベルをプリンタに送信しました", @@ -397,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "サーバープロファイルの削除", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "プロファイル名", "@profileName": {}, "profileNone": "利用可能なプロファイルがありません", @@ -405,10 +595,16 @@ "@profileNotSelected": {}, "profileSelect": "InvenTreeサーバーを選択", "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, "profileTapToCreate": "タップしてプロフィールを作成または選択します", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, "purchaseOrder": "発注書", "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "発注書の更新", "@purchaseOrderEdit": {}, "purchaseOrders": "発注書", @@ -421,14 +617,28 @@ "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, "quantityEmpty": "数量が空です", "@quantityEmpty": {}, "quantityInvalid": "数量が無効です", "@quantityInvalid": {}, "quantityPositive": "数量は1以上", "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, "queryNoResults": "検索結果はありません", "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, "refresh": "更新", "@refresh": {}, "refreshing": "更新中", @@ -453,6 +663,10 @@ "@results": {}, "request": "リクエスト", "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, "requestingData": "データをリクエスト中", "@requestingData": {}, "required": "必須", @@ -471,10 +685,16 @@ "@response405": {}, "response429": "リクエストが多すぎます", "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, "response501": "未実装", "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, "response503": "サービスは利用できません", "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, "response505": "このHTTP バージョンはサポートされていません", "@response505": {}, "responseData": "応答データ", @@ -489,19 +709,40 @@ }, "returned": "返品済", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "保存", "@save": { "description": "Save" }, "scanBarcode": "バーコードをスキャン", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "スキャンされた在庫場所", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "検索", "@search": { "description": "search" }, + "searching": "Searching", + "@searching": {}, "searchLocation": "在庫場所を検索", "@searchLocation": {}, "searchParts": "パーツの検索", @@ -520,6 +761,8 @@ "@send": {}, "serialNumber": "シリアルナンバー", "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, "server": "サーバー", "@server": {}, "serverAddress": "サーバーアドレス:", @@ -540,10 +783,14 @@ "@serverConnecting": {}, "serverCouldNotConnect": "サーバーに接続できませんでした", "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, "serverError": "サーバーエラー", "@serverError": {}, "serverDetails": "サーバの詳細", "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, "serverOld": "旧サーバーのバージョン", "@serverOld": {}, "serverSettings": "サーバー設定:", @@ -556,6 +803,16 @@ "@serverInstance": {}, "serverNotConnected": "サーバーに接続されていません", "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, "sounds": "サウンド", "@sounds": {}, "soundOnBarcodeAction": "バーコード動作で音を鳴らす", @@ -592,6 +849,8 @@ "@stockItemDeleteSuccess": {}, "stockItemHistory": "在庫履歴", "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, "stockItemTransferred": "在庫アイテムが転送されました", "@stockItemTransferred": {}, "stockItemUpdated": "在庫アイテムが更新されました", @@ -614,6 +873,8 @@ "@stockTopLevel": {}, "strictHttps": "厳格なHTTPSを使用", "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, "subcategory": "サブカテゴリー", "@subcategory": {}, "subcategories": "サブカテゴリー", @@ -628,12 +889,28 @@ "@sublocationNoneDetail": {}, "submitFeedback": "フィードバックを送信", "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, "supplier": "サプライヤー", "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, "suppliers": "サプライヤー", "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, "takePicture": "画像を撮影", "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, "templatePart": "上位テンプレートパーツ", "@templatePart": {}, "testName": "テスト名", @@ -646,6 +923,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, "testResultAdd": "テスト結果を追加", "@testResultAdd": {}, "testResultNone": "テスト結果がありません", @@ -666,6 +945,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, "transfer": "転送", "@transfer": { "description": "transfer" @@ -674,6 +955,8 @@ "@transferStock": { "description": "transfer stock" }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, "transferStockLocation": "在庫の保管場所を移動", "@transferStockLocation": {}, "transferStockLocationDetail": "この在庫を他の場所に移動する", @@ -682,6 +965,8 @@ "@translate": {}, "translateHelp": "InvenTree アプリの翻訳に協力する", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, "units": "単位", "@units": {}, "unknownResponse": "不明な応答", @@ -692,6 +977,10 @@ "@uploadFailed": {}, "uploadSuccess": "アップロードされたファイル", "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, "username": "ユーザー名", "@username": {}, "usernameEmpty": "ユーザー名は空にできません。", @@ -704,8 +993,12 @@ "@valueCannotBeEmpty": {}, "valueRequired": "値が必要です", "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, "version": "バージョン", "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, "website": "Webサイト", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 6264b1f..2fcc457 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -1,65 +1,768 @@ { "@@locale": "ko", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, "add": "추가", "@add": { "description": "add" }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, "address": "주소", "@address": {}, "appAbout": "InvenTree 소개", "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "앱 릴리즈 노트 표시", "@appReleaseNotes": {}, "appSettings": "앱 설정", "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, "billOfMaterials": "부품 명세서", "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "취소", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, "company": "회사", "@company": {}, "companyEdit": "회사 수정", "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, "error": "오류", "@error": { "description": "Error" }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, "errorDetails": "오류 세부 정보", "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "키워드", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, "noResults": "결과 없음", "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, "password": "비밀번호", "@password": {}, "passwordEmpty": "비밀번호는 비워둘 수 없습니다", "@passwordEmpty": {}, "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, "profileConnect": "서버에 연결", "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, "quantity": "수량", "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, "reportBug": "버그 신고", "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, "response505": "지원되지 않는 HTTP 버전", "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "저장", "@save": { "description": "Save" }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, "select": "선택", "@select": {}, "selectFile": "파일 선택", "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, "server": "서버", "@server": {}, "serverAddress": "서버 주소", @@ -70,34 +773,232 @@ "@serverApiVersion": {}, "serverAuthenticationError": "인증 오류", "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, "serverConnecting": "서버에 연결하는 중", "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, "serverError": "서버 오류", "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, "serverOld": "오래된 서버 버전", "@serverOld": {}, "serverSettings": "서버 설정", "@serverSettings": {}, "serverStart": "서버 주소는 http[s] 로 시작해야 합니다", "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, "status": "상태", "@status": {}, "statusCode": "상태 코드", "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, "targetDate": "목표 날짜", "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, "timeout": "시간 초과", "@timeout": { "description": "" }, "tokenError": "토큰 오류", "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, "translate": "번역", "@translate": {}, "translateHelp": "InvenTree 앱의 번역을 도와주세요", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, "version": "버전", "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, "website": "웹사이트", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index e4c0e9e..820fa6e 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -1,7 +1,1004 @@ { "@@locale": "lv", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index e567bf7..86bd397 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "App details", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "App release notities weergeven", "@appReleaseNotes": {}, "appSettings": "App Instellingen", @@ -78,9 +82,20 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Streepjescode niet toegewezen", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barcode Scan vertraging", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Vertraging tussen barcode scannen", @@ -91,6 +106,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Scan voorraadlocatie", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Gescand naar locatie", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Artikel niet gescand in", @@ -115,6 +134,10 @@ "@build": {}, "building": "Produceren", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Annuleer", "@cancel": { "description": "Cancel" @@ -153,8 +176,12 @@ }, "credits": "Credits", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Klanten", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Beschadigd", "@damaged": {}, "darkMode": "Donkere Modus", @@ -294,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Geabonneerde Onderdelen", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Geabonneerde Onderdelen weergeven op startscherm", @@ -362,6 +393,8 @@ "@issueOrder": {}, "itemInLocation": "Artikel al op locatie", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Trefwoorden", "@keywords": {}, "labelPrinting": "Label afdrukken", @@ -382,6 +415,8 @@ "@lastUpdated": {}, "level": "Niveau", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Regelartikel", "@lineItem": {}, "lineItems": "Regelartikelen", @@ -400,6 +435,12 @@ "@locationNotSet": {}, "locationUpdated": "Voorraadlocatie bijgewerkt", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "Link", "@link": {}, "lost": "Verloren", @@ -450,6 +491,12 @@ "@orientationSystem": {}, "outstanding": "Openstaand", "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Verpakkingen", "@packaging": {}, "packageName": "Pakketnaam", @@ -478,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Geen onderdelen", "@partsNone": {}, "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", @@ -536,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Serverprofiel Verwijderen", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Profielnaam", "@profileName": {}, "profileNone": "Geen profielen beschikbaar", @@ -658,19 +709,34 @@ }, "returned": "Teruggestuurd", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Verkooporders", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Bewaren", "@save": { "description": "Save" }, "scanBarcode": "Streepjescode Scannen", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Scan Naar Locatie", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scan dit item naar een locatie", "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Zoeken", "@search": { "description": "search" @@ -739,6 +805,12 @@ "@serverNotConnected": {}, "serverNotSelected": "Server niet geselecteerd", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, "sku": "Artikelnummer", "@sku": {}, "sounds": "Geluid", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index be5fac4..0949e8e 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "App-detaljer", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Vis appens utgivelsesnotater", "@appReleaseNotes": {}, "appSettings": "Appinnstillinger", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Strekkode ikke tildelt", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Skann strekkode for å motta del", "@barcodeReceivePart": {}, "barcodeScanPaused": "Skanning satt på pause", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Ingen deler", "@partsNone": {}, "partNoResults": "Ingen deler samsvarer med spørringen", @@ -717,6 +725,8 @@ }, "scanBarcode": "Skann strekkode", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Skann til plassering", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Skann artikkelen til plassering", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Sendt", "@shipped": {}, "sku": "SKU-kode", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 1faf7b2..709ea26 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Szczegóły aplikacji", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", "@appReleaseNotes": {}, "appSettings": "Ustawienia aplikacji", @@ -64,6 +68,8 @@ "@barcodeSettings": {}, "barcodeAssign": "Przypisz kod kreskowy", "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, "barcodeAssigned": "Kod kreskowy przypisany", "@barcodeAssigned": {}, "barcodeError": "Błąd czytnika kodów kreskowych", @@ -76,13 +82,34 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Kod kreskowy nieprzypisany", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, "barcodeScanLocation": "Skanuj lokalizację zapasów", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Przedmiot nie zeskanowany do", @@ -101,10 +128,16 @@ "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, "build": "Budowa", "@build": {}, "building": "Budowanie", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Anuluj", "@cancel": { "description": "Cancel" @@ -147,6 +180,8 @@ "@customer": {}, "customers": "Klienci", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Uszkodzone", "@damaged": {}, "darkMode": "Tryb ciemny", @@ -155,10 +190,14 @@ "@darkModeEnable": {}, "delete": "Usuń", "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, "deletePart": "Usuń Komponent", "@deletePart": {}, "deletePartDetail": "Usuń ten komponent z bazy danych", "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, "description": "Opis", "@description": {}, "destroyed": "Zniszczony", @@ -183,12 +222,16 @@ "@editLocation": {}, "editNotes": "Edytuj Notatki", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "Edytuj część", "@editPart": { "description": "edit part" }, "editItem": "Edytuj Pozycję Magazynową", "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, "enterPassword": "Wprowadź hasło", "@enterPassword": {}, "enterUsername": "Wprowadź nazwę użytkownika", @@ -205,6 +248,10 @@ "@errorDetails": {}, "errorFetch": "Błąd pobierania danych z serwea", "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, "errorReporting": "Raportowanie błędów", "@errorReporting": {}, "errorReportUpload": "Prześlij raport o błędach", @@ -217,12 +264,44 @@ "@feedbackError": {}, "feedbackSuccess": "Opinia przesłana", "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "Na stanie", "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, "filterTemplate": "Szablon", "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, "filterVirtual": "Wirtualny", "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, "formatException": "Wyjątek formatowania", "@formatException": {}, "formatExceptionJson": "Wyjątek formatu danych JSON", @@ -233,6 +312,7 @@ "@history": { "description": "history" }, + "home": "Home", "@homeScreen": {}, "homeScreen": "Ekran główny", "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", @@ -241,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Obserwowane części", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", @@ -267,16 +351,24 @@ "@inactiveDetail": {}, "includeSubcategories": "Zawieraj podkategorie", "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, "includeSublocations": "Zawieraj sublokacje", "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, "incompleteDetails": "Niekompletne szczegóły profilu", "@incompleteDetails": {}, "internalPartNumber": "Wewnętrzny numer części", "@internalPartNumber": {}, + "info": "Info", + "@info": {}, "inProduction": "W produkcji", "@inProduction": {}, "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, "invalidHost": "Nieprawidłowa nazwa hosta", "@invalidHost": {}, "invalidHostDetails": "Podana nazwa serwera jest nieprawidłowa", @@ -289,22 +381,52 @@ "@invalidStockLocation": {}, "invalidStockItem": "Nieprawidłowa część magazynowa", "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nieprawidłowy login lub hasło", "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, "issueDate": "Data Wystawienia", "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, "itemInLocation": "Część jest już w lokacji", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Słowa kluczowe", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, "lastStocktake": "Ostatnia inwentaryzacja", "@lastStocktake": {}, "lastUpdated": "Ostatnia aktualizacja", "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Pozycja", "@lineItem": {}, "lineItems": "Pozycje", "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, "locationCreate": "Nowa Lokalizacja", "@locationCreate": {}, "locationCreateDetail": "Utwórz nową pozycję magazynową", @@ -313,8 +435,20 @@ "@locationNotSet": {}, "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, "lost": "Zagubiono", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, "manufacturers": "Producenci", "@manufacturers": {}, "missingData": "Brakujące dane", @@ -329,6 +463,8 @@ }, "notifications": "Powiadomienia", "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, "noResponse": "Brak odpowiedzi od serwera", "@noResponse": {}, "noResults": "Brak wyników", @@ -343,12 +479,32 @@ "@onOrder": {}, "onOrderDetails": "Pozycje obecnie w zamówieniu", "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Opakowanie", "@packaging": {}, "packageName": "Nazwa pakietu", "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, "parent": "Nadrzędny", "@parent": {}, "parentCategory": "Kategoria nadrzędna", @@ -369,10 +525,14 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Brak części", "@partsNone": {}, "partNoResults": "Brak komponentów pasujących do zapytania", "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, "partsStarred": "Obserwowane części", "@partsStarred": {}, "partsStarredNone": "Brak części oznaczonych gwiazdką", @@ -439,8 +599,12 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, "purchaseOrder": "Zlecenie Zakupu", "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", "@purchaseOrderEdit": {}, "purchaseOrders": "Zlecenia zakupu", @@ -453,20 +617,28 @@ "@quantity": { "description": "Quantity" }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, "quantityEmpty": "Ilość jest pusta", "@quantityEmpty": {}, "quantityInvalid": "Ilość jest nieprawidłowa", "@quantityInvalid": {}, "quantityPositive": "Ilość musi być dodatnia", "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, "queryNoResults": "Nie znaleziono wyników dla zapytania", "@queryNoResults": {}, "received": "Odebrane", "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, "receiveItem": "Przyjmij artykuły", "@receiveItem": {}, "receivedItem": "Przyjęta Pozycja Magazynowa", "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, "refresh": "Odśwież", "@refresh": {}, "refreshing": "Odświeżanie", @@ -491,6 +663,10 @@ "@results": {}, "request": "Żądanie", "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, "requestingData": "Żądanie danych", "@requestingData": {}, "required": "Wymagane", @@ -533,21 +709,40 @@ }, "returned": "Zwrócono", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Zlecenia Sprzedaży", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Zapisz", "@save": { "description": "Save" }, "scanBarcode": "Skanuj kod kreskowy", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Skanuj do lokacji", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Szukaj", "@search": { "description": "search" }, + "searching": "Searching", + "@searching": {}, "searchLocation": "Wyszukaj lokalizację", "@searchLocation": {}, "searchParts": "Szukaj części", @@ -566,6 +761,8 @@ "@send": {}, "serialNumber": "Numer seryjny", "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, "server": "Serwer", "@server": {}, "serverAddress": "Adres serwera", @@ -606,6 +803,16 @@ "@serverInstance": {}, "serverNotConnected": "Serwer nie podłączony", "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, "sounds": "Dźwięki", "@sounds": {}, "soundOnBarcodeAction": "Odtwarzaj dźwięk w trakcie odczytywania kodu kreskowego", @@ -620,6 +827,8 @@ "@stock": { "description": "stock" }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, "stockItem": "Element magazynowy", "@stockItem": { "description": "stock item title" @@ -684,6 +893,16 @@ "@suppliedParts": {}, "supplier": "Dostawca", "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, "suppliers": "Dostawcy", "@suppliers": {}, "supplierReference": "Identyfikator Dostawcy", @@ -692,6 +911,8 @@ "@takePicture": {}, "targetDate": "Data Docelowa", "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, "testName": "Nazwa testu", "@testName": {}, "testPassedOrFailed": "Test zaliczony lub nieudany", @@ -702,6 +923,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, "testResultAdd": "Dodaj wynik testu", "@testResultAdd": {}, "testResultNone": "Brak wyników testu", @@ -722,6 +945,8 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, "transfer": "Przenieś", "@transfer": { "description": "transfer" @@ -730,10 +955,18 @@ "@transferStock": { "description": "transfer stock" }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, "translate": "Przetłumacz", "@translate": {}, "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, "units": "Jednostki", "@units": {}, "unknownResponse": "Nieznana odpowiedź", @@ -760,6 +993,8 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Wartość jest wymagana", "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, "version": "Wersja", "@version": {}, "viewSupplierPart": "Zobacz Dostawcę Części", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 9f4477b..1711e6c 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Detalhes do aplicativo", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, "appSettings": "Configurações do App", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Digitalize o código de barras para receber a parte", "@barcodeReceivePart": {}, "barcodeScanPaused": "Escaneamento de código de barras pausado", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Sem peças", "@partsNone": {}, "partNoResults": "Nenhuma peça corresponde a consulta", @@ -717,6 +725,8 @@ }, "scanBarcode": "Scanear Cod Bar", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Scan para localizacao", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Digitalize este item no local", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor não selecionado", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Enviado", "@shipped": {}, "sku": "Código (SKU)", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 39f4646..cdf471f 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Detalhes do App", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, "appSettings": "Configurações do App", @@ -54,10 +58,18 @@ "@attachmentSelect": {}, "attention": "Aviso", "@attention": {}, + "available": "Available", + "@available": {}, "availableStock": "Stock disponível", "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, "barcodeAssign": "Atribuir Código de Barras", "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, "barcodeAssigned": "Código de barras atribuído", "@barcodeAssigned": {}, "barcodeError": "Erro ao escanear código de barras", @@ -70,13 +82,34 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear Localização", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado no local", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "O item não foi digitalizado em", @@ -95,14 +128,22 @@ "@billOfMaterials": {}, "bom": "Lista de Materiais", "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, "build": "Compilar", "@build": {}, "building": "Compilando", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, "category": "Categoria", "@category": {}, "categoryCreate": "Nova Categoria", @@ -135,16 +176,28 @@ }, "credits": "Créditos", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Clientes", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, "delete": "Excluir", "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, "deletePart": "Excluir esta parte", "@deletePart": {}, "deletePartDetail": "Remover esta peça da base de dados", "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, "description": "Descrição", "@description": {}, "destroyed": "Destruído", @@ -169,12 +222,16 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "Editar a peça", "@editPart": { "description": "edit part" }, "editItem": "Editar Item do Estoque", "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, "enterUsername": "Inserir usuário", @@ -191,15 +248,757 @@ "@errorDetails": {}, "errorFetch": "Erro ao recolher dados do servidor", "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, "errorReporting": "Comunicação de Erros", "@errorReporting": {}, "errorReportUpload": "Enviar relatórios de erro", "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, "lastUpdated": "Ultima atualização", "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, "lineItems": "Itens de linha", "@lineItems": {}, - "@saleOrderCreate": {} + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 0ccffdc..5fffe1e 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Информация о приложении", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Показать заметки о выпуске приложения", "@appReleaseNotes": {}, "appSettings": "Настройки приложения", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Штрих-код не назначен", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Отсканируйте штрих-код для получения детали", "@barcodeReceivePart": {}, "barcodeScanPaused": "Сканирование штрих-кода приостановлено", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Нет компонентов", "@partsNone": {}, "partNoResults": "Нет компонентов, соответствующих запросу", @@ -717,6 +725,8 @@ }, "scanBarcode": "Сканировать штрихкод", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Сканировать в местоположение", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Отсканировать этот компонент в местоположение", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не выбран", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Отгружено", "@shipped": {}, "sku": "SKU", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 2dc50ee..f4f5b77 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -1,7 +1,1004 @@ { "@@locale": "sk", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 7a3dfc7..a7eca4d 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -1,7 +1,1004 @@ { "@@locale": "sl", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 799ed5c..8334cd1 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -1,7 +1,1004 @@ { "@@locale": "sr-CS", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 84921e4..1e686a2 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Appdetaljer", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Visa versionsinfo för app", "@appReleaseNotes": {}, "appSettings": "Appinställningar", @@ -72,25 +76,140 @@ "@barcodeError": {}, "barcodeInUse": "Streckkoden används redan", "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, "build": "Bygg", "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "Avbryt", "@cancel": { "description": "Cancel" }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, "category": "Kategori", "@category": {}, "categoryCreate": "Ny kategori", "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, "company": "Företag", "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Kunder", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, "delete": "Radera", "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, "description": "Beskrivning", "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, "downloadError": "Nedladdningsfel", "@downloadError": {}, "edit": "Redigera", @@ -103,6 +222,8 @@ "@editLocation": {}, "editNotes": "Redigera anteckningar", "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, "editPart": "Redigera artikel", "@editPart": { "description": "edit part" @@ -125,69 +246,759 @@ "@errorDelete": {}, "errorDetails": "Felinformation", "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "I lager", "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "Visa leverantörer", "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, "homeShowManufacturers": "Visa tillverkare", "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, "includeSubcategories": "Inkludera underkategorier", "@includeSubcategories": {}, "includeSubcategoriesDetail": "Visa resultat från underkategorier", "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Nyckelord", "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, "language": "Språk", "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, "languageSelect": "Välj språk", "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, "lastUpdated": "Senast uppdaterad", "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, "manufacturers": "Tillverkare", "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, "name": "Namn", "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, "notes": "Anteckningar", "@notes": { "description": "Notes" }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, "parameters": "Parametrar", "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, "password": "Lösenord", "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, "reference": "Referens", "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Spara", "@save": { "description": "Save" }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Sök", "@search": { "description": "search" }, "searching": "Söker", "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, "serialNumbers": "Serienummer", "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, "settings": "Inställningar", "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, "status": "Status", "@status": {}, "statusCode": "Statuskod", "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, "subcategory": "Underkategori", "@subcategory": {}, "subcategories": "Underkategorier", "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, "supplier": "Leverantör", "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, "suppliers": "Leverantörer", "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, "username": "Användarnamn", - "@username": {} + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index c1727ff..31d6396 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -1,7 +1,1004 @@ { "@@locale": "th", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, - "@saleOrderCreate": {} + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 53aae3d..ba6570c 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Uygulama Detayları", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Uygulama yayınlama notları", "@appReleaseNotes": {}, "appSettings": "Uygulama Ayarları", @@ -78,9 +82,20 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barkod atanmış değil", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barkod Tarama Gecikmesi", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Barkod taramaları arasındaki gecikme", @@ -91,6 +106,10 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Stok konumu tara", "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Konuma tarandı", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Madde taranmış değil", @@ -115,6 +134,10 @@ "@build": {}, "building": "Oluşturma", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "İptal", "@cancel": { "description": "Cancel" @@ -153,8 +176,12 @@ }, "credits": "Katkıda Bulunanlar", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "Müşteriler", "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, "damaged": "Hasarlı", "@damaged": {}, "darkMode": "Koyu Mod", @@ -251,6 +278,8 @@ "@filterComponentDetail": {}, "filterExternal": "Harici", "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "Stokta mevcut", "@filterInStock": {}, "filterInStockDetail": "Stoğu olan parçaları göster", @@ -292,6 +321,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, "homeShowSubscribed": "Parça bildirimlerine abone ol", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", @@ -356,8 +389,12 @@ "@issue": {}, "issueDate": "Sorun Tarihi", "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, "itemInLocation": "Parça zaten konumda", "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, "labelPrinting": "Etiket Yazdırma", @@ -378,10 +415,18 @@ "@lastUpdated": {}, "level": "Düzey", "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, "lineItem": "Parça Sırası", "@lineItem": {}, "lineItems": "Parçalar Sırası", "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, "locationCreate": "Yeni Konum", "@locationCreate": {}, "locationCreateDetail": "Yeni stok konumu oluştur", @@ -390,10 +435,18 @@ "@locationNotSet": {}, "locationUpdated": "Stok lokasyonu güncellendi", "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, "link": "Bağlantı", "@link": {}, "lost": "Kayıp", "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, "manufacturer": "Üretici", "@manufacturer": {}, "manufacturers": "Üreticiler", @@ -436,6 +489,14 @@ "@orientationPortrait": {}, "orientationSystem": "Sistem", "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, "packaging": "Paketleme", "@packaging": {}, "packageName": "Paket İsmi", @@ -464,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Parça Yok", "@partsNone": {}, "partNoResults": "Sorguyla eşleşen parça yok", @@ -506,6 +569,8 @@ "@pluginPrinter": {}, "pluginSupport": "Eklenti Desteği Etkin", "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, "printLabelFailure": "Etiket yazdırılamadı", "@printLabelFailure": {}, "printLabelSuccess": "Etiket yazıcıya gönderildi", @@ -520,6 +585,8 @@ "@profileEdit": {}, "profileDelete": "Sunucu profilini sil", "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, "profileName": "Profil Adı", "@profileName": {}, "profileNone": "Kullanılabiir profil yok", @@ -642,17 +709,34 @@ }, "returned": "Geri Dönen", "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, "save": "Kaydet", "@save": { "description": "Save" }, "scanBarcode": "Barkod Tara", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Konuma Tara", "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, "search": "Ara", "@search": { "description": "search" @@ -721,6 +805,12 @@ "@serverNotConnected": {}, "serverNotSelected": "Sunucu bulunamadı", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, "sku": "Stok No", "@sku": {}, "sounds": "Sesler", @@ -737,6 +827,8 @@ "@stock": { "description": "stock" }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, "stockItem": "Stok Kalemi", "@stockItem": { "description": "stock item title" @@ -779,6 +871,10 @@ "@stockLocations": {}, "stockTopLevel": "Üst seviye stok konumu", "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, "subcategory": "Alt kategori", "@subcategory": {}, "subcategories": "Alt kategoriler", @@ -799,6 +895,12 @@ "@supplier": {}, "supplierPart": "Tedarikçi Parçası", "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, "supplierParts": "Tedarikçi Parçaları", "@supplierParts": {}, "suppliers": "Tedarikçiler", @@ -821,6 +923,8 @@ "@testResults": { "description": "" }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, "testResultAdd": "Test Sonucu Ekle", "@testResultAdd": {}, "testResultNone": "Test Sonucu Yok", @@ -853,6 +957,10 @@ }, "transferStockDetail": "Öğeyi farklı bir lokasyona aktarın", "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, "translate": "Çeviri", "@translate": {}, "translateHelp": "Çeviriye yardım et", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 5aa165e..ee3f4db 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "Chi tiết về ứng dụng", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "Hiển thị ghi chú phát hành ứng dụng", "@appReleaseNotes": {}, "appSettings": "Cài đặt ứng dụng", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Mã vạch chưa được quét", "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, "barcodeReceivePart": "Quét mã vạch để nhận sản phẩm", "@barcodeReceivePart": {}, "barcodeScanPaused": "Quét mã vạch đã bị dừng", @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, "partsNone": "Không có phụ tùng", "@partsNone": {}, "partNoResults": "Không có phụ kiện nào phù hợp", @@ -717,6 +725,8 @@ }, "scanBarcode": "Quét mã vạch", "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, "scanIntoLocation": "Quét vào điểm bán", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Quét mặt hàng này vào điểm bán", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "Chưa chọn máy chủ", "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, "shipped": "Đã vận chuyển", "@shipped": {}, "sku": "Mã sản phẩm", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 571de89..783aad4 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -34,6 +34,10 @@ "@appCredits": {}, "appDetails": "应用详情", "@appDetails": {}, + "allocated": "已分配", + "@allocated": {}, + "allocateStock": "分配库存", + "@allocateStock": {}, "appReleaseNotes": "显示应用发布笔记", "@appReleaseNotes": {}, "appSettings": "应用设置", @@ -78,6 +82,8 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "未分配条形码", "@barcodeNotAssigned": {}, + "barcodeScanPart": "扫描零件条形码", + "@barcodeScanPart": {}, "barcodeReceivePart": "扫描条形码以接收零件", "@barcodeReceivePart": {}, "barcodeScanPaused": "条形码扫描已暂停", @@ -116,7 +122,7 @@ "@barcodeUnassign": {}, "barcodeUnknown": "无法识别条形码", "@barcodeUnknown": {}, - "batchCode": "批量编码", + "batchCode": "批号", "@batchCode": {}, "billOfMaterials": "物料清单", "@billOfMaterials": {}, @@ -519,6 +525,8 @@ "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "零件未被标记为可销售", + "@partNotSalable": {}, "partsNone": "无零件", "@partsNone": {}, "partNoResults": "没有匹配查询的零件", @@ -717,6 +725,8 @@ }, "scanBarcode": "扫描条形码", "@scanBarcode": {}, + "scanSupplierPart": "扫描供应商条形码", + "@scanSupplierPart": {}, "scanIntoLocation": "已扫描至位置", "@scanIntoLocation": {}, "scanIntoLocationDetail": "扫描此项目到此位置", @@ -795,6 +805,10 @@ "@serverNotConnected": {}, "serverNotSelected": "未选定服务器", "@serverNotSelected": {}, + "shipments": "配送", + "@shipments": {}, + "shipmentAdd": "添加配送", + "@shipmentAdd": {}, "shipped": "已配送", "@shipped": {}, "sku": "库存单位 (SKU)", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 996d478..c28ea98 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -34,10 +34,16 @@ "@appCredits": {}, "appDetails": "應用程式詳情", "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, "appReleaseNotes": "顯示應用程式發布說明", "@appReleaseNotes": {}, "appSettings": "程式設定", "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, "attachments": "附件", "@attachments": {}, "attachImage": "附加影像", @@ -50,11 +56,74 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "選取附件", "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, "available": "可用", "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, "barcodes": "條碼", "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, "billOfMaterials": "材料清單", "@billOfMaterials": {}, "bom": "材料清單", @@ -65,6 +134,10 @@ "@build": {}, "building": "生產中", "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, "cancel": "取消", "@cancel": { "description": "Cancel" @@ -75,12 +148,24 @@ "@category": {}, "categoryCreate": "新增類別", "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, "company": "公司", "@company": {}, "companyEdit": "編輯公司", "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, "companies": "公司", "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, "count": "數量", "@count": { "description": "Count" @@ -91,18 +176,32 @@ }, "credits": "感謝", "@credits": {}, + "customer": "Customer", + "@customer": {}, "customers": "客戶", "@customers": {}, - "darkMode": "暗黑模式", + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "深色模式", "@darkMode": {}, - "darkModeEnable": "啟用夜間模式", + "darkModeEnable": "啟用深色模式", "@darkModeEnable": {}, "delete": "刪除", "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, "deletePart": "刪除零件", "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, "description": "敘述", "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, "details": "詳細資訊", "@details": { "description": "details" @@ -119,6 +218,20 @@ }, "editCategory": "編輯類別", "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, "enterPassword": "輸入密碼", "@enterPassword": {}, "enterUsername": "輸入使用者名稱", @@ -127,8 +240,30 @@ "@error": { "description": "Error" }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, "feedback": "回饋", "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, "filterActive": "啟用", "@filterActive": {}, "filterActiveDetail": "顯示可用的零件", @@ -137,16 +272,42 @@ "@filterAssembly": {}, "filterAssemblyDetail": "顯示已組裝的零件", "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, "filterExternal": "外部", "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, "filterInStock": "有貨", "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, "filterTemplate": "範本", "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, "filterTrackable": "可追蹤", "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, "filterVirtual": "虛擬", "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, "history": "歷史", "@history": { "description": "history" @@ -154,43 +315,690 @@ "home": "首頁", "@homeScreen": {}, "homeScreen": "主畫面", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "顯示供應商", "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, "homeShowManufacturers": "顯示生產商", "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, "homeShowCustomers": "顯示客戶", "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, "imageUploadFailure": "圖片上傳失敗", "@imageUploadFailure": {}, "imageUploadSuccess": "圖片上傳", "@imageUploadSuccess": {}, "inactive": "未啟用", "@inactive": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, "info": "資訊", "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, "keywords": "關鍵字", "@keywords": {}, "labelPrinting": "標籤印製", "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, "language": "語言", "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, "languageSelect": "選擇語言", "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, "notes": "備註", "@notes": { "description": "Notes" }, "notifications": "通知", "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, "parts": "零件", "@parts": { "description": "Part (multiple)" }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, "stock": "庫存", "@stock": { "description": "stock" - } + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} } \ No newline at end of file From a889417fe03f363593d508671bb7b39b09f35c36 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 18 Apr 2024 21:48:45 +1000 Subject: [PATCH 460/746] Company active filters (#484) * Add support for "active" status for: - SupplierPart - Company * Add filtering options * Fix default value * Add inactive tiles * Update text and release notes --- assets/release_notes.md | 7 ++++++ lib/api.dart | 3 +++ lib/inventree/company.dart | 16 +++++++++++++- lib/l10n/app_en.arb | 3 +++ lib/widget/company/company_detail.dart | 23 ++++++++++++++++++++ lib/widget/company/company_list.dart | 17 +++++++++++++++ lib/widget/company/supplier_part_detail.dart | 23 ++++++++++++++++++++ lib/widget/company/supplier_part_list.dart | 15 ++++++++++++- 8 files changed, 105 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index a920d6a..16a736b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,10 @@ +### 0.14.3 - April 2024 +--- + +- Support "active" field for Company model +- Support "active" field for SupplierPart model +- Updated translations + ### 0.14.2 - February 2024 --- diff --git a/lib/api.dart b/lib/api.dart index 7028bea..cf33bd1 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -342,6 +342,9 @@ class InvenTreeAPI { // Does the server support "null" top-level filtering for PartCategory and StockLocation endpoints? bool get supportsNullTopLevelFiltering => isConnected() && apiVersion < 174; + // Does the server support "active" status on Company and SupplierPart API endpoints? + bool get supportsCompanyActiveStatus => isConnected() && apiVersion >= 189; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 4ebbc98..94b71b1 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -23,7 +23,7 @@ class InvenTreeCompany extends InvenTreeModel { @override Map> formFields() { - return { + Map> fields = { "name": {}, "description": {}, "website": {}, @@ -32,6 +32,12 @@ class InvenTreeCompany extends InvenTreeModel { "is_customer": {}, "currency": {}, }; + + if (InvenTreeAPI().supportsCompanyActiveStatus) { + fields["active"] = {}; + } + + return fields; } String get image => (jsondata["image"] ?? jsondata["thumbnail"] ?? InvenTreeAPI.staticImage) as String; @@ -50,6 +56,8 @@ class InvenTreeCompany extends InvenTreeModel { bool get isCustomer => getBool("is_customer"); + bool get active => getBool("active", backup: true); + int get partSuppliedCount => getInt("part_supplied"); int get partManufacturedCount => getInt("parts_manufactured"); @@ -137,6 +145,10 @@ class InvenTreeSupplierPart extends InvenTreeModel { fields["pack_quantity"] = {}; } + if (InvenTreeAPI().supportsCompanyActiveStatus) { + fields["active"] = {}; + } + return fields; } @@ -175,6 +187,8 @@ class InvenTreeSupplierPart extends InvenTreeModel { String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; String get SKU => getString("SKU"); + + bool get active => getBool("active", backup: true); int get partId => getInt("part"); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 231a79e..8c0f05c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -509,6 +509,9 @@ "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index bf83ee4..9d098aa 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -233,6 +233,29 @@ class _CompanyDetailState extends RefreshableState { ), )); + if (!widget.company.active) { + tiles.add( + ListTile( + title: Text( + L10().inactive, + style: TextStyle( + color: COLOR_DANGER + ) + ), + subtitle: Text( + L10().inactiveCompany, + style: TextStyle( + color: COLOR_DANGER + ) + ), + leading: FaIcon( + FontAwesomeIcons.circleExclamation, + color: COLOR_DANGER + ), + ) + ); + } + if (widget.company.website.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.website}"), diff --git a/lib/widget/company/company_list.dart b/lib/widget/company/company_list.dart index b68dffd..1c7db1b 100644 --- a/lib/widget/company/company_list.dart +++ b/lib/widget/company/company_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/api.dart"; +import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; @@ -58,6 +59,22 @@ class _CompanyListState extends PaginatedSearchState { _CompanyListState() : super(); + @override + Map> get filterOptions { + + Map> filters = {}; + + if (InvenTreeAPI().supportsCompanyActiveStatus) { + filters["active"] = { + "label": L10().filterActive, + "help_text": L10().filterActiveDetail, + "tristate": true, + }; + } + + return filters; + } + @override Future requestPage(int limit, int offset, Map params) async { diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index 6ca43cb..a8268e3 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -131,6 +131,29 @@ class _SupplierPartDisplayState extends RefreshableState get orderingOptions => {}; @override - Map> get filterOptions => {}; + Map> get filterOptions { + + Map> filters = {}; + + if (InvenTreeAPI().supportsCompanyActiveStatus) { + filters["active"] = { + "label": L10().filterActive, + "help_text": L10().filterActiveDetail, + "tristate": true, + }; + } + + return filters; + } @override Future requestPage(int limit, int offset, Map params) async { From 4499f3e00e27eb34119b363cef8a92fcff8ca7cb Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 18 Apr 2024 22:53:21 +1000 Subject: [PATCH 461/746] Barcode workflow (#485) * Refactor stock barcode operations into new file * Add setting to control confirmation of stock transfer actions * Update details when scannign stock item * Confirm movement when moving items into location * Cleanup --- assets/release_notes.md | 1 + lib/api_form.dart | 8 +- lib/barcode/barcode.dart | 258 +++------------------- lib/barcode/purchase_order.dart | 4 +- lib/barcode/sales_order.dart | 4 +- lib/barcode/stock.dart | 292 +++++++++++++++++++++++++ lib/inventree/stock.dart | 44 ++++ lib/l10n/app_en.arb | 6 + lib/preferences.dart | 1 + lib/settings/barcode_settings.dart | 2 +- lib/settings/part_settings.dart | 19 +- lib/widget/stock/location_display.dart | 1 + lib/widget/stock/stock_detail.dart | 40 +--- test/barcode_test.dart | 4 +- 14 files changed, 403 insertions(+), 281 deletions(-) create mode 100644 lib/barcode/stock.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 16a736b..d41beb3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Support "active" field for Company model - Support "active" field for SupplierPart model +- Adjustments to barcode scanning workflow - Updated translations ### 0.14.2 - February 2024 diff --git a/lib/api_form.dart b/lib/api_form.dart index 31e5d3e..f2578df 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -10,7 +10,6 @@ import "package:flutter/material.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; -import "package:inventree/barcode/tones.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; @@ -342,12 +341,7 @@ class APIFormField { controller.text = hash; data["value"] = hash; - barcodeSuccessTone(); - - showSnackIcon( - L10().barcodeAssigned, - success: true - ); + barcodeSuccess(L10().barcodeAssigned); }); scanBarcode(context, handler: handler); diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 91e600c..fead1b3 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -9,7 +9,6 @@ import "package:one_context/one_context.dart"; import "package:inventree/api.dart"; -import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/barcode/camera_controller.dart"; @@ -33,6 +32,35 @@ import "package:inventree/widget/stock/stock_detail.dart"; import "package:inventree/widget/company/supplier_part_detail.dart"; +// Signal a barcode scan success to the user +Future barcodeSuccess(String msg) async { + + barcodeSuccessTone(); + showSnackIcon(msg, success: true); +} + +// Signal a barcode scan failure to the user +Future barcodeFailure(String msg, dynamic extra) async { + barcodeFailureTone(); + showSnackIcon( + msg, + success: false, + onAction: () { + OneContext().showDialog( + builder: (BuildContext context) => SimpleDialog( + title: Text(L10().barcodeError), + children: [ + ListTile( + title: Text(L10().responseData), + subtitle: Text(extra.toString()) + ) + ] + ) + ); + } + ); +} + /* * Launch a barcode scanner with a particular context and handler. * @@ -266,234 +294,6 @@ class BarcodeScanHandler extends BarcodeHandler { } -/* - * Generic class for scanning a StockLocation. - * - * - Validates that the scanned barcode matches a valid StockLocation - * - Runs a "callback" function if a valid StockLocation is found - */ -class BarcodeScanStockLocationHandler extends BarcodeHandler { - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanLocation; - - @override - Future onBarcodeMatched(Map data) async { - - // We expect that the barcode points to a 'stocklocation' - if (data.containsKey("stocklocation")) { - int _loc = (data["stocklocation"]["pk"] ?? -1) as int; - - // A valid stock location! - if (_loc > 0) { - - debug("Scanned stock location ${_loc}"); - - final bool result = await onLocationScanned(_loc); - - if (result && OneContext.hasContext) { - OneContext().pop(); - return; - } - } - } - - // If we get to this point, something went wrong during the scan process - barcodeFailureTone(); - - showSnackIcon( - L10().invalidStockLocation, - success: false, - ); - } - - // Callback function which runs when a valid StockLocation is scanned - // If this function returns 'true' the barcode scanning dialog will be closed - Future onLocationScanned(int locationId) async { - // Re-implement this for particular subclass - return false; - } - -} - - -/* - * Generic class for scanning a StockItem - * - * - Validates that the scanned barcode matches a valid StockItem - * - Runs a "callback" function if a valid StockItem is found - */ -class BarcodeScanStockItemHandler extends BarcodeHandler { - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanItem; - - @override - Future onBarcodeMatched(Map data) async { - // We expect that the barcode points to a 'stockitem' - if (data.containsKey("stockitem")) { - int _item = (data["stockitem"]["pk"] ?? -1) as int; - - // A valid stock location! - if (_item > 0) { - - barcodeSuccessTone(); - - bool result = await onItemScanned(_item); - - if (result && OneContext.hasContext) { - OneContext().pop(); - return; - } - } - } - - // If we get to this point, something went wrong during the scan process - barcodeFailureTone(); - - showSnackIcon( - L10().invalidStockItem, - success: false, - ); - } - - // Callback function which runs when a valid StockItem is scanned - Future onItemScanned(int itemId) async { - // Re-implement this for particular subclass - return false; - } -} - - -/* - * Barcode handler for scanning a provided StockItem into a scanned StockLocation. - * - * - The class is initialized by passing a valid StockItem object - * - Expects to scan barcode for a StockLocation - * - The StockItem is transferred into the scanned location - */ -class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { - - StockItemScanIntoLocationHandler(this.item); - - final InvenTreeStockItem item; - - @override - Future onLocationScanned(int locationId) async { - - final result = await item.transferStock(locationId); - - if (result) { - barcodeSuccessTone(); - showSnackIcon(L10().barcodeScanIntoLocationSuccess, success: true); - } else { - barcodeFailureTone(); - showSnackIcon(L10().barcodeScanIntoLocationFailure, success: false); - } - - return result; - } -} - - -/* - * Barcode handler for scanning stock item(s) into the specified StockLocation. - * - * - The class is initialized by passing a valid StockLocation object - * - Expects to scan a barcode for a StockItem - * - The scanned StockItem is transferred into the provided StockLocation - */ -class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { - - StockLocationScanInItemsHandler(this.location); - - final InvenTreeStockLocation location; - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanItem; - - @override - Future onItemScanned(int itemId) async { - - final InvenTreeStockItem? item = await InvenTreeStockItem().get(itemId) as InvenTreeStockItem?; - - bool result = false; - - if (item != null) { - - // Item is already *in* the specified location - if (item.locationId == location.pk) { - barcodeFailureTone(); - showSnackIcon(L10().itemInLocation, success: true); - return false; - } else { - result = await item.transferStock(location.pk); - } - } - - showSnackIcon( - result ? L10().barcodeScanIntoLocationSuccess : L10().barcodeScanIntoLocationFailure, - success: result - ); - - // We always return false here, to ensure the barcode scan dialog remains open - return false; - } -} - - -/* - * Barcode handler class for scanning a StockLocation into another StockLocation - * - * - The class is initialized by passing a valid StockLocation object - * - Expects to scan barcode for another *parent* StockLocation - * - The scanned StockLocation is set as the "parent" of the provided StockLocation - */ -class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { - - ScanParentLocationHandler(this.location); - - final InvenTreeStockLocation location; - - @override - Future onLocationScanned(int locationId) async { - - final response = await location.update( - values: { - "parent": locationId.toString(), - }, - expectedStatusCode: null, - ); - - switch (response.statusCode) { - case 200: - case 201: - barcodeSuccessTone(); - showSnackIcon(L10().barcodeScanIntoLocationSuccess, success: true); - return true; - case 400: // Invalid parent location chosen - barcodeFailureTone(); - showSnackIcon(L10().invalidStockLocation, success: false); - return false; - default: - barcodeFailureTone(); - showSnackIcon( - L10().barcodeScanIntoLocationFailure, - success: false, - actionText: L10().details, - onAction: () { - showErrorDialog( - L10().barcodeError, - response: response, - ); - } - ); - return false; - } - } -} - - /* * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) */ diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart index 8fe67b8..8c91fed 100644 --- a/lib/barcode/purchase_order.dart +++ b/lib/barcode/purchase_order.dart @@ -6,6 +6,7 @@ import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; import "package:inventree/api_form.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/handler.dart"; import "package:inventree/barcode/tones.dart"; @@ -51,8 +52,7 @@ class POReceiveBarcodeHandler extends BarcodeHandler { return onBarcodeUnknown(data); } - barcodeSuccessTone(); - showSnackIcon(L10().receivedItem, success: true); + barcodeSuccess(L10().receivedItem); } @override diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart index 69583d9..bc42746 100644 --- a/lib/barcode/sales_order.dart +++ b/lib/barcode/sales_order.dart @@ -8,6 +8,7 @@ import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; +import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/handler.dart"; import "package:inventree/barcode/tones.dart"; @@ -115,8 +116,7 @@ class SOAllocateStockHandler extends BarcodeHandler { return onBarcodeUnknown(data); } - barcodeSuccessTone(); - showSnackIcon(L10().allocated, success: true); + barcodeSuccess(L10().allocated); } @override diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart new file mode 100644 index 0000000..8de6ed5 --- /dev/null +++ b/lib/barcode/stock.dart @@ -0,0 +1,292 @@ +import "package:flutter/cupertino.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/preferences.dart"; +import "package:one_context/one_context.dart"; + +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/handler.dart"; +import "package:inventree/barcode/tones.dart"; + +import "package:inventree/inventree/stock.dart"; + +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/snacks.dart"; + + +/* + * Generic class for scanning a StockLocation. + * + * - Validates that the scanned barcode matches a valid StockLocation + * - Runs a "callback" function if a valid StockLocation is found + */ +class BarcodeScanStockLocationHandler extends BarcodeHandler { + + @override + String getOverlayText(BuildContext context) => L10().barcodeScanLocation; + + @override + Future onBarcodeMatched(Map data) async { + + // We expect that the barcode points to a 'stocklocation' + if (data.containsKey("stocklocation")) { + int _loc = (data["stocklocation"]["pk"] ?? -1) as int; + + // A valid stock location! + if (_loc > 0) { + + debug("Scanned stock location ${_loc}"); + + final bool result = await onLocationScanned(_loc); + + if (result && OneContext.hasContext) { + OneContext().pop(); + return; + } + } + } + + // If we get to this point, something went wrong during the scan process + barcodeFailureTone(); + + showSnackIcon( + L10().invalidStockLocation, + success: false, + ); + } + + // Callback function which runs when a valid StockLocation is scanned + // If this function returns 'true' the barcode scanning dialog will be closed + Future onLocationScanned(int locationId) async { + // Re-implement this for particular subclass + return false; + } + +} + + +/* + * Generic class for scanning a StockItem + * + * - Validates that the scanned barcode matches a valid StockItem + * - Runs a "callback" function if a valid StockItem is found + */ +class BarcodeScanStockItemHandler extends BarcodeHandler { + + @override + String getOverlayText(BuildContext context) => L10().barcodeScanItem; + + @override + Future onBarcodeMatched(Map data) async { + // We expect that the barcode points to a 'stockitem' + if (data.containsKey("stockitem")) { + int _item = (data["stockitem"]["pk"] ?? -1) as int; + + // A valid stock location! + if (_item > 0) { + + barcodeSuccessTone(); + + bool result = await onItemScanned(_item); + + if (result && OneContext.hasContext) { + OneContext().pop(); + return; + } + } + } + + // If we get to this point, something went wrong during the scan process + barcodeFailureTone(); + + showSnackIcon( + L10().invalidStockItem, + success: false, + ); + } + + // Callback function which runs when a valid StockItem is scanned + Future onItemScanned(int itemId) async { + // Re-implement this for particular subclass + return false; + } +} + + +/* + * Barcode handler for scanning a provided StockItem into a scanned StockLocation. + * + * - The class is initialized by passing a valid StockItem object + * - Expects to scan barcode for a StockLocation + * - The StockItem is transferred into the scanned location + */ +class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { + + StockItemScanIntoLocationHandler(this.item); + + final InvenTreeStockItem item; + + @override + Future onLocationScanned(int locationId) async { + + final bool confirm = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); + + bool result = false; + + if (confirm) { + + Map fields = item.transferFields(); + + // Override location with scanned value + fields["location"]?["value"] = locationId; + + launchApiForm( + OneContext().context!, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.dolly, + onSuccess: (data) async { + showSnackIcon(L10().stockItemUpdated, success: true); + } + ); + + return true; + } else { + result = await item.transferStock(locationId); + } + + if (result) { + barcodeSuccess(L10().barcodeScanIntoLocationSuccess); + } else { + barcodeFailureTone(); + showSnackIcon(L10().barcodeScanIntoLocationFailure, success: false); + } + + return result; + } +} + + +/* + * Barcode handler for scanning stock item(s) into the specified StockLocation. + * + * - The class is initialized by passing a valid StockLocation object + * - Expects to scan a barcode for a StockItem + * - The scanned StockItem is transferred into the provided StockLocation + */ +class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { + + StockLocationScanInItemsHandler(this.location); + + final InvenTreeStockLocation location; + + @override + String getOverlayText(BuildContext context) => L10().barcodeScanItem; + + @override + Future onItemScanned(int itemId) async { + + final InvenTreeStockItem? item = await InvenTreeStockItem().get(itemId) as InvenTreeStockItem?; + final bool confirm = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); + + bool result = false; + + if (item != null) { + + // Item is already *in* the specified location + if (item.locationId == location.pk) { + barcodeFailureTone(); + showSnackIcon(L10().itemInLocation, success: true); + return false; + } else { + if (confirm) { + Map fields = item.transferFields(); + + // Override location with provided location value + fields["location"]?["value"] = location.pk; + + launchApiForm( + OneContext().context!, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.dolly, + onSuccess: (data) async { + showSnackIcon(L10().stockItemUpdated, success: true); + } + ); + + return true; + + } else { + result = await item.transferStock(location.pk); + + showSnackIcon( + result ? L10().barcodeScanIntoLocationSuccess : L10().barcodeScanIntoLocationFailure, + success: result + ); + } + } + } + + // We always return false here, to ensure the barcode scan dialog remains open + return false; + } +} + + +/* + * Barcode handler class for scanning a StockLocation into another StockLocation + * + * - The class is initialized by passing a valid StockLocation object + * - Expects to scan barcode for another *parent* StockLocation + * - The scanned StockLocation is set as the "parent" of the provided StockLocation + */ +class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { + + ScanParentLocationHandler(this.location); + + final InvenTreeStockLocation location; + + @override + Future onLocationScanned(int locationId) async { + + final response = await location.update( + values: { + "parent": locationId.toString(), + }, + expectedStatusCode: null, + ); + + switch (response.statusCode) { + case 200: + case 201: + barcodeSuccess(L10().barcodeScanIntoLocationSuccess); + return true; + case 400: // Invalid parent location chosen + barcodeFailureTone(); + showSnackIcon(L10().invalidStockLocation, success: false); + return false; + default: + barcodeFailureTone(); + showSnackIcon( + L10().barcodeScanIntoLocationFailure, + success: false, + actionText: L10().details, + onAction: () { + showErrorDialog( + L10().barcodeError, + response: response, + ); + } + ); + return false; + } + } +} diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 4f455fe..ba4e871 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -145,6 +145,50 @@ class InvenTreeStockItem extends InvenTreeModel { @override List get rolesRequired => ["stock"]; + // Return a set of fields to transfer this stock item via dialog + Map transferFields() { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": quantity, + }, + "location": { + "value": locationId, + }, + "status": { + "parent": "items", + "nested": true, + "value": status, + }, + "packaging": { + "parent": "items", + "nested": true, + "value": packaging, + }, + "notes": {}, + }; + + if (isSerialized()) { + // Prevent editing of 'quantity' field if the item is serialized + fields["quantity"]["hidden"] = true; + } + + // Old API does not support these fields + if (!api.supportsStockAdjustExtraFields) { + fields.remove("packaging"); + fields.remove("status"); + } + + return fields; + } + // URLs for performing stock actions static String transferStockUrl() => "stock/transfer/"; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8c0f05c..2f622ff 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -240,6 +240,12 @@ "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScan": {}, + "connectionRefused": "Connection Refused", "@connectionRefused": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 19e4ffb..4828a7a 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -35,6 +35,7 @@ const String INV_PART_SHOW_BOM = "partShowBom"; // Stock settings const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; const String INV_STOCK_SHOW_TESTS = "stockShowTests"; +const String INV_STOCK_CONFIRM_SCAN = "stockConfirmScan"; const String INV_REPORT_ERRORS = "reportErrors"; const String INV_STRICT_HTTPS = "strictHttps"; diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index bb202b2..ffcf404 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -110,7 +110,7 @@ class _InvenTreeBarcodeSettingsState extends State { bool partShowBom = true; bool stockShowHistory = false; bool stockShowTests = false; + bool stockConfirmScan = false; @override void initState() { @@ -32,6 +33,7 @@ class _InvenTreePartSettingsState extends State { partShowBom = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_BOM, true) as bool; stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; + stockConfirmScan = await InvenTreeSettingsManager().getValue(INV_STOCK_CONFIRM_SCAN, false) as bool; if (mounted) { setState(() { @@ -42,7 +44,7 @@ class _InvenTreePartSettingsState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(L10().part)), + appBar: AppBar(title: Text(L10().partSettings)), body: Container( child: ListView( children: [ @@ -74,6 +76,7 @@ class _InvenTreePartSettingsState extends State { }, ), ), + Divider(), ListTile( title: Text(L10().stockItemHistory), subtitle: Text(L10().stockItemHistoryDetail), @@ -101,6 +104,20 @@ class _InvenTreePartSettingsState extends State { }); }, ), + ), + ListTile( + title: Text(L10().confirmScan), + subtitle: Text(L10().confirmScanDetail), + leading: FaIcon(FontAwesomeIcons.qrcode), + trailing: Switch( + value: stockConfirmScan, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_STOCK_CONFIRM_SCAN, value); + setState(() { + stockConfirmScan = value; + }); + } + ), ) ] ) diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index f31940c..ac73c0d 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -6,6 +6,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/purchase_order.dart"; +import "package:inventree/barcode/stock.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index d9b4edf..ee21b44 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -5,6 +5,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/stock.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -436,44 +437,7 @@ class _StockItemDisplayState extends RefreshableState { */ Future _transferStockDialog(BuildContext context) async { - Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": widget.item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": widget.item.quantity, - }, - "location": { - "value": widget.item.locationId, - }, - "status": { - "parent": "items", - "nested": true, - "value": widget.item.status, - }, - "packaging": { - "parent": "items", - "nested": true, - "value": widget.item.packaging, - }, - "notes": {}, - }; - - if (widget.item.isSerialized()) { - // Prevent editing of 'quantity' field if the item is serialized - fields["quantity"]["hidden"] = true; - } - - // Old API does not support these fields - if (!api.supportsStockAdjustExtraFields) { - fields.remove("packaging"); - fields.remove("status"); - } + Map fields = widget.item.transferFields(); launchApiForm( context, diff --git a/test/barcode_test.dart b/test/barcode_test.dart index 181e74d..cd77c57 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -8,9 +8,11 @@ import "package:flutter_test/flutter_test.dart"; import "package:inventree/api.dart"; -import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/stock.dart"; + import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; From f986e163e3a92fab8ce140d2760c918cf967f6ce Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 18 Apr 2024 22:54:19 +1000 Subject: [PATCH 462/746] Bump version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 165b298..49e1f7c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.14.2+80 +version: 0.14.3+81 environment: sdk: ">=2.19.5 <3.13.0" From 177f040324dfcb46c0edb5c45b42792cfab554d6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 19 Apr 2024 10:33:09 +1000 Subject: [PATCH 463/746] New Crowdin updates (#486) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/bg_BG/app_bg_BG.arb | 5 +++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 5 +++++ lib/l10n/da_DK/app_da_DK.arb | 5 +++++ lib/l10n/de_DE/app_de_DE.arb | 5 +++++ lib/l10n/el_GR/app_el_GR.arb | 5 +++++ lib/l10n/es_ES/app_es_ES.arb | 5 +++++ lib/l10n/es_MX/app_es_MX.arb | 5 +++++ lib/l10n/fa_IR/app_fa_IR.arb | 5 +++++ lib/l10n/fi_FI/app_fi_FI.arb | 5 +++++ lib/l10n/fr_FR/app_fr_FR.arb | 5 +++++ lib/l10n/he_IL/app_he_IL.arb | 5 +++++ lib/l10n/hi_IN/app_hi_IN.arb | 5 +++++ lib/l10n/hu_HU/app_hu_HU.arb | 5 +++++ lib/l10n/id_ID/app_id_ID.arb | 5 +++++ lib/l10n/it_IT/app_it_IT.arb | 5 +++++ lib/l10n/ja_JP/app_ja_JP.arb | 5 +++++ lib/l10n/ko_KR/app_ko_KR.arb | 5 +++++ lib/l10n/lv_LV/app_lv_LV.arb | 5 +++++ lib/l10n/nl_NL/app_nl_NL.arb | 5 +++++ lib/l10n/no_NO/app_no_NO.arb | 5 +++++ lib/l10n/pl_PL/app_pl_PL.arb | 5 +++++ lib/l10n/pt_BR/app_pt_BR.arb | 5 +++++ lib/l10n/pt_PT/app_pt_PT.arb | 5 +++++ lib/l10n/ru_RU/app_ru_RU.arb | 5 +++++ lib/l10n/sk_SK/app_sk_SK.arb | 5 +++++ lib/l10n/sl_SI/app_sl_SI.arb | 5 +++++ lib/l10n/sr_CS/app_sr_CS.arb | 5 +++++ lib/l10n/sv_SE/app_sv_SE.arb | 5 +++++ lib/l10n/th_TH/app_th_TH.arb | 5 +++++ lib/l10n/tr_TR/app_tr_TR.arb | 5 +++++ lib/l10n/vi_VN/app_vi_VN.arb | 5 +++++ lib/l10n/zh_CN/app_zh_CN.arb | 5 +++++ lib/l10n/zh_TW/app_zh_TW.arb | 5 +++++ 33 files changed, 165 insertions(+) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 83726ea..4a73da4 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 3bd17c3..9a9440a 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Konfigurace nastavení serveru", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Spojení selhalo", "@connectionRefused": {}, "count": "Počet", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Neaktivní", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Tato část je označena jako neaktivní", "@inactiveDetail": {}, "includeSubcategories": "Zahrnout podkategorie", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 3150f91..a0afda8 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index ebcf0a8..0cf5cda 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Server-Einstellungen konfigurieren", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Verbindung verweigert", "@connectionRefused": {}, "count": "Zählen", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inaktiv", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Teil als inaktiv gekennzeichnet", "@inactiveDetail": {}, "includeSubcategories": "Unter-Kategorien einschließen", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 484a908..4af1818 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index cf36269..62ca798 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure las opciones de su servidor", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Contar", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactivo", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Esta pieza está marcada como inactiva", "@inactiveDetail": {}, "includeSubcategories": "Incluir subcategorias", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index c72542f..b0688a8 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configurar ajustes del servidor", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Número", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactivo", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Esta parte está marcada como inactiva", "@inactiveDetail": {}, "includeSubcategories": "Incluir subcategorias", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 5f61ecd..ab5c064 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 53e6818..e250099 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Määritä palvelimen asetukset", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Yhteys evätty", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 7cf5a4c..09e3d12 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configurer les paramètres serveur", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connexion refusée", "@connectionRefused": {}, "count": "Nombre", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactif", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Cette pièce est marquée comme inactive", "@inactiveDetail": {}, "includeSubcategories": "Inclure les sous-catégories", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index fec5213..48f0acd 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 17cb49d..249569a 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 320116f..f3866e5 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Kiszolgáló beállítások konfigurálása", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "A kapcsolat visszautasítva", "@connectionRefused": {}, "count": "Mennyiség", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inaktív", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Ez az alkatrész inaktív lett", "@inactiveDetail": {}, "includeSubcategories": "Alkategóriákkal együtt", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 1c1ee8f..6be7331 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 5e6e2b3..14917e7 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configurare le impostazioni del server", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connessione rifiutata", "@connectionRefused": {}, "count": "Quantità", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inattivo", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Questo articolo è contrassegnato come inattivo", "@inactiveDetail": {}, "includeSubcategories": "Includi sottocategorie", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index cc082bb..b72b8b2 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "サーバー設定", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "接続を拒否しました", "@connectionRefused": {}, "count": "カウント", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "無効", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "この部品は無効としてマークされています", "@inactiveDetail": {}, "includeSubcategories": "サブカテゴリを含む", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 2fcc457..a8cdc6f 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 820fa6e..43443fe 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 86bd397..b842802 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configureer server instellingen", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Verbinding geweigerd", "@connectionRefused": {}, "count": "Tellen", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactief", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Dit onderdeel is gemarkeerd als inactief", "@inactiveDetail": {}, "includeSubcategories": "Inclusief subcategorieën", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 0949e8e..56d1645 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Konfigurer serverinnstillinger", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Tilkobling avvist", "@connectionRefused": {}, "count": "Antall", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inaktiv", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Denne delen er merket som inaktiv", "@inactiveDetail": {}, "includeSubcategories": "Inkluder underkategorier", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 709ea26..28db846 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Konfiguruj ustawienia serwera", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Połączenie odrzucone", "@connectionRefused": {}, "count": "Ilość", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Nieaktywny", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", "@inactiveDetail": {}, "includeSubcategories": "Zawieraj podkategorie", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 1711e6c..f98ddee 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Definir as configurações do servidor", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contar", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inativo", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Este produto esta marcado como inativo", "@inactiveDetail": {}, "includeSubcategories": "Incluir sub-categorias", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index cdf471f..0f4d628 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configurar os parâmetros do servidor de email", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contagem", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 5fffe1e..a21f940 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Настройка параметров сервера", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Отказано в подключении", "@connectionRefused": {}, "count": "Количество", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Неактивный", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Эта часть помечена как неактивная", "@inactiveDetail": {}, "includeSubcategories": "Включить подкатегории", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index f4f5b77..fb30c75 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index a7eca4d..f9c5e5f 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 8334cd1..9b1af03 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 1e686a2..0d07c08 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Inkludera underkategorier", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 31d6396..a9a0510 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Inactive", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index ba6570c..2d003a3 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Sunucu ayarlarınızı yapılandırın", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Bağlantı reddedildi", "@connectionRefused": {}, "count": "Sayım", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Pasif", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Bu parça pasif olarak işaretlendi", "@inactiveDetail": {}, "includeSubcategories": "Alt kategorileri dahil et", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index ee3f4db..03929c2 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Cấu hình thiết lập máy chủ", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Kết nối bị từ chối", "@connectionRefused": {}, "count": "Đếm", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "Không hoạt động", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "Phần này được đánh dấu là không hoạt động", "@inactiveDetail": {}, "includeSubcategories": "Bao gồm danh mục con", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 783aad4..369914e 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "配置服务器的设置", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "连接被拒绝", "@connectionRefused": {}, "count": "数量", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "未激活", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "此零件已被标为未激活", "@inactiveDetail": {}, "includeSubcategories": "包含子类别", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index c28ea98..58207b5 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -164,6 +164,9 @@ "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "數量", @@ -347,6 +350,8 @@ "@imageUploadSuccess": {}, "inactive": "未啟用", "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, "includeSubcategories": "Include Subcategories", From 86425ebb2bebafde71887599375ccf2e3f8e45a1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 29 Apr 2024 20:28:59 +1000 Subject: [PATCH 464/746] New translations app_en.arb (Ukrainian) (#487) --- lib/l10n/uk_UA/app_uk_UA.arb | 1009 ++++++++++++++++++++++++++++++++++ 1 file changed, 1009 insertions(+) create mode 100644 lib/l10n/uk_UA/app_uk_UA.arb diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb new file mode 100644 index 0000000..0f4f74a --- /dev/null +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -0,0 +1,1009 @@ +{ + "@@locale": "uk", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file From 91cb24c74cbfa79dbcaa2855d7308e45add3d13f Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 10 May 2024 23:52:26 +1000 Subject: [PATCH 465/746] New translations app_en.arb (Hungarian) (#488) --- lib/l10n/hu_HU/app_hu_HU.arb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index f3866e5..9b538b2 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "App részletek", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Lefoglalva", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Készlet foglalása", "@allocateStock": {}, "appReleaseNotes": "Kiadási közlemények", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Vonalkód nincs hozzárendelve", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Vonalkód beolvasása", "@barcodeScanPart": {}, "barcodeReceivePart": "Olvasd le a vonalkódot a bevételezéshez", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Kiszolgáló beállítások konfigurálása", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Mozgatás megerősítése", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Készlet mozgatás megerősítése vonalkód olvasáskor", "connectionRefused": "A kapcsolat visszautasítva", "@connectionRefused": {}, "count": "Mennyiség", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inaktív", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Ez a vállalat inaktív lett", "@inactiveCompany": {}, "inactiveDetail": "Ez az alkatrész inaktív lett", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Az alkatrész nincsen értékesíthetőnek jelölve", "@partNotSalable": {}, "partsNone": "Nincsenek alkatrészek", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Vonalkód beolvasása", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Beszállítói cikk vonalkódjának beolvasása", "@scanSupplierPart": {}, "scanIntoLocation": "Beolvasás helyre", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Szállítmányok", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Szállítmány hozzáadása", "@shipmentAdd": {}, "shipped": "Kiszállítva", "@shipped": {}, From 3c0bca276d02eec18fd7976438da8d5fbdad3cc2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 May 2024 20:41:02 +1000 Subject: [PATCH 466/746] Label printing fix (#489) * Add check for modern label printing interface * Update getLabelTemplates * Fix typo * Refactor / simplify * Revert parameter type * Update version number and release notes * Refactor label printing function - Will require some cleanup in the future - Still needs testing * Fix for modern printing * Typo fix --- assets/release_notes.md | 6 + lib/api.dart | 3 + lib/inventree/model.dart | 3 + lib/inventree/part.dart | 3 + lib/inventree/purchase_order.dart | 3 + lib/inventree/sales_order.dart | 3 + lib/inventree/stock.dart | 6 + lib/labels.dart | 175 +++++++++++++++---------- lib/settings/about.dart | 2 +- lib/widget/part/part_detail.dart | 14 +- lib/widget/stock/location_display.dart | 14 +- lib/widget/stock/stock_detail.dart | 14 +- pubspec.yaml | 2 +- 13 files changed, 171 insertions(+), 77 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index d41beb3..7404407 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.15.0 - May 2024 +--- + +- Support modern label printing API +- Updated translations + ### 0.14.3 - April 2024 --- diff --git a/lib/api.dart b/lib/api.dart index cf33bd1..67b076f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -345,6 +345,9 @@ class InvenTreeAPI { // Does the server support "active" status on Company and SupplierPart API endpoints? bool get supportsCompanyActiveStatus => isConnected() && apiVersion >= 189; + // Does the server support the "modern" (consolidated) label printing API? + bool get supportsModenLabelPrinting => isConnected() && apiVersion >= 197; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index a28e5d6..747dc26 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -64,6 +64,9 @@ class InvenTreeModel { // Note: If the WEB_URL is the same (except for /api/) as URL then just leave blank String get WEB_URL => ""; + // Return the "model type" of this model + String get MODEL_TYPE => ""; + // Helper function to set a value in the JSON data void setValue(String key, dynamic value) { jsondata[key] = value; diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index e44494e..61e1c27 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -196,6 +196,9 @@ class InvenTreePart extends InvenTreeModel { @override String get URL => "part/"; + @override + String get MODEL_TYPE => "part"; + @override List get rolesRequired => ["part"]; diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 8070894..fab3672 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -20,6 +20,9 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { @override String get URL => "order/po/"; + @override + String get MODEL_TYPE => "purchaseorder"; + @override List get rolesRequired => ["purchase_order"]; diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index b65ad61..b23d8eb 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -23,6 +23,9 @@ class InvenTreeSalesOrder extends InvenTreeOrder { @override String get URL => "order/so/"; + @override + String get MODEL_TYPE => "salesorder"; + @override List get rolesRequired => ["sales_order"]; diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index ba4e871..b9c4036 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -142,6 +142,9 @@ class InvenTreeStockItem extends InvenTreeModel { @override String get URL => "stock/"; + @override + String get MODEL_TYPE => "stockitem"; + @override List get rolesRequired => ["stock"]; @@ -649,6 +652,9 @@ class InvenTreeStockLocation extends InvenTreeModel { @override String get URL => "stock/location/"; + @override + String get MODEL_TYPE => "stocklocation"; + @override List get rolesRequired => ["stock_location"]; diff --git a/lib/labels.dart b/lib/labels.dart index c43ad30..c8fadd0 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -6,50 +6,18 @@ import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; import "package:inventree/widget/snacks.dart"; -/* - * Discover which label templates are available for a given item - */ -Future>> getLabelTemplates( - String labelType, - Map data, -) async { - - if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) { - return []; - } - - // Filter by active plugins - data["enabled"] = "true"; - - List> labels = []; - - await InvenTreeAPI().get( - "/label/${labelType}/", - params: data, - ).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - for (var label in response.resultsList()) { - if (label is Map) { - labels.add(label); - } - } - } - }); - - return labels; -} - - /* * Select a particular label, from a provided list of options, * and print against the selected instances. + * */ Future selectAndPrintLabel( - BuildContext context, - List> labels, - String labelType, - String labelQuery, - ) async { + BuildContext context, + List> labels, + int instanceId, + String labelType, + String labelQuery, +) async { if (!InvenTreeAPI().isConnected()) { return; @@ -91,7 +59,7 @@ Future selectAndPrintLabel( for (var plugin in plugins) { plugin_options.add({ "display_name": plugin.humanName, - "value": plugin.key + "value": InvenTreeAPI().supportsModenLabelPrinting ? plugin.pk : plugin.key }); } @@ -124,38 +92,113 @@ Future selectAndPrintLabel( icon: FontAwesomeIcons.print, onSuccess: (Map data) async { int labelId = (data["label"] ?? -1) as int; - String pluginKey = (data["plugin"] ?? "") as String; + var pluginKey = data["plugin"]; - if (labelId != -1 && pluginKey.isNotEmpty) { - String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; + bool result = false; + + if (labelId != -1 && pluginKey != null) { showLoadingOverlay(context); - InvenTreeAPI().get(url).then((APIResponse response) { - hideLoadingOverlay(); - if (response.isValid() && response.statusCode == 200) { + if (InvenTreeAPI().supportsModenLabelPrinting) { - var data = response.asMap(); - - if (data.containsKey("file")) { - var label_file = (data["file"] ?? "") as String; - - // Attempt to open remote file - InvenTreeAPI().downloadFile(label_file); - } else { - showSnackIcon( - L10().printLabelSuccess, - success: true - ); + // Modern label printing API uses a POST request to a single API endpoint. + await InvenTreeAPI().post( + "/label/print/", + body: { + "plugin": pluginKey, + "template": labelId, + "items": [instanceId] + } + ).then((APIResponse response) { + hideLoadingOverlay(); + + if (response.isValid() && response.statusCode >= 200 && + response.statusCode <= 201) { + var data = response.asMap(); + + if (data.containsKey("output")) { + var label_file = (data["output"] ?? "") as String; + + // Attempt to open generated file + InvenTreeAPI().downloadFile(label_file); + result = true; + } } - } else { - showSnackIcon( - L10().printLabelFailure, - success: false, - ); - } }); + } else { + // Legacy label printing API + // Uses a GET request to a specially formed URL which depends on the parameters + String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; + await InvenTreeAPI().get(url).then((APIResponse response) { + hideLoadingOverlay(); + if (response.isValid() && response.statusCode == 200) { + var data = response.asMap(); + if (data.containsKey("file")) { + var label_file = (data["file"] ?? "") as String; + + // Attempt to open remote file + InvenTreeAPI().downloadFile(label_file); + result = true; + } + } + }); } - }, - ); + + if (result) { + showSnackIcon( + L10().printLabelSuccess, + success: true + ); + } else { + showSnackIcon( + L10().printLabelFailure, + success: false, + ); + } + } + }); +} + + +/* + * Discover which label templates are available for a given item + */ +Future>> getLabelTemplates( + String labelType, + Map data, +) async { + + if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) { + return []; + } + + // Filter by active plugins + data["enabled"] = "true"; + + String url = "/label/template/"; + + if (InvenTreeAPI().supportsModenLabelPrinting) { + data["model_type"] = labelType; + } else { + // Legacy label printing API endpoint + url = "/label/${labelType}/"; + } + + List> labels = []; + + await InvenTreeAPI().get( + url, + params: data, + ).then((APIResponse response) { + if (response.isValid() && response.statusCode == 200) { + for (var label in response.resultsList()) { + if (label is Map) { + labels.add(label); + } + } + } + }); + + return labels; } \ No newline at end of file diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 3f02f6f..1bec376 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -194,7 +194,7 @@ class InvenTreeAboutWidget extends StatelessWidget { tiles.add( ListTile( title: Text(L10().documentation), - subtitle: Text("https://docs.inventree.org"), + subtitle: Text("https://docs.inventree.org/app"), leading: FaIcon(FontAwesomeIcons.book, color: COLOR_ACTION), onTap: () { _openDocs(); diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 8009ee6..f9693a1 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -129,6 +129,7 @@ class _PartDisplayState extends RefreshableState { selectAndPrintLabel( context, labels, + widget.part.pk, "part", "part=${widget.part.pk}" ); @@ -248,9 +249,16 @@ class _PartDisplayState extends RefreshableState { allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { - _labels = await getLabelTemplates("part", { - "part": widget.part.pk.toString(), - }); + + String model_type = api.supportsModenLabelPrinting ? InvenTreePart().MODEL_TYPE : "part"; + String item_key = api.supportsModenLabelPrinting ? "items" : "part"; + + _labels = await getLabelTemplates( + model_type, + { + item_key: widget.part.pk.toString() + } + ); } if (mounted) { diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index ac73c0d..dcb1372 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -193,6 +193,7 @@ class _LocationDisplayState extends RefreshableState { selectAndPrintLabel( context, labels, + widget.location!.pk, "location", "location=${widget.location!.pk}" ); @@ -247,9 +248,16 @@ class _LocationDisplayState extends RefreshableState { if (allowLabelPrinting) { if (widget.location != null) { - _labels = await getLabelTemplates("location", { - "location": widget.location!.pk.toString() - }); + + String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "location"; + String item_key = api.supportsModenLabelPrinting ? "items" : "location"; + + _labels = await getLabelTemplates( + model_type, + { + item_key: widget.location!.pk.toString() + } + ); } } diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index ee21b44..f44f0dd 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -138,6 +138,7 @@ class _StockItemDisplayState extends RefreshableState { selectAndPrintLabel( context, labels, + widget.item.pk, "stock", "item=${widget.item.pk}" ); @@ -264,10 +265,17 @@ class _StockItemDisplayState extends RefreshableState { // Request information on labels available for this stock item if (allowLabelPrinting) { + + String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "stock"; + String item_key = api.supportsModenLabelPrinting ? "items" : "item"; + // Clear the existing labels list - _labels = await getLabelTemplates("stock", { - "item": widget.item.pk.toString() - }); + _labels = await getLabelTemplates( + model_type, + { + item_key: widget.item.pk.toString() + } + ); } if (mounted) { diff --git a/pubspec.yaml b/pubspec.yaml index 49e1f7c..0589baa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.14.3+81 +version: 0.15.0+82 environment: sdk: ">=2.19.5 <3.13.0" From 9a6e1e6381d797ba3d4d4374f4b2f89914aba332 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 12 May 2024 20:42:08 +1000 Subject: [PATCH 467/746] New translations app_en.arb (Russian) (#490) --- lib/l10n/ru_RU/app_ru_RU.arb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index a21f940..3651af7 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Информация о приложении", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Выделено", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Выделить запас", "@allocateStock": {}, "appReleaseNotes": "Показать заметки о выпуске приложения", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Штрих-код не назначен", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Сканировать штрих-код", "@barcodeScanPart": {}, "barcodeReceivePart": "Отсканируйте штрих-код для получения детали", "@barcodeReceivePart": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Неактивный", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Эта компания помечена как неактивная", "@inactiveCompany": {}, "inactiveDetail": "Эта часть помечена как неактивная", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Часть не помечена как продаваемая", "@partNotSalable": {}, "partsNone": "Нет компонентов", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Сканировать штрихкод", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Отсканировать штрих-код части от поставщика", "@scanSupplierPart": {}, "scanIntoLocation": "Сканировать в местоположение", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не выбран", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Поставки", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Добавить поставку", "@shipmentAdd": {}, "shipped": "Отгружено", "@shipped": {}, From 541060aa0390bbf25fbd55e8bf4e76a3caad34bb Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 15 May 2024 20:19:34 +1000 Subject: [PATCH 468/746] Print label key (#491) * We now use the plugin key for printing labels * Bump API version for modern label printing * Fix typo --- lib/api.dart | 2 +- lib/labels.dart | 6 +++--- lib/widget/part/part_detail.dart | 4 ++-- lib/widget/stock/location_display.dart | 4 ++-- lib/widget/stock/stock_detail.dart | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 67b076f..1c960f3 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -346,7 +346,7 @@ class InvenTreeAPI { bool get supportsCompanyActiveStatus => isConnected() && apiVersion >= 189; // Does the server support the "modern" (consolidated) label printing API? - bool get supportsModenLabelPrinting => isConnected() && apiVersion >= 197; + bool get supportsModernLabelPrinting => isConnected() && apiVersion >= 198; // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/labels.dart b/lib/labels.dart index c8fadd0..668bbf9 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -59,7 +59,7 @@ Future selectAndPrintLabel( for (var plugin in plugins) { plugin_options.add({ "display_name": plugin.humanName, - "value": InvenTreeAPI().supportsModenLabelPrinting ? plugin.pk : plugin.key + "value": plugin.key, }); } @@ -100,7 +100,7 @@ Future selectAndPrintLabel( showLoadingOverlay(context); - if (InvenTreeAPI().supportsModenLabelPrinting) { + if (InvenTreeAPI().supportsModernLabelPrinting) { // Modern label printing API uses a POST request to a single API endpoint. await InvenTreeAPI().post( @@ -178,7 +178,7 @@ Future>> getLabelTemplates( String url = "/label/template/"; - if (InvenTreeAPI().supportsModenLabelPrinting) { + if (InvenTreeAPI().supportsModernLabelPrinting) { data["model_type"] = labelType; } else { // Legacy label printing API endpoint diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index f9693a1..c310a59 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -250,8 +250,8 @@ class _PartDisplayState extends RefreshableState { if (allowLabelPrinting) { - String model_type = api.supportsModenLabelPrinting ? InvenTreePart().MODEL_TYPE : "part"; - String item_key = api.supportsModenLabelPrinting ? "items" : "part"; + String model_type = api.supportsModernLabelPrinting ? InvenTreePart().MODEL_TYPE : "part"; + String item_key = api.supportsModernLabelPrinting ? "items" : "part"; _labels = await getLabelTemplates( model_type, diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index dcb1372..ece7c27 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -249,8 +249,8 @@ class _LocationDisplayState extends RefreshableState { if (widget.location != null) { - String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "location"; - String item_key = api.supportsModenLabelPrinting ? "items" : "location"; + String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "location"; + String item_key = api.supportsModernLabelPrinting ? "items" : "location"; _labels = await getLabelTemplates( model_type, diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index f44f0dd..12c7dea 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -266,8 +266,8 @@ class _StockItemDisplayState extends RefreshableState { // Request information on labels available for this stock item if (allowLabelPrinting) { - String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "stock"; - String item_key = api.supportsModenLabelPrinting ? "items" : "item"; + String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "stock"; + String item_key = api.supportsModernLabelPrinting ? "items" : "item"; // Clear the existing labels list _labels = await getLabelTemplates( From 9638b782cc877d00783429c1197713bcff2054ea Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 21 May 2024 09:02:29 +1000 Subject: [PATCH 469/746] New Crowdin updates (#493) * New translations app_en.arb (German) * New translations app_en.arb (Italian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Portuguese) --- lib/l10n/de_DE/app_de_DE.arb | 20 +++--- lib/l10n/it_IT/app_it_IT.arb | 100 +++++++++++++++--------------- lib/l10n/pt_PT/app_pt_PT.arb | 114 +++++++++++++++++------------------ lib/l10n/zh_CN/app_zh_CN.arb | 6 +- 4 files changed, 120 insertions(+), 120 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 0cf5cda..cdada25 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "App-Informationen", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Zugewiesen", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Bestand zuweisen", "@allocateStock": {}, "appReleaseNotes": "App-Versionshinweise anzeigen", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode nicht zugewiesen", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Teilebarcode sannen", "@barcodeScanPart": {}, "barcodeReceivePart": "Barcode scannen um Teil zu empfangen", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Server-Einstellungen konfigurieren", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Transfer bestätigen", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Bestätigen Sie Bestandsverschiebungen beim Scannen von Barcodes", "connectionRefused": "Verbindung verweigert", "@connectionRefused": {}, "count": "Zählen", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inaktiv", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Dieses Unternehmen ist als inaktiv markiert", "@inactiveCompany": {}, "inactiveDetail": "Teil als inaktiv gekennzeichnet", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Artikel nicht als verkaufbar markiert", "@partNotSalable": {}, "partsNone": "Keine Teile", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Barcode scannen", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Lieferanten Barcode scannen", "@scanSupplierPart": {}, "scanIntoLocation": "In Lagerorten buchen", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Lieferungen", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Lieferung hinzufügen", "@shipmentAdd": {}, "shipped": "Versandt", "@shipped": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 14917e7..7f3ac09 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Dettagli App", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Allocato", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Alloca stock", "@allocateStock": {}, "appReleaseNotes": "Mostra le note di rilascio dell'app", "@appReleaseNotes": {}, @@ -58,13 +58,13 @@ "@attachmentSelect": {}, "attention": "Attenzione", "@attention": {}, - "available": "Available", + "available": "Disponibile", "@available": {}, "availableStock": "Giacenza Disponibile", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Codici a barre", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Impostazioni codici a barre", "@barcodeSettings": {}, "barcodeAssign": "Assegna Codice A Barre", "@barcodeAssign": {}, @@ -86,13 +86,13 @@ "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Scansione codice a barre in pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Premi oppure tieni premuti per mettere in pausa la scansione", "@barcodeScanPause": {}, "barcodeScanAssign": "Scansiona per assegnare codice a barre", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Input scanner", "@barcodeScanController": {}, "barcodeScanControllerDetail": "Select barcode scanner input source", "@barcodeScanControllerDetail": {}, @@ -134,9 +134,9 @@ "@build": {}, "building": "In Costruzione", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Fotocamera interna", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Utilizza la fotocamera interna per leggere i codici a barre", "@cameraInternalDetail": {}, "cancel": "Annulla", "@cancel": { @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Configurare le impostazioni del server", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Conferma trasferimento", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Conferma trasferimento dettagli stock durante scansione codici a barre", "connectionRefused": "Connessione rifiutata", "@connectionRefused": {}, "count": "Quantità", @@ -179,11 +179,11 @@ }, "credits": "Riconoscimenti", "@credits": {}, - "customer": "Customer", + "customer": "Cliente", "@customer": {}, "customers": "Clienti", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Riferimento cliente", "@customerReference": {}, "damaged": "Danneggiato", "@damaged": {}, @@ -225,7 +225,7 @@ "@editLocation": {}, "editNotes": "Modifica Note", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Modifica parametro", "@editParameter": {}, "editPart": "Modifica Articolo", "@editPart": { @@ -279,9 +279,9 @@ "@filterComponent": {}, "filterComponentDetail": "Mostra componenti articoli", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Esterno", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Mostra stock su posizione esterne", "@filterExternalDetail": {}, "filterInStock": "In Giacenza", "@filterInStock": {}, @@ -324,9 +324,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Mostra ordini di vendita", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Mostra bottone ordine di vendita sulla schermata principale", "@homeShowSoDescription": {}, "homeShowSubscribed": "Articoli Sottoscritti", "@homeShowSubscribed": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inattivo", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Questa azienda è contrassegnata come inattiva", "@inactiveCompany": {}, "inactiveDetail": "Questo articolo è contrassegnato come inattivo", "@inactiveDetail": {}, @@ -398,13 +398,13 @@ "@issueOrder": {}, "itemInLocation": "Elemento già in posizione", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "L'elemento è stato rimosso", "@itemDeleted": {}, "keywords": "Parole Chiave", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Etichetta in stampa", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Abilita stampa etichette", "@labelPrintingDetail": {}, "labelTemplate": "Modello Etichetta", "@labelTemplate": {}, @@ -420,7 +420,7 @@ "@lastUpdated": {}, "level": "Livello", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Aggiungi Elemento Riga", "@lineItemAdd": {}, "lineItem": "Elemento Riga", "@lineItem": {}, @@ -440,19 +440,19 @@ "@locationNotSet": {}, "locationUpdated": "Ubicazione di magazzino aggiornata", "@locationUpdated": {}, - "login": "Login", + "login": "Accedi", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Inserisci i dettagli di accesso", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Nome utente e password non sono memorizzati localmente", "@loginEnterDetails": {}, "link": "Collegamento", "@link": {}, "lost": "Perso", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Codice articolo produttore", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Produttore", "@manufacturer": {}, "manufacturers": "Produttori", "@manufacturers": {}, @@ -484,23 +484,23 @@ "@onOrder": {}, "onOrderDetails": "Articoli attualmente in ordine", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Orientamento dello schermo", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Orientamento dello schermo (richiede riavvio)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Orizzontale", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Verticale", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Sistema", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "In Sospeso", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Mostra Ordini di Vendita inevasi", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "In ritardo", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Mostra Ordini di Vendita in ritardo", "@overdueDetail": {}, "packaging": "Confezionamento", "@packaging": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Parte non contrassegnata come vendibile", "@partNotSalable": {}, "partsNone": "Nessun Articolo", "@partsNone": {}, @@ -590,7 +590,7 @@ "@profileEdit": {}, "profileDelete": "Elimina Profilo Del Server", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Disconetti", "@profileLogout": {}, "profileName": "Nome Profilo", "@profileName": {}, @@ -604,11 +604,11 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Tocca per creare o selezionare un profilo", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Codice del progetto", "@projectCode": {}, "purchaseOrder": "Ordine d'acquisto", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Nuovo Ordine di Acquisto", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifica ordine d'acquisto", "@purchaseOrderEdit": {}, @@ -636,7 +636,7 @@ "@queryNoResults": {}, "received": "Ricevuto", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Visualizza elementi ricevuti", "@receivedFilterDetail": {}, "receiveItem": "Ricevi Articolo", "@receiveItem": {}, @@ -714,15 +714,15 @@ }, "returned": "Restituito", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Ordini di Vendita", "@salesOrder": {}, "salesOrders": "Ordini di vendita", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Nuovo Ordine di Vendita", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Modifica Ordine di Vendita", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Ordine di vendita aggiornato", "@salesOrderUpdated": {}, "save": "Salva", "@save": { @@ -736,11 +736,11 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scansiona questo elemento nell'ubicazione", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Scanner esterno", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Usa lo scanner esterno per leggere i codici a barre (modalità cuneo)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Scansiona Parti Ricevute", "@scanReceivedParts": {}, "search": "Cerca", "@search": { diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 0f4d628..32879d8 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Detalhes do App", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Alocado", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Alocar estoque", "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, @@ -58,17 +58,17 @@ "@attachmentSelect": {}, "attention": "Aviso", "@attention": {}, - "available": "Available", + "available": "Disponível", "@available": {}, "availableStock": "Stock disponível", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Códigos de barras", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Definições do código de barras", "@barcodeSettings": {}, "barcodeAssign": "Atribuir Código de Barras", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Digitalize o código de barras personalizado para atribuir", "@barcodeAssignDetail": {}, "barcodeAssigned": "Código de barras atribuído", "@barcodeAssigned": {}, @@ -82,33 +82,33 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Digitalizar o código de barras da parte", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Digitalize o código de barras para receber a parte", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Verificação do código de barras pausada", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Toque ou segure para pausar a verificação", "@barcodeScanPause": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Entrada do Scanner", "@barcodeScanController": {}, "barcodeScanControllerDetail": "Select barcode scanner input source", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Atraso na entrada do código de barras", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Atraso entre digitalizações de código de barras", "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Buscar itens de estoque neste local", "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear Localização", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Modo de varredura única", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Pausar leitor de código de barras após cada verificação", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado no local", "@barcodeScanIntoLocationSuccess": {}, @@ -134,15 +134,15 @@ "@build": {}, "building": "Compilando", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Câmera Interna", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Usar a câmera interna para ler códigos de barras", "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Cancelar pedido", "@cancelOrder": {}, "category": "Categoria", "@category": {}, @@ -164,7 +164,7 @@ "@companies": {}, "configureServer": "Configurar os parâmetros do servidor de email", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmar transferência", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Conexão recusada", @@ -179,27 +179,27 @@ }, "credits": "Créditos", "@credits": {}, - "customer": "Customer", + "customer": "Cliente", "@customer": {}, "customers": "Clientes", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Referência do Cliente", "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "Modo Noturno", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Ativar modo noturno", "@darkModeEnable": {}, "delete": "Excluir", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Falha ao excluir", "@deleteFailed": {}, "deletePart": "Excluir esta parte", "@deletePart": {}, "deletePartDetail": "Remover esta peça da base de dados", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Excluído com sucesso", "@deleteSuccess": {}, "description": "Descrição", "@description": {}, @@ -225,7 +225,7 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Editar Parâmetro", "@editParameter": {}, "editPart": "Editar a peça", "@editPart": { @@ -233,7 +233,7 @@ }, "editItem": "Editar Item do Estoque", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Editar item de linha", "@editLineItem": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, @@ -251,15 +251,15 @@ "@errorDetails": {}, "errorFetch": "Erro ao recolher dados do servidor", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Erro ao solicitar funções de usuário do servidor", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Erro ao solicitar dados do plugin do servidor", "@errorPluginInfo": {}, "errorReporting": "Comunicação de Erros", "@errorReporting": {}, "errorReportUpload": "Enviar relatórios de erro", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Enviar relatórios de erros e registos anónimos", "@errorReportUploadDetails": {}, "feedback": "Feedback", "@feedback": {}, @@ -267,66 +267,66 @@ "@feedbackError": {}, "feedbackSuccess": "Feedback submitted", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Ativo", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Mostrar partes ativas", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Montado", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Mostrar partes montadas", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Componente", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Exibir partes do componente", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Externo", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Mostrar estoque em locais externos", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "Em Estoque", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Mostrar peças que têm estoque", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serializado", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Mostrar itens de estoque serializados", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Modelo", "@filterTemplate": {}, "filterTemplateDetail": "Show template parts", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Rastreável", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Mostrar partes rastreáveis", "@filterTrackableDetail": {}, "filterVirtual": "Virtual", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Mostrar peças virtuais", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Opções de filtro", "@filteringOptions": {}, "formatException": "Format Exception", "@formatException": {}, "formatExceptionJson": "JSON data format exception", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Erro de formulário", "@formError": {}, - "history": "History", + "history": "Histórico", "@history": { "description": "history" }, - "home": "Home", + "home": "Início", "@homeScreen": {}, - "homeScreen": "Home Screen", - "homeScreenSettings": "Configure home screen settings", + "homeScreen": "Ecrã inicial", + "homeScreenSettings": "Definir as configurações da tela inicial", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Mostrar Pedido de Compras", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Mostrar botão de pedido de compra na tela inicial", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Mostrar Pedidos de Vendas", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Mostrar botão de pedido de compra na tela inicial", "@homeShowSoDescription": {}, "homeShowSubscribed": "Subscribed Parts", "@homeShowSubscribed": {}, diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 369914e..472dab1 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "配置服务器的设置", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "确认转移", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "扫描条形码时确认库存转移详情", "connectionRefused": "连接被拒绝", "@connectionRefused": {}, "count": "数量", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "未激活", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "此公司被标记为不活跃", "@inactiveCompany": {}, "inactiveDetail": "此零件已被标为未激活", "@inactiveDetail": {}, From 349b3d43667aa79cc790ee75af466072f173b78c Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 30 May 2024 19:03:36 +1000 Subject: [PATCH 470/746] New Crowdin updates (#495) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 20 ++++++++++---------- lib/l10n/pt_BR/app_pt_BR.arb | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 62ca798..846ce3e 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Detalles de la app", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Asignado", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Asignar stock", "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, @@ -58,13 +58,13 @@ "@attachmentSelect": {}, "attention": "Atención", "@attention": {}, - "available": "Available", + "available": "Disponible", "@available": {}, "availableStock": "Inventario Disponible", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Códigos de barras", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Ajustes de códigos de barras", "@barcodeSettings": {}, "barcodeAssign": "Asignar código de barras", "@barcodeAssign": {}, @@ -187,9 +187,9 @@ "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "Modo oscuro", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Activar modo oscuro", "@darkModeEnable": {}, "delete": "Eliminar", "@delete": {}, @@ -440,7 +440,7 @@ "@locationNotSet": {}, "locationUpdated": "Ubicación de stock actualizada", "@locationUpdated": {}, - "login": "Login", + "login": "Iniciar sesión", "@login": {}, "loginEnter": "Enter login details", "@loginEnter": {}, @@ -452,7 +452,7 @@ "@lost": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Fabricante", "@manufacturer": {}, "manufacturers": "Fabricantes", "@manufacturers": {}, @@ -492,7 +492,7 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Sistema", "@orientationSystem": {}, "outstanding": "Outstanding", "@outstanding": {}, diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index f98ddee..bfea033 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Detalhes do aplicativo", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Alocado", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Estoque alocado", "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras não atribuído", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Escanear código de barras de peça", "@barcodeScanPart": {}, "barcodeReceivePart": "Digitalize o código de barras para receber a parte", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Definir as configurações do servidor", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmar Transferência", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Confirmar detalhes de transferência de estoque quando escanear código de barras", "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contar", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inativo", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Esta empresa está marcada como inativa", "@inactiveCompany": {}, "inactiveDetail": "Este produto esta marcado como inativo", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Peça não marcada como vendível", "@partNotSalable": {}, "partsNone": "Sem peças", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Scanear Cod Bar", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Escanear código de barras de peça de fornecedor", "@scanSupplierPart": {}, "scanIntoLocation": "Scan para localizacao", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor não selecionado", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Envios", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Adicionar envio", "@shipmentAdd": {}, "shipped": "Enviado", "@shipped": {}, From 4302f542dcd2ca6013969986607c8878986c9c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Nuno?= <49878220+BaTaTaAdb@users.noreply.github.com> Date: Sat, 1 Jun 2024 00:21:28 +0100 Subject: [PATCH 471/746] Update README.md (#496) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d59af46..b3f1336 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,17 @@ We use the [invoke](https://www.pyinvoke.org) to run some core tasks - you will Initial project setup (after you have installed all required dev tools) is as follows: -Install required flutter packages: -``` -flutter pub get -``` - Generate initial translation files: ``` invoke translate ``` +Install required flutter packages: +``` +flutter pub get +``` + You should now be ready to debug on a connected or emulated device! ### Building Release Versions @@ -52,4 +52,4 @@ Build iOS release: ``` invoke ios -``` \ No newline at end of file +``` From 7575ba0136935240b203296aecd56a994f43e1fb Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Jun 2024 21:46:01 +1000 Subject: [PATCH 472/746] New Crowdin updates (#497) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 82 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 32879d8..9cdcb95 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -94,7 +94,7 @@ "@barcodeScanAssign": {}, "barcodeScanController": "Entrada do Scanner", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Selecionar fonte de entrada do leitor de códigos de barras", "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Atraso na entrada do código de barras", "@barcodeScanDelay": {}, @@ -128,7 +128,7 @@ "@billOfMaterials": {}, "bom": "Lista de Materiais", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Mostrar Lista de Materiais", "@bomEnable": {}, "build": "Compilar", "@build": {}, @@ -166,7 +166,7 @@ "@configureServer": {}, "confirmScan": "Confirmar transferência", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Confirmar a transferência de estoque ao ler códigos de barras", "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contagem", @@ -261,11 +261,11 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Enviar relatórios de erros e registos anónimos", "@errorReportUploadDetails": {}, - "feedback": "Feedback", + "feedback": "Comentários", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Erro ao enviar comentário", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Comentário enviado", "@feedbackSuccess": {}, "filterActive": "Ativo", "@filterActive": {}, @@ -293,7 +293,7 @@ "@filterSerializedDetail": {}, "filterTemplate": "Modelo", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Mostrar partes do modelo", "@filterTemplateDetail": {}, "filterTrackable": "Rastreável", "@filterTrackable": {}, @@ -305,9 +305,9 @@ "@filterVirtualDetail": {}, "filteringOptions": "Opções de filtro", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Formatar erro", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "Erro de formatação de data JSON", "@formatExceptionJson": {}, "formError": "Erro de formulário", "@formError": {}, @@ -328,47 +328,47 @@ "@homeShowSo": {}, "homeShowSoDescription": "Mostrar botão de pedido de compra na tela inicial", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Peças Subscritas", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Mostrar partes subscritas na tela inicial", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Mostrar Fornecedores", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Mostrar botão de fornecedores na tela inicial", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "Mostrar Fabricantes", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Mostrar botão de fabricantes na tela inicial", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Mostrar Clientes", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Mostrar botão de clientes na tela inicial", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Erro no envio da imagem", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Imagem enviada", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Inativo", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Esta empresa está marcada como inativa", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "Este produto está marcado como inativo", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "Incluir Subcategorias", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "Mostrar resultados de subcategorias", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "Incluir sub-região", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Mostrar resultados das sub-regiões", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "Detalhes de perfil incompletos", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "Número interno do produto", "@internalPartNumber": {}, - "info": "Info", + "info": "Informações", "@info": {}, - "inProduction": "In Production", + "inProduction": "Em Produção", "@inProduction": {}, "inProductionDetail": "This stock item is in production", "@inProductionDetail": {}, @@ -440,21 +440,21 @@ "@locationNotSet": {}, "locationUpdated": "Stock location updated", "@locationUpdated": {}, - "login": "Login", + "login": "Entrar", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Introduza os seus credenciais", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Nome de utilizador e palavra-passe não são armazenados localmente", "@loginEnterDetails": {}, "link": "Link", "@link": {}, - "lost": "Lost", + "lost": "Perdido", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Número da Peça do Fabricante", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Fabricante", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "Fabricantes", "@manufacturers": {}, "missingData": "Missing Data", "@missingData": {}, @@ -492,13 +492,13 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Sistema", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Pendente", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Mostrar pedidos pendentes", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Em atraso", "@overdue": {}, "overdueDetail": "Show overdue orders", "@overdueDetail": {}, From 715cd069468263e3b28afa8f5b5da47ecabf36f7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Jun 2024 21:50:24 +1000 Subject: [PATCH 473/746] Long sn fix (#499) * Improve tasks.py - Works from any subdir now * Update stock detail display * FIx width of "serial" column in stock item list --- lib/widget/stock/stock_detail.dart | 4 ++-- lib/widget/stock/stock_list.dart | 17 ++++++++++------- tasks.py | 8 +++++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 12c7dea..b98b2d4 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -467,7 +467,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text("${widget.item.partName}"), subtitle: Text("${widget.item.partDescription}"), leading: InvenTreeAPI().getThumbnail(widget.item.partImage), - trailing: Text( + trailing: widget.item.isSerialized() ? null : Text( widget.item.quantityString(), style: TextStyle( fontSize: 20, @@ -548,7 +548,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().serialNumber), leading: FaIcon(FontAwesomeIcons.hashtag), - trailing: Text("${widget.item.serialNumber}"), + subtitle: Text("${widget.item.serialNumber}"), ) ); } else { diff --git a/lib/widget/stock/stock_list.dart b/lib/widget/stock/stock_list.dart index c24c35c..dd36a30 100644 --- a/lib/widget/stock/stock_list.dart +++ b/lib/widget/stock/stock_list.dart @@ -133,14 +133,17 @@ class _PaginatedStockItemListState extends PaginatedSearchState StockDetailWidget(item))); diff --git a/tasks.py b/tasks.py index feda09d..04b6830 100644 --- a/tasks.py +++ b/tasks.py @@ -1,5 +1,6 @@ """Invoke tasks for building the app""" +import os import sys from invoke import task @@ -13,8 +14,13 @@ def clean(c): @task def translate(c): """Update translation files""" + + here = os.path.dirname(__file__) + l10_dir = os.path.join(here, 'lib', 'l10n') + l10_dir = os.path.abspath(l10_dir) + python = 'python3' if sys.platform.lower() == 'darwin' else 'python' - c.run(f"cd lib/l10n && {python} collect_translations.py") + c.run(f"cd {l10_dir} && {python} collect_translations.py") @task(pre=[clean, translate]) From e600c5f6b5711d44cd05a1bbf85b2570ae6ef237 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Jun 2024 21:58:54 +1000 Subject: [PATCH 474/746] Update release notes (#500) --- assets/release_notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 7404407..4adbc4b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,7 +1,8 @@ -### 0.15.0 - May 2024 +### 0.15.0 - June 2024 --- - Support modern label printing API +- Improved display of stock item serial numbers - Updated translations ### 0.14.3 - April 2024 From aed07514dd32141cd8b56a212a902e8a1c05af97 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Jun 2024 13:37:02 +1000 Subject: [PATCH 475/746] New translations app_en.arb (Portuguese) (#502) --- lib/l10n/pt_PT/app_pt_PT.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 9cdcb95..6c88882 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -370,13 +370,13 @@ "@info": {}, "inProduction": "Em Produção", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "Este item de estoque está em produção", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Produto Interno", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "Hostname inválido", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "O hostname fornecido é inválido", "@invalidHostDetails": {}, "invalidPart": "Invalid Part", "@invalidPart": {}, From b6d5d017ec07aa52558d30cefd9d1a0a799c51ec Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Jun 2024 16:35:40 +1000 Subject: [PATCH 476/746] updates for iOS build (#503) - Required to meet latest apple store --- ios/Runner.xcodeproj/project.pbxproj | 16 +++++++++------- .../xcshareddata/WorkspaceSettings.xcsettings | 5 +++++ pubspec.yaml | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 044f417..3b4c00d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -391,6 +390,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -399,7 +399,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -424,7 +424,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -475,6 +475,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -489,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -532,6 +533,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -540,7 +542,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -565,7 +567,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -598,7 +600,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/pubspec.yaml b/pubspec.yaml index 0589baa..a708771 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.15.0+82 +version: 0.15.0+83 environment: sdk: ">=2.19.5 <3.13.0" From c3eb1a5fcaeacf4b96f9719f77dbe254a94b96a3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Jun 2024 22:14:20 +1000 Subject: [PATCH 477/746] New Crowdin updates (#504) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Romanian) --- lib/l10n/es_MX/app_es_MX.arb | 20 +- lib/l10n/ro_RO/app_ro_RO.arb | 1009 ++++++++++++++++++++++++++++++++++ 2 files changed, 1019 insertions(+), 10 deletions(-) create mode 100644 lib/l10n/ro_RO/app_ro_RO.arb diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index b0688a8..ea4924e 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Detalles de la app", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Asignado", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Asignar existencias", "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, @@ -82,11 +82,11 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Escanear código de barras de parte", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Escaneo de código de barras en pausa", "@barodeScanPaused": {}, "barcodeScanPause": "Tap or hold to pause scanning", "@barcodeScanPause": {}, @@ -420,7 +420,7 @@ "@lastUpdated": {}, "level": "Nivel", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Añadir Artículo de Línea", "@lineItemAdd": {}, "lineItem": "Artículo del pedido", "@lineItem": {}, @@ -440,9 +440,9 @@ "@locationNotSet": {}, "locationUpdated": "Ubicación de inventario actualizada", "@locationUpdated": {}, - "login": "Login", + "login": "Iniciar sesión", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Ingresar datos de acceso", "@loginEnter": {}, "loginEnterDetails": "Username and password are not stored locally", "@loginEnterDetails": {}, @@ -810,11 +810,11 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Envíos", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Añadir Envío", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Enviado", "@shipped": {}, "sku": "SKU", "@sku": {}, diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb new file mode 100644 index 0000000..d90b9c5 --- /dev/null +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -0,0 +1,1009 @@ +{ + "@@locale": "ro", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file From e8373944950ba9304822388e8592c357a4a9508e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Jun 2024 23:16:01 +1000 Subject: [PATCH 478/746] Modern attachments (#505) * Minimum API version is now 100 * Remove old API features - Anything below API v100 no longer supported * Reefactor attachment widget to support modern attachment API * Filter and display attachments correctly * Refactor --- lib/api.dart | 39 +++----------- lib/barcode/barcode.dart | 7 +-- lib/inventree/company.dart | 5 +- lib/inventree/model.dart | 38 ++++++++++++-- lib/inventree/part.dart | 9 ++-- lib/inventree/purchase_order.dart | 5 +- lib/inventree/sales_order.dart | 5 +- lib/inventree/stock.dart | 10 ++-- lib/settings/about.dart | 16 +++--- lib/widget/attachment_widget.dart | 29 ++++++++--- lib/widget/company/company_detail.dart | 56 +++++++++------------ lib/widget/drawer.dart | 20 ++++---- lib/widget/order/purchase_order_detail.dart | 4 +- lib/widget/order/sales_order_detail.dart | 4 +- lib/widget/part/part_detail.dart | 28 ++++------- lib/widget/stock/location_display.dart | 16 +++--- lib/widget/stock/stock_detail.dart | 23 +++------ test/api_test.dart | 4 -- 18 files changed, 151 insertions(+), 167 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 1c960f3..968e43f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -187,7 +187,8 @@ class InvenTreeAPI { } // Minimum required API version for server - static const _minApiVersion = 20; + // 2023-03-04 + static const _minApiVersion = 100; bool _strictHttps = false; @@ -282,30 +283,6 @@ class InvenTreeAPI { String get serverVersion => (serverInfo["version"] ?? "") as String; int get apiVersion => (serverInfo["apiVersion"] ?? 1) as int; - // Plugins enabled at API v34 and above - bool get pluginsEnabled => apiVersion >= 34 && (serverInfo["plugins_enabled"] ?? false) as bool; - - // API endpoint for receiving purchase order line items was introduced in v12 - bool get supportsPoReceive => apiVersion >= 12; - - // Notification support requires API v25 or newer - bool get supportsNotifications => isConnected() && apiVersion >= 25; - - // Return True if the API supports 'settings' (requires API v46) - bool get supportsSettings => isConnected() && apiVersion >= 46; - - // Part parameter support requires API v56 or newer - bool get supportsPartParameters => isConnected() && apiVersion >= 56; - - // Supports 'modern' barcode API (v80 or newer) - bool get supportModernBarcodes => isConnected() && apiVersion >= 80; - - // Structural categories requires API v83 or newer - bool get supportsStructuralCategories => isConnected() && apiVersion >= 83; - - // Company attachments require API v95 or newer - bool get supportCompanyAttachments => isConnected() && apiVersion >= 95; - // Consolidated search request API v102 or newer bool get supportsConsolidatedSearch => isConnected() && apiVersion >= 102; @@ -346,7 +323,11 @@ class InvenTreeAPI { bool get supportsCompanyActiveStatus => isConnected() && apiVersion >= 189; // Does the server support the "modern" (consolidated) label printing API? - bool get supportsModernLabelPrinting => isConnected() && apiVersion >= 198; + bool get supportsModernLabelPrinting => isConnected() && apiVersion >= 201; + + // Does the server support the "modern" (consolidated) attachment API? + // Ref: https://github.com/inventree/InvenTree/pull/7420 + bool get supportsModernAttachments => isConnected() && apiVersion >= 207; // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; @@ -1517,7 +1498,6 @@ class InvenTreeAPI { Map _userSettings = {}; Future getGlobalSetting(String key) async { - if (!supportsSettings) return ""; InvenTreeGlobalSetting? setting = _globalSettings[key]; @@ -1543,7 +1523,6 @@ class InvenTreeAPI { } Future getUserSetting(String key) async { - if (!supportsSettings) return ""; InvenTreeUserSetting? setting = _userSettings[key]; @@ -1687,10 +1666,6 @@ class InvenTreeAPI { return; } - if (!supportsNotifications) { - return; - } - InvenTreeNotification().count(filters: {"read": "false"}).then((int n) { notification_counter = n; }); diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index fead1b3..64af533 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -341,12 +341,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { } else { String barcode; - if (InvenTreeAPI().supportModernBarcodes) { - barcode = (data["barcode_data"] ?? "") as String; - } else { - // Legacy barcode API - barcode = (data["hash"] ?? data["barcode_hash"] ?? "") as String; - } + barcode = (data["barcode_data"] ?? "") as String; if (barcode.isEmpty) { barcodeFailureTone(); diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 94b71b1..b9ac214 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -106,7 +106,10 @@ class InvenTreeCompanyAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "company"; @override - String get URL => "company/attachment/"; + String get REF_MODEL_TYPE => "company"; + + @override + String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "company/attachment/"; @override InvenTreeModel createFromJson(Map json) => InvenTreeCompanyAttachment.fromJson(json); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 747dc26..35cfc12 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -938,9 +938,17 @@ class InvenTreeAttachment extends InvenTreeModel { InvenTreeAttachment.fromJson(Map json) : super.fromJson(json); + @override + String get URL => "attachment/"; + // Override this reference field for any subclasses + // Note: This is used for the *legacy* attachment API String get REFERENCE_FIELD => ""; + // Override this reference field for any subclasses + // Note: This is used for the *modern* attachment API + String get REF_MODEL_TYPE => ""; + String get attachment => getString("attachment"); // Return the filename of the attachment @@ -989,15 +997,39 @@ class InvenTreeAttachment extends InvenTreeModel { } } - Future uploadAttachment(File attachment, int parentId, {String comment = "", Map fields = const {}}) async { + // Return a count of how many attachments exist against the specified model ID + Future countAttachments(int modelId) { + + Map filters = {}; + + if (InvenTreeAPI().supportsModernAttachments) { + filters["model_type"] = REF_MODEL_TYPE; + filters["model_id"] = modelId.toString(); + } else { + filters[REFERENCE_FIELD] = modelId.toString(); + } + + return count(filters: filters); + } + + Future uploadAttachment(File attachment, String modelType, int modelId, {String comment = "", Map fields = const {}}) async { // Ensure that the correct reference field is set Map data = Map.from(fields); - data[REFERENCE_FIELD] = parentId.toString(); + String url = URL; + + if (InvenTreeAPI().supportsModernAttachments) { + // All attachments are stored in a consolidated table + url = "attachment/"; + data["model_id"] = modelId.toString(); + data["model_type"] = modelType; + } else { + data[REFERENCE_FIELD] = modelId.toString(); + } final APIResponse response = await InvenTreeAPI().uploadFile( - URL, + url, attachment, method: "POST", name: "attachment", diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 61e1c27..1102393 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -36,10 +36,6 @@ class InvenTreePartCategory extends InvenTreeModel { "structural": {}, }; - if (!api.supportsStructuralCategories) { - fields.remove("structural"); - } - return fields; } @@ -475,7 +471,10 @@ class InvenTreePartAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "part"; @override - String get URL => "part/attachment/"; + String get REF_MODEL_TYPE => "part"; + + @override + String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "part/attachment/"; @override InvenTreeModel createFromJson(Map json) => InvenTreePartAttachment.fromJson(json); diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index fab3672..ac8973d 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -237,7 +237,10 @@ class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "order"; @override - String get URL => "order/po/attachment/"; + String get REF_MODEL_TYPE => "purchaseorder"; + + @override + String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "order/po/attachment/"; @override InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrderAttachment.fromJson(json); diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index b23d8eb..0002adc 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -280,6 +280,9 @@ class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "order"; @override - String get URL => "order/so/attachment/"; + String get REF_MODEL_TYPE => "salesorder"; + + @override + String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "order/so/attachment/"; } diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index b9c4036..4d12553 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -635,11 +635,13 @@ class InvenTreeStockItemAttachment extends InvenTreeAttachment { String get REFERENCE_FIELD => "stock_item"; @override - String get URL => "stock/attachment/"; + String get REF_MODEL_TYPE => "stockitem"; + + @override + String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "stock/attachment/"; @override InvenTreeModel createFromJson(Map json) => InvenTreeStockItemAttachment.fromJson(json); - } @@ -669,10 +671,6 @@ class InvenTreeStockLocation extends InvenTreeModel { "structural": {}, }; - if (!api.supportsStructuralCategories) { - fields.remove("structural"); - } - return fields; } diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 1bec376..880da20 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -121,15 +121,13 @@ class InvenTreeAboutWidget extends StatelessWidget { ); // Display extra tile if the server supports plugins - if (InvenTreeAPI().pluginsEnabled) { - tiles.add( - ListTile( - title: Text(L10().pluginSupport), - subtitle: Text(L10().pluginSupportDetail), - leading: FaIcon(FontAwesomeIcons.plug), - ) - ); - } + tiles.add( + ListTile( + title: Text(L10().pluginSupport), + subtitle: Text(L10().pluginSupportDetail), + leading: FaIcon(FontAwesomeIcons.plug), + ) + ); } else { tiles.add( diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 1a31993..e182df0 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -6,6 +6,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:one_context/one_context.dart"; import "package:url_launcher/url_launcher.dart"; +import "package:inventree/api.dart"; import "package:inventree/l10.dart"; import "package:inventree/app_colors.dart"; @@ -25,10 +26,10 @@ import "package:inventree/widget/refreshable_state.dart"; */ class AttachmentWidget extends StatefulWidget { - const AttachmentWidget(this.attachment, this.referenceId, this.hasUploadPermission) : super(); + const AttachmentWidget(this.attachmentClass, this.modelId, this.hasUploadPermission) : super(); - final InvenTreeAttachment attachment; - final int referenceId; + final InvenTreeAttachment attachmentClass; + final int modelId; final bool hasUploadPermission; @override @@ -74,7 +75,9 @@ class _AttachmentWidgetState extends RefreshableState { if (file == null) return; showLoadingOverlay(context); - final bool result = await widget.attachment.uploadAttachment(file, widget.referenceId); + + final bool result = await widget.attachmentClass.uploadAttachment(file, widget.attachmentClass.MODEL_TYPE, widget.modelId); + hideLoadingOverlay(); if (result) { @@ -131,14 +134,24 @@ class _AttachmentWidgetState extends RefreshableState { @override Future request(BuildContext context) async { - await widget.attachment.list( - filters: { - widget.attachment.REFERENCE_FIELD: widget.referenceId.toString() - } + Map filters = {}; + + if (InvenTreeAPI().supportsModernAttachments) { + filters["model_type"] = widget.attachmentClass.MODEL_TYPE; + filters["model_id"] = widget.modelId.toString(); + } else { + filters[widget.attachmentClass.REFERENCE_FIELD] = widget.modelId.toString(); + } + + await widget.attachmentClass.list( + filters: filters ).then((var results) { attachments.clear(); + print("Found ${results.length} results:"); + for (var result in results) { + print(result.toString()); if (result is InvenTreeAttachment) { attachments.add(result); } diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 9d098aa..57cdc38 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -188,19 +188,14 @@ class _CompanyDetailState extends RefreshableState { } }); - if (api.supportCompanyAttachments) { - InvenTreeCompanyAttachment().count( - filters: { - "company": widget.company.pk.toString() - } - ).then((value) { - if (mounted) { - setState(() { - attachmentCount = value; - }); - } - }); - } + InvenTreeCompanyAttachment().countAttachments(widget.company.pk) + .then((value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); } Future editCompany(BuildContext context) async { @@ -397,25 +392,24 @@ class _CompanyDetailState extends RefreshableState { )); } - if (api.supportCompanyAttachments) { - tiles.add(ListTile( - title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeCompanyAttachment(), - widget.company.pk, - InvenTreeCompany().canEdit - ) + + tiles.add(ListTile( + title: Text(L10().attachments), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeCompanyAttachment(), + widget.company.pk, + InvenTreeCompany().canEdit ) - ); - } - )); - } + ) + ); + } + )); return tiles; } diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index f38ad33..5dd47c8 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -174,18 +174,16 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add(Divider()); } - if (InvenTreeAPI().supportsNotifications) { - int notification_count = InvenTreeAPI().notification_counter; + int notification_count = InvenTreeAPI().notification_counter; - tiles.add( - ListTile( - leading: FaIcon(FontAwesomeIcons.bell, color: COLOR_ACTION), - trailing: notification_count > 0 ? Text(notification_count.toString()) : null, - title: Text(L10().notifications), - onTap: _notifications, - ) - ); - } + tiles.add( + ListTile( + leading: FaIcon(FontAwesomeIcons.bell, color: COLOR_ACTION), + trailing: notification_count > 0 ? Text(notification_count.toString()) : null, + title: Text(L10().notifications), + onTap: _notifications, + ) + ); tiles.add( ListTile( diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index ae7606a..adc5b47 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -228,9 +228,7 @@ class _PurchaseOrderDetailState extends RefreshableState { supportsProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED"); - InvenTreeSalesOrderAttachment().count(filters: { - "order": widget.order.pk.toString() - }).then((int value) { + InvenTreeSalesOrderAttachment().countAttachments(widget.order.pk).then((int value) { if (mounted) { setState(() { attachmentCount = value; diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index c310a59..c2e044e 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -90,15 +90,13 @@ class _PartDisplayState extends RefreshableState { List actions = []; if (InvenTreePart().canEdit) { - if (api.supportModernBarcodes) { - actions.add( - customBarcodeAction( - context, this, - widget.part.customBarcode, "part", - widget.part.pk - ) - ); - } + actions.add( + customBarcodeAction( + context, this, + widget.part.customBarcode, "part", + widget.part.pk + ) + ); } return actions; @@ -184,18 +182,10 @@ class _PartDisplayState extends RefreshableState { }); // Request the number of parameters for this part - if (api.supportsPartParameters) { - showParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; - } else { - showParameters = false; - } + showParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; // Request the number of attachments - InvenTreePartAttachment().count( - filters: { - "part": part.pk.toString(), - } - ).then((int value) { + InvenTreePartAttachment().countAttachments(part.pk).then((int value) { if (mounted) { setState(() { attachmentCount = value; diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index ece7c27..0251667 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -140,15 +140,13 @@ class _LocationDisplayState extends RefreshableState { } // Assign or un-assign barcodes - if (api.supportModernBarcodes) { - actions.add( - customBarcodeAction( - context, this, - location!.customBarcode, "stocklocation", - location!.pk - ) - ); - } + actions.add( + customBarcodeAction( + context, this, + location!.customBarcode, "stocklocation", + location!.pk + ) + ); } return actions; diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index b98b2d4..b3c829f 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -183,15 +183,13 @@ class _StockItemDisplayState extends RefreshableState { ) ); - if (api.supportModernBarcodes) { - actions.add( - customBarcodeAction( - context, this, - widget.item.customBarcode, - "stockitem", widget.item.pk - ) - ); - } + actions.add( + customBarcodeAction( + context, this, + widget.item.customBarcode, + "stockitem", widget.item.pk + ) + ); } return actions; @@ -246,12 +244,7 @@ class _StockItemDisplayState extends RefreshableState { } // Request the number of attachments - InvenTreeStockItemAttachment().count( - filters: { - "stock_item": widget.item.pk.toString() - } - ).then((int value) { - + InvenTreeStockItemAttachment().countAttachments(widget.item.pk).then((int value) { if (mounted) { setState(() { attachmentCount = value; diff --git a/test/api_test.dart b/test/api_test.dart index a9c7291..86d52d2 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -110,10 +110,6 @@ void main() { // Check supported functions assert(api.apiVersion >= 50); - assert(api.supportsSettings); - assert(api.supportsNotifications); - assert(api.supportsPoReceive); - assert(api.serverInstance.isNotEmpty); assert(api.serverVersion.isNotEmpty); From 464d415115da1ef15e345f4e11026660132888a5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Jun 2024 23:23:16 +1000 Subject: [PATCH 479/746] Version update (#506) --- assets/release_notes.md | 7 +++++++ pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 4adbc4b..6fd5e23 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,10 @@ +### 0.16.0 - June 2024 +--- + +- Add support for new file attachments API +- Drop support for legacy servers with API version < 100 + + ### 0.15.0 - June 2024 --- diff --git a/pubspec.yaml b/pubspec.yaml index a708771..e94e18f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.15.0+83 +version: 0.16.0+85 environment: sdk: ">=2.19.5 <3.13.0" From 5a9a0b08557cdcf50888fba764119f412e19cef9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Jul 2024 10:37:41 +1000 Subject: [PATCH 480/746] New Crowdin updates (#507) * New translations app_en.arb (Turkish) * New translations app_en.arb (Italian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Russian) * New translations app_en.arb (Czech) * New translations app_en.arb (Polish) * New translations app_en.arb (Swedish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (French) * New translations app_en.arb (Turkish) * New translations app_en.arb (French) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Estonian) --- lib/l10n/ar_SA/app_ar_SA.arb | 1009 ++++++++++++++++++++++++++++++++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 18 +- lib/l10n/et_EE/app_et_EE.arb | 1009 ++++++++++++++++++++++++++++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 20 +- lib/l10n/it_IT/app_it_IT.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 202 +++---- lib/l10n/pt_BR/app_pt_BR.arb | 2 +- lib/l10n/pt_PT/app_pt_PT.arb | 2 +- lib/l10n/ro_RO/app_ro_RO.arb | 504 ++++++++--------- lib/l10n/ru_RU/app_ru_RU.arb | 4 +- lib/l10n/sv_SE/app_sv_SE.arb | 12 +- lib/l10n/tr_TR/app_tr_TR.arb | 22 +- lib/l10n/uk_UA/app_uk_UA.arb | 36 +- 13 files changed, 2430 insertions(+), 412 deletions(-) create mode 100644 lib/l10n/ar_SA/app_ar_SA.arb create mode 100644 lib/l10n/et_EE/app_et_EE.arb diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb new file mode 100644 index 0000000..2f370ff --- /dev/null +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -0,0 +1,1009 @@ +{ + "@@locale": "ar", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 9a9440a..a4c1bb2 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Konfigurace nastavení serveru", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Potvrdit převod", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Potvrdit podrobnosti o převodu zásob při skenování čárových kódů", "connectionRefused": "Spojení selhalo", "@connectionRefused": {}, "count": "Počet", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Neaktivní", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Tato společnost je označena jako neaktivní", "@inactiveCompany": {}, "inactiveDetail": "Tato část je označena jako neaktivní", "@inactiveDetail": {}, @@ -506,7 +506,7 @@ "@packaging": {}, "packageName": "Název balíčku", "@packageName": {}, - "parameters": "Paramtery", + "parameters": "Parametry", "@parameters": {}, "parametersSettingDetail": "Zobrazit parametry", "@parametersSettingDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Část není označena jako prodejná", "@partNotSalable": {}, "partsNone": "Žádné díly", "@partsNone": {}, @@ -646,7 +646,7 @@ "@reference": {}, "refresh": "Obnovit", "@refresh": {}, - "refreshing": "Obnovuji…", + "refreshing": "Obnovuji", "@refreshing": {}, "rejected": "Zamítnuto", "@rejected": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Skenovat čarový kód", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Naskenovat čárový kód dílu dodavatele", "@scanSupplierPart": {}, "scanIntoLocation": "Skenovat umístění", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Server není vybrán", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Dodávky", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Přidat dodávku", "@shipmentAdd": {}, "shipped": "Odesláno", "@shipped": {}, diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb new file mode 100644 index 0000000..5aa8b62 --- /dev/null +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -0,0 +1,1009 @@ +{ + "@@locale": "et", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "Ok", + "@ok": { + "description": "OK" + }, + "about": "Info", + "@about": {}, + "accountDetails": "Konto andmed", + "@accountDetails": {}, + "actions": "Tegevused", + "@actions": { + "description": "" + }, + "actionsNone": "Ühtegi toimingut pole saadaval", + "@actionsNone": {}, + "add": "Lisa", + "@add": { + "description": "add" + }, + "addStock": "Lisa ladu", + "@addStock": { + "description": "add stock" + }, + "address": "Aadress", + "@address": {}, + "appAbout": "InvenTree kohta", + "@appAbout": {}, + "appCredits": "Rakenduse autorid", + "@appCredits": {}, + "appDetails": "Rakenduse üksikasjad", + "@appDetails": {}, + "allocated": "Eraldatud", + "@allocated": {}, + "allocateStock": "Jaota laoseis", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "Rakenduse sätted", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Manused", + "@attachments": {}, + "attachImage": "Lisa pilte", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Manust pole", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Valige manus", + "@attachmentSelect": {}, + "attention": "Tähelepanu", + "@attention": {}, + "available": "Saadaval", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Loobu", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Tühista tellimus", + "@cancelOrder": {}, + "category": "Kategooria", + "@category": {}, + "categoryCreate": "Uus kategooria", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Ettevõte", + "@company": {}, + "companyEdit": "Muuda ettevõtet", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Ettevõtted", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Kinnita ülekanne", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Tume režiim", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Kustuta", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Dokumendid", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Allalaadimise viga", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Viga", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Vea üksikasjad", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profiili nimi", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Kogus", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Saadud", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Värskenda", + "@refresh": {}, + "refreshing": "Värskendan", + "@refreshing": {}, + "rejected": "Tagasi lükatud", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Vajalik", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Ligipääs puudub", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Hind kokku", + "@totalPrice": {}, + "transfer": "Ülekanne", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Liiguta ladu", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Tõlgi", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 09e3d12..c8ed9f7 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Détails de l'application", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Allouée", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Allouer un stock", "@allocateStock": {}, "appReleaseNotes": "Afficher les notes de version de l'application", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Code-barres non assigné", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Scanner le code-barres d'une pièce", "@barcodeScanPart": {}, "barcodeReceivePart": "Scannez le code-barres pour recevoir la pièce", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Configurer les paramètres serveur", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmer le transfert", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Confirmation des détails du transfert de stock lors de la lecture des codes-barres", "connectionRefused": "Connexion refusée", "@connectionRefused": {}, "count": "Nombre", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inactif", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Cette entreprise est marquée comme inactive", "@inactiveCompany": {}, "inactiveDetail": "Cette pièce est marquée comme inactive", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Pièce non marquée comme commercialisable", "@partNotSalable": {}, "partsNone": "Aucune pièces", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Scanner un code-barres", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scanner le code-barres des pièces des fournisseurs", "@scanSupplierPart": {}, "scanIntoLocation": "Scanner vers l'emplacement", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Serveur non sélectionné", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Modes de livraison", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Ajouter un mode de livraison", "@shipmentAdd": {}, "shipped": "Expédié", "@shipped": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 7f3ac09..ce96d7e 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Codice a barre non assegnato", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Scansiona codice a barre del prodotto", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 28db846..0c3c22c 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Szczegóły aplikacji", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Przydzielono", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Przydziel zapasy", "@allocateStock": {}, "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", "@appReleaseNotes": {}, @@ -68,7 +68,7 @@ "@barcodeSettings": {}, "barcodeAssign": "Przypisz kod kreskowy", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Zeskanuj własny kod kreskowy, aby przypisać", "@barcodeAssignDetail": {}, "barcodeAssigned": "Kod kreskowy przypisany", "@barcodeAssigned": {}, @@ -82,33 +82,33 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Kod kreskowy nieprzypisany", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Zeskanuj kod kreskowy części", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Zeskanuj kod kreskowy, aby otrzymać część", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Skanowanie kodów kreskowych wstrzymane", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Dotknij lub przytrzymaj, aby wstrzymać skanowanie", "@barcodeScanPause": {}, "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Wejście skanera", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Wybierz źródło danych skanera kodów kreskowych", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Opóźnienie skanowania kodu kreskowego", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Opóźnienie między skanowaniem kodów kreskowych", "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Zeskanuj przedmioty do tej lokalizacji", "@barcodeScanInItems": {}, "barcodeScanLocation": "Skanuj lokalizację zapasów", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Tryb pojedynczego skanowania", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Wstrzymaj skaner kodów kreskowych po każdym skanowaniu", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Zeskanowano do lokacji", "@barcodeScanIntoLocationSuccess": {}, @@ -128,15 +128,15 @@ "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Wyświetl Bill of Materials", "@bomEnable": {}, "build": "Budowa", "@build": {}, "building": "Budowanie", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Kamera wewnętrzna", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Użyj wewnętrznej kamery do odczytu kodów kreskowych", "@cameraInternalDetail": {}, "cancel": "Anuluj", "@cancel": { @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Konfiguruj ustawienia serwera", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Potwierdź transfer", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Potwierdź szczegóły transferu zapasów podczas skanowania kodów kreskowych", "connectionRefused": "Połączenie odrzucone", "@connectionRefused": {}, "count": "Ilość", @@ -193,13 +193,13 @@ "@darkModeEnable": {}, "delete": "Usuń", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Usuwanie nie powiodło się", "@deleteFailed": {}, "deletePart": "Usuń Komponent", "@deletePart": {}, "deletePartDetail": "Usuń ten komponent z bazy danych", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Usuwanie zakończone powodzeniem", "@deleteSuccess": {}, "description": "Opis", "@description": {}, @@ -225,7 +225,7 @@ "@editLocation": {}, "editNotes": "Edytuj Notatki", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Edytuj Parametr", "@editParameter": {}, "editPart": "Edytuj część", "@editPart": { @@ -267,27 +267,27 @@ "@feedbackError": {}, "feedbackSuccess": "Opinia przesłana", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Aktywny", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Pokaż aktywne części", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Złożone", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Pokaż złożone części", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Komponent", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Pokaż części składowe", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Zewnętrzne", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Pokaż zapasy w zewnętrznych lokalizacjach", "@filterExternalDetail": {}, "filterInStock": "Na stanie", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Pokaż części, które są na stanie", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serializowane", "@filterSerialized": {}, "filterSerializedDetail": "Show serialized stock items", "@filterSerializedDetail": {}, @@ -295,15 +295,15 @@ "@filterTemplate": {}, "filterTemplateDetail": "Show template parts", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Możliwość śledzenia", "@filterTrackable": {}, "filterTrackableDetail": "Show trackable parts", "@filterTrackableDetail": {}, "filterVirtual": "Wirtualny", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Pokaż części wirtualne", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Opcje filtrowania", "@filteringOptions": {}, "formatException": "Wyjątek formatowania", "@formatException": {}, @@ -315,7 +315,7 @@ "@history": { "description": "history" }, - "home": "Home", + "home": "Strona główna", "@homeScreen": {}, "homeScreen": "Ekran główny", "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", @@ -324,9 +324,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Pokaż zlecenia sprzedaży", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Pokaż przycisk zleceń sprzedaży na ekrani głównym", "@homeShowSoDescription": {}, "homeShowSubscribed": "Obserwowane części", "@homeShowSubscribed": {}, @@ -372,7 +372,7 @@ "@inProduction": {}, "inProductionDetail": "Ten przedmiot magazynowy jest w produkcji", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Część wewnętrzna", "@internalPart": {}, "invalidHost": "Nieprawidłowa nazwa hosta", "@invalidHost": {}, @@ -390,7 +390,7 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nieprawidłowy login lub hasło", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "Problem", "@issue": {}, "issueDate": "Data Wystawienia", "@issueDate": {}, @@ -402,23 +402,23 @@ "@itemDeleted": {}, "keywords": "Słowa kluczowe", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Drukowanie etykiet", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Włącz drukowanie etykiet", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Szablon etykiety", "@labelTemplate": {}, - "language": "Language", + "language": "Język", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Domyślny język systemu", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Wybierz język", "@languageSelect": {}, "lastStocktake": "Ostatnia inwentaryzacja", "@lastStocktake": {}, "lastUpdated": "Ostatnia aktualizacja", "@lastUpdated": {}, - "level": "Level", + "level": "Poziom", "@level": {}, "lineItemAdd": "Add Line Item", "@lineItemAdd": {}, @@ -428,9 +428,9 @@ "@lineItems": {}, "lineItemUpdated": "Line item updated", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Zlokalizuj element magazynowy", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Zlokalizuj lokalizację zapasów", "@locateLocation": {}, "locationCreate": "Nowa Lokalizacja", "@locationCreate": {}, @@ -440,19 +440,19 @@ "@locationNotSet": {}, "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", "@locationUpdated": {}, - "login": "Login", + "login": "Zaloguj się", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Wprowadź dane logowania", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Nazwa użytkownika i hasło nie są przechowywane lokalnie", "@loginEnterDetails": {}, "link": "Link", "@link": {}, "lost": "Zagubiono", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Numer Części Producenta (MPN)", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Producent", "@manufacturer": {}, "manufacturers": "Producenci", "@manufacturers": {}, @@ -468,7 +468,7 @@ }, "notifications": "Powiadomienia", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Brak nowych powiadomień", "@notificationsEmpty": {}, "noResponse": "Brak odpowiedzi od serwera", "@noResponse": {}, @@ -484,13 +484,13 @@ "@onOrder": {}, "onOrderDetails": "Pozycje obecnie w zamówieniu", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Orientacja ekranu", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Orientacja ekranu (wymaga ponownego uruchomienia)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Poziomo", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Portret", "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, @@ -498,7 +498,7 @@ "@outstanding": {}, "outstandingOrderDetail": "Show outstanding orders", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Zaległe", "@overdue": {}, "overdueDetail": "Show overdue orders", "@overdueDetail": {}, @@ -506,9 +506,9 @@ "@packaging": {}, "packageName": "Nazwa pakietu", "@packageName": {}, - "parameters": "Parameters", + "parameters": "Parametry", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Wyświetl parametry części", "@parametersSettingDetail": {}, "parent": "Nadrzędny", "@parent": {}, @@ -530,13 +530,13 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Część nie oznaczona jako sprzedawalna", "@partNotSalable": {}, "partsNone": "Brak części", "@partsNone": {}, "partNoResults": "Brak komponentów pasujących do zapytania", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "Ustawienia części", "@partSettings": {}, "partsStarred": "Obserwowane części", "@partsStarred": {}, @@ -604,11 +604,11 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Kod projektu", "@projectCode": {}, "purchaseOrder": "Zlecenie Zakupu", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Nowe zlecenie zakupu", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", "@purchaseOrderEdit": {}, @@ -622,7 +622,7 @@ "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Dostępna ilość", "@quantityAvailable": {}, "quantityEmpty": "Ilość jest pusta", "@quantityEmpty": {}, @@ -630,19 +630,19 @@ "@quantityInvalid": {}, "quantityPositive": "Ilość musi być dodatnia", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Wpisz szukaną frazę", "@queryEmpty": {}, "queryNoResults": "Nie znaleziono wyników dla zapytania", "@queryNoResults": {}, "received": "Odebrane", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Pokaż otrzymane elementy", "@receivedFilterDetail": {}, "receiveItem": "Przyjmij artykuły", "@receiveItem": {}, "receivedItem": "Przyjęta Pozycja Magazynowa", "@receivedItem": {}, - "reference": "Reference", + "reference": "Odwołanie", "@reference": {}, "refresh": "Odśwież", "@refresh": {}, @@ -668,9 +668,9 @@ "@results": {}, "request": "Żądanie", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "Żądanie nie powiodło się", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "Żądanie zakończone sukcesem", "@requestSuccessful": {}, "requestingData": "Żądanie danych", "@requestingData": {}, @@ -714,15 +714,15 @@ }, "returned": "Zwrócono", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Zlecenie sprzedaży", "@salesOrder": {}, "salesOrders": "Zlecenia Sprzedaży", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Zlecenie sprzedaży", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Edytuj zlecenie sprzedaży", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Zlecenie sprzedaży zaktualizowane", "@salesOrderUpdated": {}, "save": "Zapisz", "@save": { @@ -730,23 +730,23 @@ }, "scanBarcode": "Skanuj kod kreskowy", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Zeskanuj kod kreskowy dostawcy", "@scanSupplierPart": {}, "scanIntoLocation": "Skanuj do lokacji", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Zeskanuj ten przedmiot w lokalizację", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Zewnętrzny skaner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Użyj zewnętrznego skanera do odczytu kodów kreskowych (tryb klina)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Skanuj otrzymane części", "@scanReceivedParts": {}, "search": "Szukaj", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Wyszukiwanie", "@searching": {}, "searchLocation": "Wyszukaj lokalizację", "@searchLocation": {}, @@ -766,7 +766,7 @@ "@send": {}, "serialNumber": "Numer seryjny", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Numery seryjne", "@serialNumbers": {}, "server": "Serwer", "@server": {}, @@ -808,13 +808,13 @@ "@serverInstance": {}, "serverNotConnected": "Serwer nie podłączony", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Serwer nie wybrany", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Wysyłki", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Dodaj wysyłkę", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Wysłano", "@shipped": {}, "sku": "SKU", "@sku": {}, @@ -832,7 +832,7 @@ "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Aktualna dostępna ilość zapasów", "@stockDetails": {}, "stockItem": "Element magazynowy", "@stockItem": { @@ -898,15 +898,15 @@ "@suppliedParts": {}, "supplier": "Dostawca", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Część dostawcy", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Edytuj część dostawcy", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Numer częsci dostawcy", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Komponenty dostawcy zaktualizowane", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Komponenty dostawcy", "@supplierParts": {}, "suppliers": "Dostawcy", "@suppliers": {}, @@ -916,7 +916,7 @@ "@takePicture": {}, "targetDate": "Data Docelowa", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "Część szablonu nadrzędnego", "@templatePart": {}, "testName": "Nazwa testu", "@testName": {}, @@ -928,7 +928,7 @@ "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Wyświetl wyniki testu elementu magazynowego", "@testResultsDetail": {}, "testResultAdd": "Dodaj wynik testu", "@testResultAdd": {}, @@ -950,7 +950,7 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Cena całkowita", "@totalPrice": {}, "transfer": "Przenieś", "@transfer": { @@ -960,17 +960,17 @@ "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "Przenieś element do innej lokalizacji", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Przenieś lokalizację zapasów", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Przenieś tę lokalizację zapasów do innego", "@transferStockLocationDetail": {}, "translate": "Przetłumacz", "@translate": {}, "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Cena jednostkowa", "@unitPrice": {}, "units": "Jednostki", "@units": {}, @@ -998,7 +998,7 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Wartość jest wymagana", "@valueRequired": {}, - "variants": "Variants", + "variants": "Warianty", "@variants": {}, "version": "Wersja", "@version": {}, diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index bfea033..e7c2b79 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -34,7 +34,7 @@ "@appCredits": {}, "appDetails": "Detalhes do aplicativo", "@appDetails": {}, - "allocated": "Alocado", + "allocated": "Alocar", "@allocated": {}, "allocateStock": "Estoque alocado", "@allocateStock": {}, diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 6c88882..2c77cb4 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -378,7 +378,7 @@ "@invalidHost": {}, "invalidHostDetails": "O hostname fornecido é inválido", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "Peça Inválida", "@invalidPart": {}, "invalidPartCategory": "Invalid Part Category", "@invalidPartCategory": {}, diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index d90b9c5..50a01f3 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -8,551 +8,551 @@ "@ok": { "description": "OK" }, - "about": "About", + "about": "Despre", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "Detalii Cont", "@accountDetails": {}, - "actions": "Actions", + "actions": "Acțiuni", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "Acțiuni indisponibile", "@actionsNone": {}, - "add": "Add", + "add": "Adaugă", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "Adaugă Stoc", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "Adresă", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "Despre InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "Credite Adiționale", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "Detalii Aplicație", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Alocat", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Alocare Stoc", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": "Afișează notele de lansare a aplicației", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "Setări Aplicație", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "Configurare setări aplicație InvenTree", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "Atașamente", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "Atașare imagine", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "Nici un atașament găsit", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "Nici un atașament găsit", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "Selectare atașament", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "Atenție", "@attention": {}, - "available": "Available", + "available": "Disponibil", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "Stoc disponibil", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Coduri de bare", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Setări cod de bare", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "Atribuie codul de bare", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Scanează si atribuie cod de bare custom", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "Cod de bare atribuit", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "Eroare scanare cod de bare", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "Cod de bare deja atribuit", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "Datele hash din codul de bare lipsesc din răspuns", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "Cod de bare negăsit", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "Cod de bare neatribuit", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Scanează cod de bare piesa", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Scanează codul de bare pentru a primi piesa", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Scanare cod de bare întreruptă", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Atingeți sau țineți apăsat pentru a întrerupe scanarea", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "Scanează pentru a atribui cod de bare", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Input Scanner", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Selectați sursa de introducere a codului de bare", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Scanare cod de bare - Pauza", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Pauza intre scanarea codurilor de bare", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "Scanează un cod de bare InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Scanează si Introdu stoc in locație", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "Scanează locație stoc", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Mod Scanare simplă", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Întrerupeți scanerul de coduri de bare după fiecare scanare", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "Introdus In locație", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "Element neintrodus", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "Scanare articol stoc", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Sunet Scanner cod Bare", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "Designează codul de bare", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "Codul de bare nu este recunoscut", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "Cod lot", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "Listă de materiale", "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Afișează lista de materiale", "@bomEnable": {}, - "build": "Build", + "build": "Asamblare", "@build": {}, - "building": "Building", + "building": "Asamblează", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Cameră internă", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Folosește camera internă pentru a citi codurile de bare", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "Anulare", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Anulează comanda", "@cancelOrder": {}, - "category": "Category", + "category": "Categorie", "@category": {}, - "categoryCreate": "New Category", + "categoryCreate": "Categorie nouă", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "Creare categorie nouă de piese", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Categorie piesa actualizată", "@categoryUpdated": {}, - "company": "Company", + "company": "Companie", "@company": {}, - "companyEdit": "Edit Company", + "companyEdit": "Editare companie", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "Nu există companii ce corespund", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "Detalii companie actualizate", "@companyUpdated": {}, - "companies": "Companies", + "companies": "Companii", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "Configurare setări server", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmă transferul", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "confirmScanDetail": "Confirmă detaliile transferului de stoc la scanarea codurilor de bare", + "connectionRefused": "Conexiune refuzată", "@connectionRefused": {}, - "count": "Count", + "count": "Număr", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "Numără Stoc", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "Credite", "@credits": {}, - "customer": "Customer", + "customer": "Client", "@customer": {}, - "customers": "Customers", + "customers": "Clienți", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Referință client", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Deteriorat", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "Mod Întunecat", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Activează modul întunecat", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "Șterge", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Operațiune de ștergere eșuată", "@deleteFailed": {}, - "deletePart": "Delete Part", + "deletePart": "Șterge Piesa", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "Elimină această piesă din baza de date", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Operație de ștergere reușită", "@deleteSuccess": {}, - "description": "Description", + "description": "Descriere", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "Distrus", "@destroyed": {}, - "details": "Details", + "details": "Detalii", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "Documentație", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "Se descarcă fișierul", "@downloading": {}, - "downloadError": "Download Error", + "downloadError": "Eroare la descărcare", "@downloadError": {}, - "edit": "Edit", + "edit": "Editare", "@edit": { "description": "edit" }, - "editCategory": "Edit Category", + "editCategory": "Editează Categoria", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "Editare locație", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "Editează notițele", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Editare Parametru", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "Editează piesa", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "Editează Element Stoc", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Editare element rând", "@editLineItem": {}, - "enterPassword": "Enter password", + "enterPassword": "Introdu parola", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "Introdu numele de utilizator", "@enterUsername": {}, - "error": "Error", + "error": "Eroare", "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "Eroare la crearea intrării in baza de date", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "Eroare la ștergerea intrării in baza de date", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "Detalii eroare", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "Eroare la preluarea datelor de pe server", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Eroare la solicitarea rolurilor utilizatorilor de pe server", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Eroare la solicitarea datelor plugin de pe server", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "Eroare la raportare", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "Încarcă rapoarte de eroare", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Încarcă rapoarte anonime de erori și jurnale de eroare", "@errorReportUploadDetails": {}, "feedback": "Feedback", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Eroare la trimiterea feedback-ului", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Feedback Submis", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Activ", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Arată piesele active", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Asamblate", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Arată piesele asamblate", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Componenta", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Afișare părți componente", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Extern", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Afișare stoc în locații externe", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "În Stoc", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Arată piesele care au stoc", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serializat", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Arată elementele serializate din stoc", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Șablon", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Afișare piese șablon", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Urmăribil", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Arată piesele urmaribile", "@filterTrackableDetail": {}, "filterVirtual": "Virtual", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Arată piesele virtuale", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Opțiuni filtrare", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Excepție format", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "Excepție format JSON", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Eroare Formular", "@formError": {}, - "history": "History", + "history": "Istoric", "@history": { "description": "history" }, - "home": "Home", + "home": "Acasă", "@homeScreen": {}, - "homeScreen": "Home Screen", - "homeScreenSettings": "Configure home screen settings", + "homeScreen": "Ecran principal", + "homeScreenSettings": "Configurați setările ecranului principal", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Arată Comenzile de Achiziție", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Afișați butonul de achiziții pe ecranul principal", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Arată Comenzile de Vânzări", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Afișare buton vânzări pe ecranul principal", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Piese Abonate", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Afișează piesele abonate pe ecranul principal", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Afișează Furnizorii", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Arată butonul furnizorilor pe ecranul principal", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "Afișare producători", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Arată butonul producători pe ecranul principal", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Afișare Clienți", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Arată butonul Clienților pe ecranul principal", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Încărcarea imaginii a eșuat", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Imagine încărcată", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Inactiv", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Această companie este marcată ca inactivă", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "Aceasta piesa este marcata ca inactiva", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "Include subcategoriile", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "Arată rezultatele din subcategorii", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "Include Sublocatii", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Afișare rezultate din sublocații", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "Detalii de profil incomplete", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "Cod piesa intern", "@internalPartNumber": {}, "info": "Info", "@info": {}, - "inProduction": "In Production", + "inProduction": "În Producţie", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "Acest articol din stoc este în producție", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Articol intern", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "Hostname invalid", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "Hostname-ul furnizat este invalid", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "Piesa Invalida", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "Categorie Piesa Invalida", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "Locație de stoc invalidă", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "Articol de stoc invalid", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Articol Furnizor Invalid", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "Combinație de nume utilizator / parolă invalida", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "Problemă", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Data emiterii", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Emite", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "Articol deja in locație", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Articolul a fost eliminat", "@itemDeleted": {}, - "keywords": "Keywords", + "keywords": "Cuvinte cheie", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Printare etichete", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Permite tipărirea etichetei", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Sablon eticheta", "@labelTemplate": {}, - "language": "Language", + "language": "Limba", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Limba de sistem implicită", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Selectează limba", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Ultima verificare de inventar", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "Ultima actualizare", "@lastUpdated": {}, - "level": "Level", + "level": "Nivel", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Adăugare element rând", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Articol Linie", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "Articole linie", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Articol linie actualizat", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Localizare articol stoc", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Localizare locație stoc", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Locație nouă", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "Creează o nouă locație de stoc", "@locationCreateDetail": {}, - "locationNotSet": "No location specified", + "locationNotSet": "Nici o locaţie specificată", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "Locație stoc actualizată", "@locationUpdated": {}, - "login": "Login", + "login": "Autentificare", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Introduceți detaliile de autentificare", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Numele de utilizator și parola nu sunt stocate local", "@loginEnterDetails": {}, "link": "Link", "@link": {}, - "lost": "Lost", + "lost": "Pierdut", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Număr Serie Producător", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Producător", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "Producători", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Date lipsă", "@missingData": {}, - "name": "Name", + "name": "Nume", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "Neconectat", "@notConnected": {}, - "notes": "Notes", + "notes": "Notițe", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Notificări", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Nicio notificare necitită", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Nici un răspuns de la server", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Niciun rezultat", "@noResults": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Nu există subcategorii", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Nicio subcategorie disponibilă", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Număr invalid", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "Pe comandă", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Piese în prezent pe comandă", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Orientare ecran", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Orientarea ecranului (necesită repornire)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Orizontală", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Verticală", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Sistem", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Restant", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Afișează comenzile neîmplinite", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Restant", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Arată comenzile restante", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Ambalaj", "@packaging": {}, - "packageName": "Package Name", + "packageName": "Nume Ambalaj", "@packageName": {}, - "parameters": "Parameters", + "parameters": "Parametri", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Afișează parametrii piesei", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "Părinte", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Categorie Părinte", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "Locație părinte", "@parentLocation": {}, - "part": "Part", + "part": "Piesa", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Piesa Noua", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Creează o nouă piesa în această categorie", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Piesa actualizata", "@partEdited": {}, - "parts": "Parts", + "parts": "Piese", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Piesa nemarcata ca fiind vânduta", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "Nicio Piesa", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "Nicio piesă care se potrivește", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "Setări Piesa", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "Piese Abonate", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "Nu există piese cu stea disponibile", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "Furnizori de piese", "@partSuppliers": {}, "partCategory": "Part Category", "@partCategory": {}, "partCategoryTopLevel": "Top level part category", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "Categorii Piese", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Detalii piesă", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Notite Piesa", "@partNotes": {}, "partStock": "Part Stock", "@partStock": { diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 3651af7..d572768 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -164,7 +164,7 @@ "@companies": {}, "configureServer": "Настройка параметров сервера", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Подтвердить перенос", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Отказано в подключении", @@ -812,7 +812,7 @@ "@serverNotSelected": {}, "shipments": "Поставки", "@shipments": {}, - "shipmentAdd": "Добавить поставку", + "shipmentAdd": "Новое Отправление", "@shipmentAdd": {}, "shipped": "Отгружено", "@shipped": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 0d07c08..208df40 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Appdetaljer", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Allokerad", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Allokera lager", "@allocateStock": {}, "appReleaseNotes": "Visa versionsinfo för app", "@appReleaseNotes": {}, @@ -76,13 +76,13 @@ "@barcodeError": {}, "barcodeInUse": "Streckkoden används redan", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "Streckkodshashdata saknas från svar", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "Ingen träff för streckkod", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "Streckkod inte tilldelad", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Skanna artikelstreckkod", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 2d003a3..a5d4c3e 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Uygulama Detayları", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Tahsis edildi", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Tahsisli stok", "@allocateStock": {}, "appReleaseNotes": "Uygulama yayınlama notları", "@appReleaseNotes": {}, @@ -82,19 +82,19 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barkod atanmış değil", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Parça barkodnu tara", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Tesellüm barkodunu tara", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Barkod tarama duraklatıldı", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Taramayı duraklatmak için dokunun veya basılı tutun", "@barcodeScanPause": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, "barcodeScanController": "Scanner Input", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Barkod tarayıcı girdi kaynağını seç", "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barkod Tarama Gecikmesi", "@barcodeScanDelay": {}, @@ -440,11 +440,11 @@ "@locationNotSet": {}, "locationUpdated": "Stok lokasyonu güncellendi", "@locationUpdated": {}, - "login": "Login", + "login": "Giriş yap", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Giriş bilgilerinizi girin", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Kullanıcı adı ve şifre kutucukları doğru doldurulmadı", "@loginEnterDetails": {}, "link": "Bağlantı", "@link": {}, @@ -590,7 +590,7 @@ "@profileEdit": {}, "profileDelete": "Sunucu profilini sil", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Hesaptan çıkış yap", "@profileLogout": {}, "profileName": "Profil Adı", "@profileName": {}, diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 0f4f74a..638e8f6 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -4,35 +4,35 @@ "@appTitle": { "description": "InvenTree application title string" }, - "ok": "OK", + "ok": "Добре", "@ok": { "description": "OK" }, - "about": "About", + "about": "Інформація про", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "Деталі облікового запису", "@accountDetails": {}, - "actions": "Actions", + "actions": "Дії", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "Немає доступних дій", "@actionsNone": {}, - "add": "Add", + "add": "Додати", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "Додати склад", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "Адреса", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "Про InvenTree", "@appAbout": {}, "appCredits": "Additional app credits", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "Про додаток", "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, @@ -40,7 +40,7 @@ "@allocateStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "Налаштування додатку", "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, @@ -56,23 +56,23 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "Select attachment", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "Попередження", "@attention": {}, - "available": "Available", + "available": "Доступно", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "Доступний склад", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "ШК", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Налаштування штрих-коду", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "Призначити штрих-код", "@barcodeAssign": {}, "barcodeAssignDetail": "Scan custom barcode to assign", "@barcodeAssignDetail": {}, "barcodeAssigned": "Barcode assigned", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "Помилка сканування штрих-коду", "@barcodeError": {}, "barcodeInUse": "Barcode already assigned", "@barcodeInUse": {}, From ea9623490d49beaef68110fed278327c5876bb95 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Jul 2024 13:53:14 +1000 Subject: [PATCH 481/746] Android sdk version (#509) * Bump target SDK version * Update pubspec and release notes * Update sentry version * Downgrade onecontext --- android/app/build.gradle | 4 +- assets/release_notes.md | 5 ++ pubspec.lock | 136 +++++++++++++++++++-------------------- pubspec.yaml | 24 +++---- 4 files changed, 87 insertions(+), 82 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 0a28e9a..c43c9bf 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 33 + compileSdkVersion 34 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -49,7 +49,7 @@ android { defaultConfig { applicationId "inventree.inventree_app" minSdkVersion 21 - targetSdkVersion 33 + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" diff --git a/assets/release_notes.md b/assets/release_notes.md index 6fd5e23..b3c0907 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.16.1 - July 2024 +--- + +- Update base packages for Android + ### 0.16.0 - June 2024 --- diff --git a/pubspec.lock b/pubspec.lock index 26fe112..e7b19e5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -261,10 +261,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" currency_formatter: dependency: "direct main" description: @@ -333,10 +333,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: e6c7ad8e572379df86ea64ef0a5395889fba3954411d47ca021b888d79f8e798 + sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" url: "https://pub.dev" source: hosted - version: "5.2.11" + version: "5.3.1" file_selector_linux: dependency: transitive description: @@ -407,10 +407,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "818cf6c28377ba2c91ed283c96fd712e9c175dd2d2488eb7fc93b6afb9ad2e08" + sha256: "21b085a1c185e46701373866144ced56cfb7a0c33f63c916bb8fe2d0c1491278" url: "https://pub.dev" source: hosted - version: "0.6.13+1" + version: "0.6.19" flutter_overlay_loader: dependency: "direct main" description: @@ -457,10 +457,10 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "875dbb9ec1ad30d68102019ceb682760d06c72747c1c5b7885781b95f88569cc" + sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f" url: "https://pub.dev" source: hosted - version: "10.3.0" + version: "10.7.0" frontend_server_client: dependency: transitive description: @@ -481,10 +481,10 @@ packages: dependency: "direct main" description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_multi_server: dependency: transitive description: @@ -513,10 +513,10 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "841837258e0b42c80946c43443054fc726f5e8aa84a97f363eb9ef0d45b33c14" + sha256: "1f498d086203360cca099d20ffea2963f48c39ce91bdd8a3b6d4a045786b02c8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.8" image_picker_android: dependency: transitive description: @@ -537,10 +537,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 url: "https://pub.dev" source: hosted - version: "0.8.8" + version: "0.8.9+1" image_picker_linux: dependency: transitive description: @@ -633,10 +633,10 @@ packages: dependency: transitive description: name: markdown - sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 + sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "7.2.1" matcher: dependency: transitive description: @@ -697,10 +697,10 @@ packages: dependency: "direct main" description: name: open_filex - sha256: "854aefd72dfd74219dc8c8d1767c34ec1eae64b8399a5be317bddb1ec2108915" + sha256: "74e2280754cf8161e860746c3181db2c996d6c1909c7057b738ede4a469816b8" url: "https://pub.dev" source: hosted - version: "4.3.2" + version: "4.4.0" package_config: dependency: transitive description: @@ -737,50 +737,50 @@ packages: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "51f0d2c554cfbc9d6a312ab35152fc77e2f0b758ce9f1a444a3a1e5b8f3c6b7f" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.2.3" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.2.1" petitparser: dependency: transitive description: @@ -865,82 +865,82 @@ packages: dependency: "direct main" description: name: sembast - sha256: "3875487075df740e3ed0817571c950f015e5f730ff84fa0351849bf002fb4e1b" + sha256: "9a9f0c7aca07043fef857b8b365f41592e48832b61462292699b57978e241c11" url: "https://pub.dev" source: hosted - version: "3.4.6+1" + version: "3.6.0" sentry: dependency: transitive description: name: sentry - sha256: "39c23342fc96105da449914f7774139a17a0ca8a4e70d9ad5200171f7e47d6ba" + sha256: "7342ef4c18932881730ac941a07a6e4cf76fe99cd1ea3bef06e53a6a1402dec0" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "8.3.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: ff68ab31918690da004a42e20204242a3ad9ad57da7e2712da8487060ac9767f + sha256: "475cf49682e4d1eb48caa2577502721bcfdcbb63f215de57b3b246d52f4f7914" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "8.3.0" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.2.1" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.2" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.2.1" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.2" shelf: dependency: transitive description: @@ -1118,66 +1118,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c url: "https://pub.dev" source: hosted - version: "6.1.10" + version: "6.2.4" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" url: "https://pub.dev" source: hosted - version: "6.0.23" + version: "6.2.2" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "0a5af0aefdd8cf820dd739886efb1637f1f24489900204f50984634c07a54815" + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: "4aca1e060978e19b2998ee28503f40b5ba6226819c2b5e3e4d1821e8ccd92198" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" url: "https://pub.dev" source: hosted - version: "2.0.14" + version: "2.2.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.1.1" uuid: dependency: transitive description: @@ -1267,5 +1267,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=3.1.0-185.0.dev <3.13.0" - flutter: ">=3.10.0" + dart: ">=3.1.0 <3.13.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index e94e18f..14efcbe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.0+85 +version: 0.16.1+86 environment: sdk: ">=2.19.5 <3.13.0" @@ -11,35 +11,35 @@ dependencies: audioplayers: ^4.1.0 # Play audio files cached_network_image: ^3.3.1 # Download and cache remote images camera: ^0.10.3 # Camera - cupertino_icons: ^1.0.3 + cupertino_icons: ^1.0.8 currency_formatter: ^2.0.1 datetime_picker_formfield: ^2.0.1 # Date / time picker device_info_plus: ^8.2.2 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields - file_picker: ^5.2.11 # Select files from the device + file_picker: ^5.3.1 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 flutter_localizations: sdk: flutter flutter_localized_locales: ^2.0.4 - flutter_markdown: ^0.6.13+1 # Rendering markdown + flutter_markdown: ^0.6.19 # Rendering markdown flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation - font_awesome_flutter: ^10.3.0 # FontAwesome icon set - http: ^0.13.5 - image_picker: ^1.0.2 # Select or take photos + font_awesome_flutter: ^10.7.0 # FontAwesome icon set + http: ^0.13.6 + image_picker: ^1.0.8 # Select or take photos infinite_scroll_pagination: ^4.0.0 # Let the server do all the work! intl: ^0.18.0 one_context: ^2.1.0 # Dialogs without requiring context - open_filex: ^4.3.2 # Open local files + open_filex: ^4.4.0 # Open local files package_info_plus: ^3.0.2 # App information introspection path: ^1.8.2 - path_provider: ^2.0.12 # Local file storage + path_provider: ^2.1.3 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning - sembast: ^3.4.6+1 # NoSQL data storage - sentry_flutter: ^7.7.0 # Error reporting - url_launcher: ^6.1.10 # Open link in system browser + sembast: ^3.6.0 # NoSQL data storage + sentry_flutter: ^8.3.0 # Error reporting + url_launcher: ^6.2.4 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.11.0 From 856cf9eee49d04a1e391119a020e5e7f659a4a4b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Jul 2024 21:46:41 +1000 Subject: [PATCH 482/746] New translations app_en.arb (Estonian) (#510) --- lib/l10n/et_EE/app_et_EE.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 5aa8b62..ceca1b5 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -283,7 +283,7 @@ "@filterExternal": {}, "filterExternalDetail": "Show stock in external locations", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "Laos", "@filterInStock": {}, "filterInStockDetail": "Show parts which have stock", "@filterInStockDetail": {}, @@ -828,7 +828,7 @@ "@status": {}, "statusCode": "Status Code", "@statusCode": {}, - "stock": "Stock", + "stock": "Ladu", "@stock": { "description": "stock" }, From 8ba10f257862049d1c7438e8a5da379d746232e0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Jul 2024 21:52:28 +1000 Subject: [PATCH 483/746] Revert sentry version (#511) - Caused issues with iOS app build --- pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index e7b19e5..3933b33 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -873,18 +873,18 @@ packages: dependency: transitive description: name: sentry - sha256: "7342ef4c18932881730ac941a07a6e4cf76fe99cd1ea3bef06e53a6a1402dec0" + sha256: "57514bc72d441ffdc463f498d6886aa586a2494fa467a1eb9d649c28010d7ee3" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "7.20.2" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "475cf49682e4d1eb48caa2577502721bcfdcbb63f215de57b3b246d52f4f7914" + sha256: "9723d58470ca43a360681ddd26abb71ca7b815f706bc8d3747afd054cf639ded" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "7.20.2" shared_preferences: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 14efcbe..bc8fc8b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: path_provider: ^2.1.3 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning sembast: ^3.6.0 # NoSQL data storage - sentry_flutter: ^8.3.0 # Error reporting + sentry_flutter: ^7.7.0 # Error reporting url_launcher: ^6.2.4 # Open link in system browser dev_dependencies: From 6ba4fa747e0a222974061ff73ae44b6d376e570e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Jul 2024 12:32:47 +1000 Subject: [PATCH 484/746] Pin specific version of sentry_flutter (#512) --- pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 3933b33..90822c6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -873,18 +873,18 @@ packages: dependency: transitive description: name: sentry - sha256: "57514bc72d441ffdc463f498d6886aa586a2494fa467a1eb9d649c28010d7ee3" + sha256: "39c23342fc96105da449914f7774139a17a0ca8a4e70d9ad5200171f7e47d6ba" url: "https://pub.dev" source: hosted - version: "7.20.2" + version: "7.9.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "9723d58470ca43a360681ddd26abb71ca7b815f706bc8d3747afd054cf639ded" + sha256: ff68ab31918690da004a42e20204242a3ad9ad57da7e2712da8487060ac9767f url: "https://pub.dev" source: hosted - version: "7.20.2" + version: "7.9.0" shared_preferences: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bc8fc8b..33bc997 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: path_provider: ^2.1.3 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning sembast: ^3.6.0 # NoSQL data storage - sentry_flutter: ^7.7.0 # Error reporting + sentry_flutter: 7.9.0 # Error reporting url_launcher: ^6.2.4 # Open link in system browser dev_dependencies: From 0485d5d089f500b2ce73fc2828ca53d42d747a42 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 23 Jul 2024 20:12:18 +1000 Subject: [PATCH 485/746] New translations app_en.arb (Romanian) (#513) --- lib/l10n/ro_RO/app_ro_RO.arb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 50a01f3..6e73fd8 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -564,23 +564,23 @@ "@passwordEmpty": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Permisiune necesară", "@permissionRequired": {}, - "printLabel": "Print Label", + "printLabel": "Printati Eticheta", "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "Imprimantă", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "Suport Plugin activat", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Serverul acceptă plugin-uri personalizate", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "Printarea etichetei a eșuat", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "Eticheta trimis la imprimanta", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Profiluri", "@profile": {}, "profileAdd": "Add Server Profile", "@profileAdd": {}, From 693b4a4fcefb26d3864d75f7b241e6fa9fa88502 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 7 Aug 2024 20:16:31 +1000 Subject: [PATCH 486/746] New Crowdin updates (#514) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Thai) --- lib/l10n/no_NO/app_no_NO.arb | 20 ++++++------ lib/l10n/th_TH/app_th_TH.arb | 60 ++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 56d1645..ed03f1e 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "App-detaljer", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Tildelt", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Tildel lagerbeholdning", "@allocateStock": {}, "appReleaseNotes": "Vis appens utgivelsesnotater", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Strekkode ikke tildelt", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Skann del-strekkode", "@barcodeScanPart": {}, "barcodeReceivePart": "Skann strekkode for å motta del", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Konfigurer serverinnstillinger", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Bekreft overføring", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Bekreft lageroverføringsdetaljer når du skanner strekkoder", "connectionRefused": "Tilkobling avvist", "@connectionRefused": {}, "count": "Antall", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inaktiv", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Dette firmaet er markert som inaktivt", "@inactiveCompany": {}, "inactiveDetail": "Denne delen er merket som inaktiv", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Delen er ikke markert som salgbar", "@partNotSalable": {}, "partsNone": "Ingen deler", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Skann strekkode", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Skann leverandørdel-strekkode", "@scanSupplierPart": {}, "scanIntoLocation": "Skann til plassering", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Forsendelser", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Legg til forsendelse", "@shipmentAdd": {}, "shipped": "Sendt", "@shipped": {}, diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index a9a0510..a7d91d5 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -4,89 +4,89 @@ "@appTitle": { "description": "InvenTree application title string" }, - "ok": "OK", + "ok": "ตกลง", "@ok": { "description": "OK" }, - "about": "About", + "about": "เกี่ยวกับ", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "รายละเอียดบัญชีผู้ใช้", "@accountDetails": {}, - "actions": "Actions", + "actions": "การดำเนินการ", "@actions": { "description": "" }, "actionsNone": "No actions available", "@actionsNone": {}, - "add": "Add", + "add": "เพิ่ม", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "เพิ่มสต็อก", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "ที่อยู่", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "เกี่ยวกับ Inventree", "@appAbout": {}, "appCredits": "Additional app credits", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "รายละเอียดของแอพพลิเคชั่น", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "แบ่ง", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "จัดสรรคลัง", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": "แสดงข้อมูลรุ่นของโปรแกรม", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "การตั้งค่าแอปพลิเคชั่น", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "การตั้งค่าแอพ Inventree", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "ไฟล์แนบ", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "แนบรูปภาพ", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "ไม่พบไฟล์แนบ", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "ไม่พบไฟล์แนบ", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "เลือกไฟล์แนบ", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "โปรดทราบ", "@attention": {}, - "available": "Available", + "available": "พร้อมใช้งาน", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "สต็อกที่มีจำหน่าย", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "บาร์โค้ด", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "ตั้งค่า บาร์โค้ด", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "กำหนดบาร์โค้ด", "@barcodeAssign": {}, "barcodeAssignDetail": "Scan custom barcode to assign", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "บาร์โค้ดที่กำหนดแล้ว", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "สแกนบาร์โค้ดผิดพลาด", "@barcodeError": {}, "barcodeInUse": "Barcode already assigned", "@barcodeInUse": {}, "barcodeMissingHash": "Barcode hash data missing from response", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "ไม่พบข้อมูลบาร์โค้ด", "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode not assigned", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "สแกนบาร์โค้ด", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "หยุดการสแกนบาร์โค้ด", "@barodeScanPaused": {}, "barcodeScanPause": "Tap or hold to pause scanning", "@barcodeScanPause": {}, From 42de3fd7d4b2c95d3fe4350c9222673512f1cacc Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 7 Aug 2024 21:11:40 +1000 Subject: [PATCH 487/746] Order hold (#515) * Add support for "ON_HOLD" status for orders * Bump version and release notes * Fix import --- assets/release_notes.md | 6 ++ lib/inventree/purchase_order.dart | 4 +- lib/inventree/sales_order.dart | 23 +++++++- lib/widget/order/purchase_order_detail.dart | 1 - lib/widget/order/sales_order_detail.dart | 65 +++++++++++++++++++-- pubspec.yaml | 2 +- 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index b3c0907..a81cd42 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.16.2 - August 2024 +--- + +- Support "ON_HOLD" status for Purchase Orders +- Support "ON_HOLD" status for Sales Orders + ### 0.16.1 - July 2024 --- diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index ac8973d..e472388 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -87,9 +87,9 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { String get supplierReference => getString("supplier_reference"); - bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED"]); + bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED", "ON_HOLD"]); - bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING"]); + bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); bool get isPlaced => api.PurchaseOrderStatus.isNameIn(status, ["PLACED"]); diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 0002adc..5bdd484 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -78,6 +78,23 @@ class InvenTreeSalesOrder extends InvenTreeOrder { }; } + Future issueOrder() async { + if (!isPending) { + return; + } + + await api.post("${url}issue/", expectedStatusCode: 201); + } + + /// Mark this order as "cancelled" + Future cancelOrder() async { + if (!isOpen) { + return; + } + + await api.post("${url}cancel/", expectedStatusCode: 201); + } + int get customerId => getInt("customer"); InvenTreeCompany? get customer { @@ -92,7 +109,11 @@ class InvenTreeSalesOrder extends InvenTreeOrder { String get customerReference => getString("customer_reference"); - bool get isOpen => api.SalesOrderStatus.isNameIn(status, ["PENDING", "IN_PROGRESS"]); + bool get isOpen => api.SalesOrderStatus.isNameIn(status, ["PENDING", "IN_PROGRESS", "ON_HOLD"]); + + bool get isPending => api.SalesOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); + + bool get isInProgress => api.SalesOrderStatus.isNameIn(status, ["IN_PROGRESS"]); bool get isComplete => api.SalesOrderStatus.isNameIn(status, ["SHIPPED"]); diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index adc5b47..ea0e308 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -163,7 +163,6 @@ class _PurchaseOrderDetailState extends RefreshableState { ); } + /// Issue this order + Future _issueOrder(BuildContext context) async { + + confirmationDialog( + L10().issueOrder, "", + icon: FontAwesomeIcons.paperPlane, + color: Colors.blue, + acceptText: L10().issue, + onAccept: () async { + await widget.order.issueOrder().then((dynamic) { + refresh(context); + }); + } + ); + } + + /// Cancel this order + Future _cancelOrder(BuildContext context) async { + + confirmationDialog( + L10().cancelOrder, "", + icon: FontAwesomeIcons.circleXmark, + color: Colors.red, + acceptText: L10().cancel, + onAccept: () async { + await widget.order.cancelOrder().then((dynamic) { + refresh(context); + }); + } + ); + } + @override List actionButtons(BuildContext context) { List actions = []; + if (widget.order.isPending) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.paperPlane, color: Colors.blue), + label: L10().issueOrder, + onTap: () async { + _issueOrder(context); + } + ) + ); + } + + if (widget.order.isOpen) { + actions.add( + SpeedDialChild( + child: FaIcon(FontAwesomeIcons.circleXmark, color: Colors.red), + label: L10().cancelOrder, + onTap: () async { + _cancelOrder(context); + } + ) + ); + } + // Add line item - if (widget.order.isOpen && InvenTreeSOLineItem().canCreate) { + if (widget.order.isInProgress && InvenTreeSOLineItem().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circlePlus), + child: FaIcon(FontAwesomeIcons.circlePlus, color: Colors.green), label: L10().lineItemAdd, onTap: () async { _addLineItem(context); @@ -117,7 +174,7 @@ class _SalesOrderDetailState extends RefreshableState { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circlePlus), + child: FaIcon(FontAwesomeIcons.truck, color: Colors.green), label: L10().shipmentAdd, onTap: () async { _addShipment(context); @@ -133,7 +190,7 @@ class _SalesOrderDetailState extends RefreshableState { List barcodeButtons(BuildContext context) { List actions = []; - if (widget.order.isOpen && InvenTreeSOLineItem().canCreate) { + if (widget.order.isInProgress && InvenTreeSOLineItem().canCreate) { actions.add( SpeedDialChild( child: Icon(Icons.barcode_reader), diff --git a/pubspec.yaml b/pubspec.yaml index 33bc997..7fb8718 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.1+86 +version: 0.16.2+87 environment: sdk: ">=2.19.5 <3.13.0" From c9cad2f89f8cb3291bbcc1660310df009f6b85c7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 8 Aug 2024 19:44:44 +1000 Subject: [PATCH 488/746] Change from fontawesome to tabler icons (#516) * Change from fontawesome to tabler icons - Consistent with the frontend * Cleanup conflicts * Use double quotes * remove unused import * Update release notes * Migrate some google icons to tabler icons * Icon update * Properly support display of custom icons * Fix lookup --- assets/release_notes.md | 1 + lib/api.dart | 14 +- lib/api_form.dart | 24 +- lib/barcode/barcode.dart | 4 +- lib/barcode/camera_controller.dart | 6 +- lib/barcode/handler.dart | 5 +- lib/barcode/purchase_order.dart | 5 +- lib/barcode/sales_order.dart | 4 +- lib/barcode/stock.dart | 6 +- lib/barcode/wedge_controller.dart | 4 +- lib/fa_icon_mapping.dart | 1461 ----------------- lib/inventree/model.dart | 57 +- lib/labels.dart | 4 +- lib/settings/about.dart | 30 +- lib/settings/app_settings.dart | 22 +- lib/settings/barcode_settings.dart | 8 +- lib/settings/home_settings.dart | 16 +- lib/settings/login.dart | 13 +- lib/settings/part_settings.dart | 13 +- lib/settings/select_server.dart | 31 +- lib/settings/settings.dart | 14 +- lib/widget/attachment_widget.dart | 12 +- lib/widget/company/company_detail.dart | 32 +- lib/widget/company/supplier_part_detail.dart | 24 +- lib/widget/dialogs.dart | 12 +- lib/widget/drawer.dart | 14 +- lib/widget/fields.dart | 6 +- lib/widget/home.dart | 33 +- lib/widget/notes_widget.dart | 4 +- lib/widget/notifications.dart | 6 +- lib/widget/order/po_line_detail.dart | 22 +- lib/widget/order/purchase_order_detail.dart | 34 +- lib/widget/order/purchase_order_list.dart | 4 +- lib/widget/order/sales_order_detail.dart | 34 +- lib/widget/order/sales_order_list.dart | 4 +- lib/widget/order/so_line_detail.dart | 24 +- lib/widget/order/so_shipment_list.dart | 4 +- lib/widget/paginator.dart | 10 +- lib/widget/part/bom_list.dart | 4 +- lib/widget/part/category_display.dart | 16 +- lib/widget/part/category_list.dart | 2 +- lib/widget/part/part_detail.dart | 41 +- lib/widget/part/part_image_widget.dart | 5 +- lib/widget/refreshable_state.dart | 3 +- lib/widget/search.dart | 22 +- lib/widget/snacks.dart | 8 +- lib/widget/spinner.dart | 4 +- lib/widget/stock/location_display.dart | 22 +- lib/widget/stock/location_list.dart | 2 +- lib/widget/stock/stock_detail.dart | 62 +- lib/widget/stock/stock_item_test_results.dart | 12 +- pubspec.lock | 16 +- pubspec.yaml | 2 +- 53 files changed, 378 insertions(+), 1864 deletions(-) delete mode 100644 lib/fa_icon_mapping.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index a81cd42..44cd352 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Support "ON_HOLD" status for Purchase Orders - Support "ON_HOLD" status for Sales Orders +- Change base icon package from FontAwesome to TablerIcons ### 0.16.1 - July 2024 --- diff --git a/lib/api.dart b/lib/api.dart index 968e43f..927cac4 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -10,7 +10,7 @@ import "package:one_context/one_context.dart"; import "package:open_filex/open_filex.dart"; import "package:cached_network_image/cached_network_image.dart"; import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter_cache_manager/flutter_cache_manager.dart"; import "package:path_provider/path_provider.dart"; @@ -261,7 +261,7 @@ class InvenTreeAPI { showSnackIcon( L10().notConnected, success: false, - icon: FontAwesomeIcons.server + icon: TablerIcons.server ); return false; @@ -428,7 +428,7 @@ class InvenTreeAPI { if (address.isEmpty) { showSnackIcon( L10().incompleteDetails, - icon: FontAwesomeIcons.circleExclamation, + icon: TablerIcons.exclamation_circle, success: false ); return false; @@ -637,7 +637,7 @@ class InvenTreeAPI { showSnackIcon( L10().profileSelect, success: false, - icon: FontAwesomeIcons.circleExclamation + icon: TablerIcons.exclamation_circle ); return false; } @@ -655,7 +655,7 @@ class InvenTreeAPI { if (_connected) { showSnackIcon( L10().serverConnected, - icon: FontAwesomeIcons.server, + icon: TablerIcons.server, success: true, ); @@ -1485,7 +1485,7 @@ class InvenTreeAPI { return CachedNetworkImage( imageUrl: url, placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER), + errorWidget: (context, url, error) => Icon(TablerIcons.circle_x, color: COLOR_DANGER), httpHeaders: defaultHeaders(), height: height, width: width, @@ -1589,7 +1589,7 @@ class InvenTreeAPI { L10().locateLocation, "", fields, - icon: FontAwesomeIcons.magnifyingGlassLocation, + icon: TablerIcons.location_search, onSuccess: (Map data) async { plugin_name = (data["plugin"] ?? "") as String; } diff --git a/lib/api_form.dart b/lib/api_form.dart index f2578df..e5278b8 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -2,7 +2,7 @@ import "dart:io"; import "package:intl/intl.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:dropdown_search/dropdown_search.dart"; import "package:datetime_picker_formfield/datetime_picker_formfield.dart"; import "package:flutter/material.dart"; @@ -335,7 +335,7 @@ class APIFormField { controller: controller, ), trailing: IconButton( - icon: Icon(Icons.qr_code), + icon: Icon(TablerIcons.qrcode), onPressed: () async { var handler = UniqueBarcodeHandler((String hash) { controller.text = hash; @@ -409,7 +409,7 @@ class APIFormField { controller: controller, ), trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.circlePlus), + icon: Icon(TablerIcons.circle_plus), onPressed: () async { FilePickerDialog.pickFile( message: L10().attachmentSelect, @@ -705,7 +705,7 @@ class APIFormField { bool isGroup = (data["label"] ?? "") == "group"; return ListTile( title: Text(name), - leading: FaIcon(isGroup ? FontAwesomeIcons.users : FontAwesomeIcons.user), + leading: Icon(isGroup ? TablerIcons.users : TablerIcons.user), ); case "contact": String name = (data["name"] ?? "") as String; @@ -726,7 +726,7 @@ class APIFormField { return ListTile( title: Text(project_code.code), subtitle: Text(project_code.description), - leading: FaIcon(FontAwesomeIcons.list) + leading: Icon(TablerIcons.list) ); default: return ListTile( @@ -745,7 +745,7 @@ class APIFormField { // Construct a widget to instruct the user that no results were found Widget _renderEmptyResult() { return ListTile( - leading: FaIcon(FontAwesomeIcons.magnifyingGlass), + leading: Icon(TablerIcons.search), title: Text(L10().noResults), subtitle: Text( L10().queryNoResults, @@ -955,7 +955,7 @@ Future launchApiForm( String method = "PATCH", Function(Map)? onSuccess, Function? onCancel, - IconData icon = FontAwesomeIcons.floppyDisk, + IconData icon = TablerIcons.device_floppy }) async { showLoadingOverlay(context); @@ -979,7 +979,7 @@ Future launchApiForm( // User does not have permission to perform this action showSnackIcon( L10().response403, - icon: FontAwesomeIcons.userXmark, + icon: TablerIcons.user_x, ); hideLoadingOverlay(); @@ -1061,7 +1061,7 @@ class APIFormWidget extends StatefulWidget { Key? key, this.onSuccess, this.fileField = "", - this.icon = FontAwesomeIcons.floppyDisk, + this.icon = TablerIcons.device_floppy, } ) : super(key: key); @@ -1114,8 +1114,8 @@ class _APIFormWidgetState extends State { color: COLOR_DANGER, ), ), - leading: FaIcon( - FontAwesomeIcons.circleExclamation, + leading: Icon( + TablerIcons.exclamation_circle, color: COLOR_DANGER ), ) @@ -1487,7 +1487,7 @@ class _APIFormWidgetState extends State { title: Text(widget.title), actions: [ IconButton( - icon: FaIcon(widget.icon), + icon: Icon(widget.icon), onPressed: () { if (_formKey.currentState!.validate()) { diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 64af533..513cdb1 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; @@ -121,7 +121,7 @@ class BarcodeScanHandler extends BarcodeHandler { showSnackIcon( L10().barcodeNoMatch, - icon: FontAwesomeIcons.circleExclamation, + icon: TablerIcons.exclamation_circle, success: false, ); } diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 9947c1a..0e644d4 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,6 +1,6 @@ import "dart:io"; import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; @@ -124,11 +124,11 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Widget build(BuildContext context) { Widget actionIcon = - FaIcon(FontAwesomeIcons.circlePause, color: COLOR_WARNING, size: 64); + Icon(TablerIcons.player_pause, color: COLOR_WARNING, size: 64); if (scanning_paused) { actionIcon = - FaIcon(FontAwesomeIcons.circlePlay, color: COLOR_ACTION, size: 64); + Icon(TablerIcons.player_play, color: COLOR_ACTION, size: 64); } String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index 3dae484..a5e1b8a 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -1,7 +1,6 @@ import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; @@ -72,7 +71,7 @@ class BarcodeHandler { showSnackIcon( L10().barcodeError, - icon: FontAwesomeIcons.circleExclamation, + icon: TablerIcons.exclamation_circle, success: false ); diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart index 8c91fed..e8bba61 100644 --- a/lib/barcode/purchase_order.dart +++ b/lib/barcode/purchase_order.dart @@ -1,6 +1,5 @@ import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; @@ -106,7 +105,7 @@ class POReceiveBarcodeHandler extends BarcodeHandler { receive_url, fields, method: "POST", - icon: FontAwesomeIcons.rightToBracket, + icon: TablerIcons.transition_right, onSuccess: (data) async { showSnackIcon(L10().receivedItem, success: true); } diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart index bc42746..e0e79ad 100644 --- a/lib/barcode/sales_order.dart +++ b/lib/barcode/sales_order.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api_form.dart"; import "package:inventree/inventree/part.dart"; @@ -159,7 +159,7 @@ class SOAllocateStockHandler extends BarcodeHandler { salesOrder!.allocate_url, fields, method: "POST", - icon: FontAwesomeIcons.rightToBracket, + icon: TablerIcons.transition_right, onSuccess: (data) async { showSnackIcon(L10().allocated, success: true); }); diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart index 8de6ed5..b9671e2 100644 --- a/lib/barcode/stock.dart +++ b/lib/barcode/stock.dart @@ -1,5 +1,5 @@ import "package:flutter/cupertino.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api_form.dart"; import "package:inventree/preferences.dart"; import "package:one_context/one_context.dart"; @@ -149,7 +149,7 @@ class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { InvenTreeStockItem.transferStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.dolly, + icon: TablerIcons.transfer, onSuccess: (data) async { showSnackIcon(L10().stockItemUpdated, success: true); } @@ -216,7 +216,7 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { InvenTreeStockItem.transferStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.dolly, + icon: TablerIcons.transfer, onSuccess: (data) async { showSnackIcon(L10().stockItemUpdated, success: true); } diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart index 98b9f0c..b239c39 100644 --- a/lib/barcode/wedge_controller.dart +++ b/lib/barcode/wedge_controller.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/controller.dart"; @@ -64,7 +64,7 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { mainAxisAlignment: MainAxisAlignment.center, children: [ Spacer(flex: 5), - FaIcon(FontAwesomeIcons.barcode, size: 64), + Icon(TablerIcons.barcode, size: 64), Spacer(flex: 5), BarcodeKeyboardListener( useKeyDownEvent: true, diff --git a/lib/fa_icon_mapping.dart b/lib/fa_icon_mapping.dart deleted file mode 100644 index 46a84c9..0000000 --- a/lib/fa_icon_mapping.dart +++ /dev/null @@ -1,1461 +0,0 @@ - -// Map text names for icons into flutter icon data -// This file has been auto-generated (do not edit manually) -// Icon data was extracted from "font_awesome_flutter.dart" -const Map fontAwesomeIconMap = { - "500px": 0xf26e, - "accessible-icon": 0xf368, - "accusoft": 0xf369, - "acquisitions-incorporated": 0xf6af, - "ad": 0xf641, - "address-book": 0xf2b9, - "address-card": 0xf2bb, - "adjust": 0xf042, - "adn": 0xf170, - "adversal": 0xf36a, - "affiliatetheme": 0xf36b, - "air-freshener": 0xf5d0, - "airbnb": 0xf834, - "algolia": 0xf36c, - "align-center": 0xf037, - "align-justify": 0xf039, - "align-left": 0xf036, - "align-right": 0xf038, - "alipay": 0xf642, - "allergies": 0xf461, - "amazon": 0xf270, - "amazon-pay": 0xf42c, - "ambulance": 0xf0f9, - "amilia": 0xf36d, - "anchor": 0xf13d, - "android": 0xf17b, - "angellist": 0xf209, - "angle-double-down": 0xf103, - "angle-double-left": 0xf100, - "angle-double-right": 0xf101, - "angle-double-up": 0xf102, - "angle-down": 0xf107, - "angle-left": 0xf104, - "angle-right": 0xf105, - "angle-up": 0xf106, - "angry": 0xf556, - "angrycreative": 0xf36e, - "angular": 0xf420, - "ankh": 0xf644, - "app-store": 0xf36f, - "app-store-ios": 0xf370, - "apper": 0xf371, - "apple": 0xf179, - "apple-alt": 0xf5d1, - "apple-pay": 0xf415, - "archive": 0xf187, - "archway": 0xf557, - "arrow-alt-circle-down": 0xf358, - "arrow-alt-circle-left": 0xf359, - "arrow-alt-circle-right": 0xf35a, - "arrow-alt-circle-up": 0xf35b, - "arrow-circle-down": 0xf0ab, - "arrow-circle-left": 0xf0a8, - "arrow-circle-right": 0xf0a9, - "arrow-circle-up": 0xf0aa, - "arrow-down": 0xf063, - "arrow-left": 0xf060, - "arrow-right": 0xf061, - "arrow-up": 0xf062, - "arrows-alt": 0xf0b2, - "arrows-alt-h": 0xf337, - "arrows-alt-v": 0xf338, - "artstation": 0xf77a, - "assistive-listening-systems": 0xf2a2, - "asterisk": 0xf069, - "asymmetrik": 0xf372, - "at": 0xf1fa, - "atlas": 0xf558, - "atlassian": 0xf77b, - "atom": 0xf5d2, - "audible": 0xf373, - "audio-description": 0xf29e, - "autoprefixer": 0xf41c, - "avianex": 0xf374, - "aviato": 0xf421, - "award": 0xf559, - "aws": 0xf375, - "baby": 0xf77c, - "baby-carriage": 0xf77d, - "backspace": 0xf55a, - "backward": 0xf04a, - "bacon": 0xf7e5, - "bacteria": 0xe059, - "bacterium": 0xe05a, - "bahai": 0xf666, - "balance-scale": 0xf24e, - "balance-scale-left": 0xf515, - "balance-scale-right": 0xf516, - "ban": 0xf05e, - "band-aid": 0xf462, - "bandcamp": 0xf2d5, - "barcode": 0xf02a, - "bars": 0xf0c9, - "baseball-ball": 0xf433, - "basketball-ball": 0xf434, - "bath": 0xf2cd, - "battery-empty": 0xf244, - "battery-full": 0xf240, - "battery-half": 0xf242, - "battery-quarter": 0xf243, - "battery-three-quarters": 0xf241, - "battle-net": 0xf835, - "bed": 0xf236, - "beer": 0xf0fc, - "behance": 0xf1b4, - "behance-square": 0xf1b5, - "bell": 0xf0f3, - "bell-slash": 0xf1f6, - "bezier-curve": 0xf55b, - "bible": 0xf647, - "bicycle": 0xf206, - "biking": 0xf84a, - "bimobject": 0xf378, - "binoculars": 0xf1e5, - "biohazard": 0xf780, - "birthday-cake": 0xf1fd, - "bitbucket": 0xf171, - "bitcoin": 0xf379, - "bity": 0xf37a, - "black-tie": 0xf27e, - "blackberry": 0xf37b, - "blender": 0xf517, - "blender-phone": 0xf6b6, - "blind": 0xf29d, - "blog": 0xf781, - "blogger": 0xf37c, - "blogger-b": 0xf37d, - "bluetooth": 0xf293, - "bluetooth-b": 0xf294, - "bold": 0xf032, - "bolt": 0xf0e7, - "bomb": 0xf1e2, - "bone": 0xf5d7, - "bong": 0xf55c, - "book": 0xf02d, - "book-dead": 0xf6b7, - "book-medical": 0xf7e6, - "book-open": 0xf518, - "book-reader": 0xf5da, - "bookmark": 0xf02e, - "bootstrap": 0xf836, - "border-all": 0xf84c, - "border-none": 0xf850, - "border-style": 0xf853, - "bowling-ball": 0xf436, - "box": 0xf466, - "box-open": 0xf49e, - "box-tissue": 0xe05b, - "boxes": 0xf468, - "braille": 0xf2a1, - "brain": 0xf5dc, - "bread-slice": 0xf7ec, - "briefcase": 0xf0b1, - "briefcase-medical": 0xf469, - "broadcast-tower": 0xf519, - "broom": 0xf51a, - "brush": 0xf55d, - "btc": 0xf15a, - "buffer": 0xf837, - "bug": 0xf188, - "building": 0xf1ad, - "bullhorn": 0xf0a1, - "bullseye": 0xf140, - "burn": 0xf46a, - "buromobelexperte": 0xf37f, - "bus": 0xf207, - "bus-alt": 0xf55e, - "business-time": 0xf64a, - "buy-n-large": 0xf8a6, - "buysellads": 0xf20d, - "calculator": 0xf1ec, - "calendar": 0xf133, - "calendar-alt": 0xf073, - "calendar-check": 0xf274, - "calendar-day": 0xf783, - "calendar-minus": 0xf272, - "calendar-plus": 0xf271, - "calendar-times": 0xf273, - "calendar-week": 0xf784, - "camera": 0xf030, - "camera-retro": 0xf083, - "campground": 0xf6bb, - "canadian-maple-leaf": 0xf785, - "candy-cane": 0xf786, - "cannabis": 0xf55f, - "capsules": 0xf46b, - "car": 0xf1b9, - "car-alt": 0xf5de, - "car-battery": 0xf5df, - "car-crash": 0xf5e1, - "car-side": 0xf5e4, - "caravan": 0xf8ff, - "caret-down": 0xf0d7, - "caret-left": 0xf0d9, - "caret-right": 0xf0da, - "caret-square-down": 0xf150, - "caret-square-left": 0xf191, - "caret-square-right": 0xf152, - "caret-square-up": 0xf151, - "caret-up": 0xf0d8, - "carrot": 0xf787, - "cart-arrow-down": 0xf218, - "cart-plus": 0xf217, - "cash-register": 0xf788, - "cat": 0xf6be, - "cc-amazon-pay": 0xf42d, - "cc-amex": 0xf1f3, - "cc-apple-pay": 0xf416, - "cc-diners-club": 0xf24c, - "cc-discover": 0xf1f2, - "cc-jcb": 0xf24b, - "cc-mastercard": 0xf1f1, - "cc-paypal": 0xf1f4, - "cc-stripe": 0xf1f5, - "cc-visa": 0xf1f0, - "centercode": 0xf380, - "centos": 0xf789, - "certificate": 0xf0a3, - "chair": 0xf6c0, - "chalkboard": 0xf51b, - "chalkboard-teacher": 0xf51c, - "charging-station": 0xf5e7, - "chart-area": 0xf1fe, - "chart-bar": 0xf080, - "chart-line": 0xf201, - "chart-pie": 0xf200, - "check": 0xf00c, - "check-circle": 0xf058, - "check-double": 0xf560, - "check-square": 0xf14a, - "cheese": 0xf7ef, - "chess": 0xf439, - "chess-bishop": 0xf43a, - "chess-board": 0xf43c, - "chess-king": 0xf43f, - "chess-knight": 0xf441, - "chess-pawn": 0xf443, - "chess-queen": 0xf445, - "chess-rook": 0xf447, - "chevron-circle-down": 0xf13a, - "chevron-circle-left": 0xf137, - "chevron-circle-right": 0xf138, - "chevron-circle-up": 0xf139, - "chevron-down": 0xf078, - "chevron-left": 0xf053, - "chevron-right": 0xf054, - "chevron-up": 0xf077, - "child": 0xf1ae, - "chrome": 0xf268, - "chromecast": 0xf838, - "church": 0xf51d, - "circle": 0xf111, - "circle-notch": 0xf1ce, - "city": 0xf64f, - "clinic-medical": 0xf7f2, - "clipboard": 0xf328, - "clipboard-check": 0xf46c, - "clipboard-list": 0xf46d, - "clock": 0xf017, - "clone": 0xf24d, - "closed-captioning": 0xf20a, - "cloud": 0xf0c2, - "cloud-download-alt": 0xf381, - "cloud-meatball": 0xf73b, - "cloud-moon": 0xf6c3, - "cloud-moon-rain": 0xf73c, - "cloud-rain": 0xf73d, - "cloud-showers-heavy": 0xf740, - "cloud-sun": 0xf6c4, - "cloud-sun-rain": 0xf743, - "cloud-upload-alt": 0xf382, - "cloudflare": 0xe07d, - "cloudscale": 0xf383, - "cloudsmith": 0xf384, - "cloudversify": 0xf385, - "cocktail": 0xf561, - "code": 0xf121, - "code-branch": 0xf126, - "codepen": 0xf1cb, - "codiepie": 0xf284, - "coffee": 0xf0f4, - "cog": 0xf013, - "cogs": 0xf085, - "coins": 0xf51e, - "columns": 0xf0db, - "comment": 0xf075, - "comment-alt": 0xf27a, - "comment-dollar": 0xf651, - "comment-dots": 0xf4ad, - "comment-medical": 0xf7f5, - "comment-slash": 0xf4b3, - "comments": 0xf086, - "comments-dollar": 0xf653, - "compact-disc": 0xf51f, - "compass": 0xf14e, - "compress": 0xf066, - "compress-alt": 0xf422, - "compress-arrows-alt": 0xf78c, - "concierge-bell": 0xf562, - "confluence": 0xf78d, - "connectdevelop": 0xf20e, - "contao": 0xf26d, - "cookie": 0xf563, - "cookie-bite": 0xf564, - "copy": 0xf0c5, - "copyright": 0xf1f9, - "cotton-bureau": 0xf89e, - "couch": 0xf4b8, - "cpanel": 0xf388, - "creative-commons": 0xf25e, - "creative-commons-by": 0xf4e7, - "creative-commons-nc": 0xf4e8, - "creative-commons-nc-eu": 0xf4e9, - "creative-commons-nc-jp": 0xf4ea, - "creative-commons-nd": 0xf4eb, - "creative-commons-pd": 0xf4ec, - "creative-commons-pd-alt": 0xf4ed, - "creative-commons-remix": 0xf4ee, - "creative-commons-sa": 0xf4ef, - "creative-commons-sampling": 0xf4f0, - "creative-commons-share": 0xf4f2, - "creative-commons-zero": 0xf4f3, - "credit-card": 0xf09d, - "critical-role": 0xf6c9, - "crop": 0xf125, - "crop-alt": 0xf565, - "cross": 0xf654, - "crosshairs": 0xf05b, - "crow": 0xf520, - "crown": 0xf521, - "crutch": 0xf7f7, - "css3": 0xf13c, - "css3-alt": 0xf38b, - "cube": 0xf1b2, - "cubes": 0xf1b3, - "cut": 0xf0c4, - "cuttlefish": 0xf38c, - "d-and-d": 0xf38d, - "d-and-d-beyond": 0xf6ca, - "dailymotion": 0xe052, - "dashcube": 0xf210, - "database": 0xf1c0, - "deaf": 0xf2a4, - "deezer": 0xe077, - "delicious": 0xf1a5, - "democrat": 0xf747, - "deploydog": 0xf38e, - "deskpro": 0xf38f, - "desktop": 0xf108, - "dev": 0xf6cc, - "deviantart": 0xf1bd, - "dharmachakra": 0xf655, - "dhl": 0xf790, - "diagnoses": 0xf470, - "diaspora": 0xf791, - "dice": 0xf522, - "dice-d20": 0xf6cf, - "dice-d6": 0xf6d1, - "dice-five": 0xf523, - "dice-four": 0xf524, - "dice-one": 0xf525, - "dice-six": 0xf526, - "dice-three": 0xf527, - "dice-two": 0xf528, - "digg": 0xf1a6, - "digital-ocean": 0xf391, - "digital-tachograph": 0xf566, - "directions": 0xf5eb, - "discord": 0xf392, - "discourse": 0xf393, - "disease": 0xf7fa, - "divide": 0xf529, - "dizzy": 0xf567, - "dna": 0xf471, - "dochub": 0xf394, - "docker": 0xf395, - "dog": 0xf6d3, - "dollar-sign": 0xf155, - "dolly": 0xf472, - "dolly-flatbed": 0xf474, - "donate": 0xf4b9, - "door-closed": 0xf52a, - "door-open": 0xf52b, - "dot-circle": 0xf192, - "dove": 0xf4ba, - "download": 0xf019, - "draft2digital": 0xf396, - "drafting-compass": 0xf568, - "dragon": 0xf6d5, - "draw-polygon": 0xf5ee, - "dribbble": 0xf17d, - "dribbble-square": 0xf397, - "dropbox": 0xf16b, - "drum": 0xf569, - "drum-steelpan": 0xf56a, - "drumstick-bite": 0xf6d7, - "drupal": 0xf1a9, - "dumbbell": 0xf44b, - "dumpster": 0xf793, - "dumpster-fire": 0xf794, - "dungeon": 0xf6d9, - "dyalog": 0xf399, - "earlybirds": 0xf39a, - "ebay": 0xf4f4, - "edge": 0xf282, - "edge-legacy": 0xe078, - "edit": 0xf044, - "egg": 0xf7fb, - "eject": 0xf052, - "elementor": 0xf430, - "ellipsis-h": 0xf141, - "ellipsis-v": 0xf142, - "ello": 0xf5f1, - "ember": 0xf423, - "empire": 0xf1d1, - "envelope": 0xf0e0, - "envelope-open": 0xf2b6, - "envelope-open-text": 0xf658, - "envelope-square": 0xf199, - "envira": 0xf299, - "equals": 0xf52c, - "eraser": 0xf12d, - "erlang": 0xf39d, - "ethereum": 0xf42e, - "ethernet": 0xf796, - "etsy": 0xf2d7, - "euro-sign": 0xf153, - "evernote": 0xf839, - "exchange-alt": 0xf362, - "exclamation": 0xf12a, - "exclamation-circle": 0xf06a, - "exclamation-triangle": 0xf071, - "expand": 0xf065, - "expand-alt": 0xf424, - "expand-arrows-alt": 0xf31e, - "expeditedssl": 0xf23e, - "external-link-alt": 0xf35d, - "external-link-square-alt": 0xf360, - "eye": 0xf06e, - "eye-dropper": 0xf1fb, - "eye-slash": 0xf070, - "facebook": 0xf09a, - "facebook-f": 0xf39e, - "facebook-messenger": 0xf39f, - "facebook-square": 0xf082, - "fan": 0xf863, - "fantasy-flight-games": 0xf6dc, - "fast-backward": 0xf049, - "fast-forward": 0xf050, - "faucet": 0xe005, - "fax": 0xf1ac, - "feather": 0xf52d, - "feather-alt": 0xf56b, - "fedex": 0xf797, - "fedora": 0xf798, - "female": 0xf182, - "fighter-jet": 0xf0fb, - "figma": 0xf799, - "file": 0xf15b, - "file-alt": 0xf15c, - "file-archive": 0xf1c6, - "file-audio": 0xf1c7, - "file-code": 0xf1c9, - "file-contract": 0xf56c, - "file-csv": 0xf6dd, - "file-download": 0xf56d, - "file-excel": 0xf1c3, - "file-export": 0xf56e, - "file-image": 0xf1c5, - "file-import": 0xf56f, - "file-invoice": 0xf570, - "file-invoice-dollar": 0xf571, - "file-medical": 0xf477, - "file-medical-alt": 0xf478, - "file-pdf": 0xf1c1, - "file-powerpoint": 0xf1c4, - "file-prescription": 0xf572, - "file-signature": 0xf573, - "file-upload": 0xf574, - "file-video": 0xf1c8, - "file-word": 0xf1c2, - "fill": 0xf575, - "fill-drip": 0xf576, - "film": 0xf008, - "filter": 0xf0b0, - "fingerprint": 0xf577, - "fire": 0xf06d, - "fire-alt": 0xf7e4, - "fire-extinguisher": 0xf134, - "firefox": 0xf269, - "firefox-browser": 0xe007, - "first-aid": 0xf479, - "first-order": 0xf2b0, - "first-order-alt": 0xf50a, - "firstdraft": 0xf3a1, - "fish": 0xf578, - "fist-raised": 0xf6de, - "flag": 0xf024, - "flag-checkered": 0xf11e, - "flag-usa": 0xf74d, - "flask": 0xf0c3, - "flickr": 0xf16e, - "flipboard": 0xf44d, - "flushed": 0xf579, - "fly": 0xf417, - "folder": 0xf07b, - "folder-minus": 0xf65d, - "folder-open": 0xf07c, - "folder-plus": 0xf65e, - "font": 0xf031, - "font-awesome": 0xf2b4, - "font-awesome-alt": 0xf35c, - "font-awesome-flag": 0xf425, - "fonticons": 0xf280, - "fonticons-fi": 0xf3a2, - "football-ball": 0xf44e, - "fort-awesome": 0xf286, - "fort-awesome-alt": 0xf3a3, - "forumbee": 0xf211, - "forward": 0xf04e, - "foursquare": 0xf180, - "free-code-camp": 0xf2c5, - "freebsd": 0xf3a4, - "frog": 0xf52e, - "frown": 0xf119, - "frown-open": 0xf57a, - "fulcrum": 0xf50b, - "funnel-dollar": 0xf662, - "futbol": 0xf1e3, - "galactic-republic": 0xf50c, - "galactic-senate": 0xf50d, - "gamepad": 0xf11b, - "gas-pump": 0xf52f, - "gavel": 0xf0e3, - "gem": 0xf3a5, - "genderless": 0xf22d, - "get-pocket": 0xf265, - "gg": 0xf260, - "gg-circle": 0xf261, - "ghost": 0xf6e2, - "gift": 0xf06b, - "gifts": 0xf79c, - "git": 0xf1d3, - "git-alt": 0xf841, - "git-square": 0xf1d2, - "github": 0xf09b, - "github-alt": 0xf113, - "github-square": 0xf092, - "gitkraken": 0xf3a6, - "gitlab": 0xf296, - "gitter": 0xf426, - "glass-cheers": 0xf79f, - "glass-martini": 0xf000, - "glass-martini-alt": 0xf57b, - "glass-whiskey": 0xf7a0, - "glasses": 0xf530, - "glide": 0xf2a5, - "glide-g": 0xf2a6, - "globe": 0xf0ac, - "globe-africa": 0xf57c, - "globe-americas": 0xf57d, - "globe-asia": 0xf57e, - "globe-europe": 0xf7a2, - "gofore": 0xf3a7, - "golf-ball": 0xf450, - "goodreads": 0xf3a8, - "goodreads-g": 0xf3a9, - "google": 0xf1a0, - "google-drive": 0xf3aa, - "google-pay": 0xe079, - "google-play": 0xf3ab, - "google-plus": 0xf2b3, - "google-plus-g": 0xf0d5, - "google-plus-square": 0xf0d4, - "google-wallet": 0xf1ee, - "gopuram": 0xf664, - "graduation-cap": 0xf19d, - "gratipay": 0xf184, - "grav": 0xf2d6, - "greater-than": 0xf531, - "greater-than-equal": 0xf532, - "grimace": 0xf57f, - "grin": 0xf580, - "grin-alt": 0xf581, - "grin-beam": 0xf582, - "grin-beam-sweat": 0xf583, - "grin-hearts": 0xf584, - "grin-squint": 0xf585, - "grin-squint-tears": 0xf586, - "grin-stars": 0xf587, - "grin-tears": 0xf588, - "grin-tongue": 0xf589, - "grin-tongue-squint": 0xf58a, - "grin-tongue-wink": 0xf58b, - "grin-wink": 0xf58c, - "grip-horizontal": 0xf58d, - "grip-lines": 0xf7a4, - "grip-lines-vertical": 0xf7a5, - "grip-vertical": 0xf58e, - "gripfire": 0xf3ac, - "grunt": 0xf3ad, - "guilded": 0xe07e, - "guitar": 0xf7a6, - "gulp": 0xf3ae, - "h-square": 0xf0fd, - "hacker-news": 0xf1d4, - "hacker-news-square": 0xf3af, - "hackerrank": 0xf5f7, - "hamburger": 0xf805, - "hammer": 0xf6e3, - "hamsa": 0xf665, - "hand-holding": 0xf4bd, - "hand-holding-heart": 0xf4be, - "hand-holding-medical": 0xe05c, - "hand-holding-usd": 0xf4c0, - "hand-holding-water": 0xf4c1, - "hand-lizard": 0xf258, - "hand-middle-finger": 0xf806, - "hand-paper": 0xf256, - "hand-peace": 0xf25b, - "hand-point-down": 0xf0a7, - "hand-point-left": 0xf0a5, - "hand-point-right": 0xf0a4, - "hand-point-up": 0xf0a6, - "hand-pointer": 0xf25a, - "hand-rock": 0xf255, - "hand-scissors": 0xf257, - "hand-sparkles": 0xe05d, - "hand-spock": 0xf259, - "hands": 0xf4c2, - "hands-helping": 0xf4c4, - "hands-wash": 0xe05e, - "handshake": 0xf2b5, - "handshake-alt-slash": 0xe05f, - "handshake-slash": 0xe060, - "hanukiah": 0xf6e6, - "hard-hat": 0xf807, - "hashtag": 0xf292, - "hat-cowboy": 0xf8c0, - "hat-cowboy-side": 0xf8c1, - "hat-wizard": 0xf6e8, - "hdd": 0xf0a0, - "head-side-cough": 0xe061, - "head-side-cough-slash": 0xe062, - "head-side-mask": 0xe063, - "head-side-virus": 0xe064, - "heading": 0xf1dc, - "headphones": 0xf025, - "headphones-alt": 0xf58f, - "headset": 0xf590, - "heart": 0xf004, - "heart-broken": 0xf7a9, - "heartbeat": 0xf21e, - "helicopter": 0xf533, - "highlighter": 0xf591, - "hiking": 0xf6ec, - "hippo": 0xf6ed, - "hips": 0xf452, - "hire-a-helper": 0xf3b0, - "history": 0xf1da, - "hive": 0xe07f, - "hockey-puck": 0xf453, - "holly-berry": 0xf7aa, - "home": 0xf015, - "hooli": 0xf427, - "hornbill": 0xf592, - "horse": 0xf6f0, - "horse-head": 0xf7ab, - "hospital": 0xf0f8, - "hospital-alt": 0xf47d, - "hospital-symbol": 0xf47e, - "hospital-user": 0xf80d, - "hot-tub": 0xf593, - "hotdog": 0xf80f, - "hotel": 0xf594, - "hotjar": 0xf3b1, - "hourglass": 0xf254, - "hourglass-end": 0xf253, - "hourglass-half": 0xf252, - "hourglass-start": 0xf251, - "house-damage": 0xf6f1, - "house-user": 0xe065, - "houzz": 0xf27c, - "hryvnia": 0xf6f2, - "html5": 0xf13b, - "hubspot": 0xf3b2, - "i-cursor": 0xf246, - "ice-cream": 0xf810, - "icicles": 0xf7ad, - "icons": 0xf86d, - "id-badge": 0xf2c1, - "id-card": 0xf2c2, - "id-card-alt": 0xf47f, - "ideal": 0xe013, - "igloo": 0xf7ae, - "image": 0xf03e, - "images": 0xf302, - "imdb": 0xf2d8, - "inbox": 0xf01c, - "indent": 0xf03c, - "industry": 0xf275, - "infinity": 0xf534, - "info": 0xf129, - "info-circle": 0xf05a, - "innosoft": 0xe080, - "instagram": 0xf16d, - "instagram-square": 0xe055, - "instalod": 0xe081, - "intercom": 0xf7af, - "internet-explorer": 0xf26b, - "invision": 0xf7b0, - "ioxhost": 0xf208, - "italic": 0xf033, - "itch-io": 0xf83a, - "itunes": 0xf3b4, - "itunes-note": 0xf3b5, - "java": 0xf4e4, - "jedi": 0xf669, - "jedi-order": 0xf50e, - "jenkins": 0xf3b6, - "jira": 0xf7b1, - "joget": 0xf3b7, - "joint": 0xf595, - "joomla": 0xf1aa, - "journal-whills": 0xf66a, - "js": 0xf3b8, - "js-square": 0xf3b9, - "jsfiddle": 0xf1cc, - "kaaba": 0xf66b, - "kaggle": 0xf5fa, - "key": 0xf084, - "keybase": 0xf4f5, - "keyboard": 0xf11c, - "keycdn": 0xf3ba, - "khanda": 0xf66d, - "kickstarter": 0xf3bb, - "kickstarter-k": 0xf3bc, - "kiss": 0xf596, - "kiss-beam": 0xf597, - "kiss-wink-heart": 0xf598, - "kiwi-bird": 0xf535, - "korvue": 0xf42f, - "landmark": 0xf66f, - "language": 0xf1ab, - "laptop": 0xf109, - "laptop-code": 0xf5fc, - "laptop-house": 0xe066, - "laptop-medical": 0xf812, - "laravel": 0xf3bd, - "lastfm": 0xf202, - "lastfm-square": 0xf203, - "laugh": 0xf599, - "laugh-beam": 0xf59a, - "laugh-squint": 0xf59b, - "laugh-wink": 0xf59c, - "layer-group": 0xf5fd, - "leaf": 0xf06c, - "leanpub": 0xf212, - "lemon": 0xf094, - "less": 0xf41d, - "less-than": 0xf536, - "less-than-equal": 0xf537, - "level-down-alt": 0xf3be, - "level-up-alt": 0xf3bf, - "life-ring": 0xf1cd, - "lightbulb": 0xf0eb, - "line": 0xf3c0, - "link": 0xf0c1, - "linkedin": 0xf08c, - "linkedin-in": 0xf0e1, - "linode": 0xf2b8, - "linux": 0xf17c, - "lira-sign": 0xf195, - "list": 0xf03a, - "list-alt": 0xf022, - "list-ol": 0xf0cb, - "list-ul": 0xf0ca, - "location-arrow": 0xf124, - "lock": 0xf023, - "lock-open": 0xf3c1, - "long-arrow-alt-down": 0xf309, - "long-arrow-alt-left": 0xf30a, - "long-arrow-alt-right": 0xf30b, - "long-arrow-alt-up": 0xf30c, - "low-vision": 0xf2a8, - "luggage-cart": 0xf59d, - "lungs": 0xf604, - "lungs-virus": 0xe067, - "lyft": 0xf3c3, - "magento": 0xf3c4, - "magic": 0xf0d0, - "magnet": 0xf076, - "mail-bulk": 0xf674, - "mailchimp": 0xf59e, - "male": 0xf183, - "mandalorian": 0xf50f, - "map": 0xf279, - "map-marked": 0xf59f, - "map-marked-alt": 0xf5a0, - "map-marker": 0xf041, - "map-marker-alt": 0xf3c5, - "map-pin": 0xf276, - "map-signs": 0xf277, - "markdown": 0xf60f, - "marker": 0xf5a1, - "mars": 0xf222, - "mars-double": 0xf227, - "mars-stroke": 0xf229, - "mars-stroke-h": 0xf22b, - "mars-stroke-v": 0xf22a, - "mask": 0xf6fa, - "mastodon": 0xf4f6, - "maxcdn": 0xf136, - "mdb": 0xf8ca, - "medal": 0xf5a2, - "medapps": 0xf3c6, - "medium": 0xf23a, - "medium-m": 0xf3c7, - "medkit": 0xf0fa, - "medrt": 0xf3c8, - "meetup": 0xf2e0, - "megaport": 0xf5a3, - "meh": 0xf11a, - "meh-blank": 0xf5a4, - "meh-rolling-eyes": 0xf5a5, - "memory": 0xf538, - "mendeley": 0xf7b3, - "menorah": 0xf676, - "mercury": 0xf223, - "meteor": 0xf753, - "microblog": 0xe01a, - "microchip": 0xf2db, - "microphone": 0xf130, - "microphone-alt": 0xf3c9, - "microphone-alt-slash": 0xf539, - "microphone-slash": 0xf131, - "microscope": 0xf610, - "microsoft": 0xf3ca, - "minus": 0xf068, - "minus-circle": 0xf056, - "minus-square": 0xf146, - "mitten": 0xf7b5, - "mix": 0xf3cb, - "mixcloud": 0xf289, - "mixer": 0xe056, - "mizuni": 0xf3cc, - "mobile": 0xf10b, - "mobile-alt": 0xf3cd, - "modx": 0xf285, - "monero": 0xf3d0, - "money-bill": 0xf0d6, - "money-bill-alt": 0xf3d1, - "money-bill-wave": 0xf53a, - "money-bill-wave-alt": 0xf53b, - "money-check": 0xf53c, - "money-check-alt": 0xf53d, - "monument": 0xf5a6, - "moon": 0xf186, - "mortar-pestle": 0xf5a7, - "mosque": 0xf678, - "motorcycle": 0xf21c, - "mountain": 0xf6fc, - "mouse": 0xf8cc, - "mouse-pointer": 0xf245, - "mug-hot": 0xf7b6, - "music": 0xf001, - "napster": 0xf3d2, - "neos": 0xf612, - "network-wired": 0xf6ff, - "neuter": 0xf22c, - "newspaper": 0xf1ea, - "nimblr": 0xf5a8, - "node": 0xf419, - "node-js": 0xf3d3, - "not-equal": 0xf53e, - "notes-medical": 0xf481, - "npm": 0xf3d4, - "ns8": 0xf3d5, - "nutritionix": 0xf3d6, - "object-group": 0xf247, - "object-ungroup": 0xf248, - "octopus-deploy": 0xe082, - "odnoklassniki": 0xf263, - "odnoklassniki-square": 0xf264, - "oil-can": 0xf613, - "old-republic": 0xf510, - "om": 0xf679, - "opencart": 0xf23d, - "openid": 0xf19b, - "opera": 0xf26a, - "optin-monster": 0xf23c, - "orcid": 0xf8d2, - "osi": 0xf41a, - "otter": 0xf700, - "outdent": 0xf03b, - "page4": 0xf3d7, - "pagelines": 0xf18c, - "pager": 0xf815, - "paint-brush": 0xf1fc, - "paint-roller": 0xf5aa, - "palette": 0xf53f, - "palfed": 0xf3d8, - "pallet": 0xf482, - "paper-plane": 0xf1d8, - "paperclip": 0xf0c6, - "parachute-box": 0xf4cd, - "paragraph": 0xf1dd, - "parking": 0xf540, - "passport": 0xf5ab, - "pastafarianism": 0xf67b, - "paste": 0xf0ea, - "patreon": 0xf3d9, - "pause": 0xf04c, - "pause-circle": 0xf28b, - "paw": 0xf1b0, - "paypal": 0xf1ed, - "peace": 0xf67c, - "pen": 0xf304, - "pen-alt": 0xf305, - "pen-fancy": 0xf5ac, - "pen-nib": 0xf5ad, - "pen-square": 0xf14b, - "pencil-alt": 0xf303, - "pencil-ruler": 0xf5ae, - "penny-arcade": 0xf704, - "people-arrows": 0xe068, - "people-carry": 0xf4ce, - "pepper-hot": 0xf816, - "perbyte": 0xe083, - "percent": 0xf295, - "percentage": 0xf541, - "periscope": 0xf3da, - "person-booth": 0xf756, - "phabricator": 0xf3db, - "phoenix-framework": 0xf3dc, - "phoenix-squadron": 0xf511, - "phone": 0xf095, - "phone-alt": 0xf879, - "phone-slash": 0xf3dd, - "phone-square": 0xf098, - "phone-square-alt": 0xf87b, - "phone-volume": 0xf2a0, - "photo-video": 0xf87c, - "php": 0xf457, - "pied-piper": 0xf2ae, - "pied-piper-alt": 0xf1a8, - "pied-piper-hat": 0xf4e5, - "pied-piper-pp": 0xf1a7, - "pied-piper-square": 0xe01e, - "piggy-bank": 0xf4d3, - "pills": 0xf484, - "pinterest": 0xf0d2, - "pinterest-p": 0xf231, - "pinterest-square": 0xf0d3, - "pizza-slice": 0xf818, - "place-of-worship": 0xf67f, - "plane": 0xf072, - "plane-arrival": 0xf5af, - "plane-departure": 0xf5b0, - "plane-slash": 0xe069, - "play": 0xf04b, - "play-circle": 0xf144, - "playstation": 0xf3df, - "plug": 0xf1e6, - "plus": 0xf067, - "plus-circle": 0xf055, - "plus-square": 0xf0fe, - "podcast": 0xf2ce, - "poll": 0xf681, - "poll-h": 0xf682, - "poo": 0xf2fe, - "poo-storm": 0xf75a, - "poop": 0xf619, - "portrait": 0xf3e0, - "pound-sign": 0xf154, - "power-off": 0xf011, - "pray": 0xf683, - "praying-hands": 0xf684, - "prescription": 0xf5b1, - "prescription-bottle": 0xf485, - "prescription-bottle-alt": 0xf486, - "print": 0xf02f, - "procedures": 0xf487, - "product-hunt": 0xf288, - "project-diagram": 0xf542, - "pump-medical": 0xe06a, - "pump-soap": 0xe06b, - "pushed": 0xf3e1, - "puzzle-piece": 0xf12e, - "python": 0xf3e2, - "qq": 0xf1d6, - "qrcode": 0xf029, - "question": 0xf128, - "question-circle": 0xf059, - "quidditch": 0xf458, - "quinscape": 0xf459, - "quora": 0xf2c4, - "quote-left": 0xf10d, - "quote-right": 0xf10e, - "quran": 0xf687, - "r-project": 0xf4f7, - "radiation": 0xf7b9, - "radiation-alt": 0xf7ba, - "rainbow": 0xf75b, - "random": 0xf074, - "raspberry-pi": 0xf7bb, - "ravelry": 0xf2d9, - "react": 0xf41b, - "reacteurope": 0xf75d, - "readme": 0xf4d5, - "rebel": 0xf1d0, - "receipt": 0xf543, - "record-vinyl": 0xf8d9, - "recycle": 0xf1b8, - "red-river": 0xf3e3, - "reddit": 0xf1a1, - "reddit-alien": 0xf281, - "reddit-square": 0xf1a2, - "redhat": 0xf7bc, - "redo": 0xf01e, - "redo-alt": 0xf2f9, - "registered": 0xf25d, - "remove-format": 0xf87d, - "renren": 0xf18b, - "reply": 0xf3e5, - "reply-all": 0xf122, - "replyd": 0xf3e6, - "republican": 0xf75e, - "researchgate": 0xf4f8, - "resolving": 0xf3e7, - "restroom": 0xf7bd, - "retweet": 0xf079, - "rev": 0xf5b2, - "ribbon": 0xf4d6, - "ring": 0xf70b, - "road": 0xf018, - "robot": 0xf544, - "rocket": 0xf135, - "rocketchat": 0xf3e8, - "rockrms": 0xf3e9, - "route": 0xf4d7, - "rss": 0xf09e, - "rss-square": 0xf143, - "ruble-sign": 0xf158, - "ruler": 0xf545, - "ruler-combined": 0xf546, - "ruler-horizontal": 0xf547, - "ruler-vertical": 0xf548, - "running": 0xf70c, - "rupee-sign": 0xf156, - "rust": 0xe07a, - "sad-cry": 0xf5b3, - "sad-tear": 0xf5b4, - "safari": 0xf267, - "salesforce": 0xf83b, - "sass": 0xf41e, - "satellite": 0xf7bf, - "satellite-dish": 0xf7c0, - "save": 0xf0c7, - "schlix": 0xf3ea, - "school": 0xf549, - "screwdriver": 0xf54a, - "scribd": 0xf28a, - "scroll": 0xf70e, - "sd-card": 0xf7c2, - "search": 0xf002, - "search-dollar": 0xf688, - "search-location": 0xf689, - "search-minus": 0xf010, - "search-plus": 0xf00e, - "searchengin": 0xf3eb, - "seedling": 0xf4d8, - "sellcast": 0xf2da, - "sellsy": 0xf213, - "server": 0xf233, - "servicestack": 0xf3ec, - "shapes": 0xf61f, - "share": 0xf064, - "share-alt": 0xf1e0, - "share-alt-square": 0xf1e1, - "share-square": 0xf14d, - "shekel-sign": 0xf20b, - "shield-alt": 0xf3ed, - "shield-virus": 0xe06c, - "ship": 0xf21a, - "shipping-fast": 0xf48b, - "shirtsinbulk": 0xf214, - "shoe-prints": 0xf54b, - "shopify": 0xe057, - "shopping-bag": 0xf290, - "shopping-basket": 0xf291, - "shopping-cart": 0xf07a, - "shopware": 0xf5b5, - "shower": 0xf2cc, - "shuttle-van": 0xf5b6, - "sign": 0xf4d9, - "sign-in-alt": 0xf2f6, - "sign-language": 0xf2a7, - "sign-out-alt": 0xf2f5, - "signal": 0xf012, - "signature": 0xf5b7, - "sim-card": 0xf7c4, - "simplybuilt": 0xf215, - "sink": 0xe06d, - "sistrix": 0xf3ee, - "sitemap": 0xf0e8, - "sith": 0xf512, - "skating": 0xf7c5, - "sketch": 0xf7c6, - "skiing": 0xf7c9, - "skiing-nordic": 0xf7ca, - "skull": 0xf54c, - "skull-crossbones": 0xf714, - "skyatlas": 0xf216, - "skype": 0xf17e, - "slack": 0xf198, - "slack-hash": 0xf3ef, - "slash": 0xf715, - "sleigh": 0xf7cc, - "sliders-h": 0xf1de, - "slideshare": 0xf1e7, - "smile": 0xf118, - "smile-beam": 0xf5b8, - "smile-wink": 0xf4da, - "smog": 0xf75f, - "smoking": 0xf48d, - "smoking-ban": 0xf54d, - "sms": 0xf7cd, - "snapchat": 0xf2ab, - "snapchat-ghost": 0xf2ac, - "snapchat-square": 0xf2ad, - "snowboarding": 0xf7ce, - "snowflake": 0xf2dc, - "snowman": 0xf7d0, - "snowplow": 0xf7d2, - "soap": 0xe06e, - "socks": 0xf696, - "solar-panel": 0xf5ba, - "sort": 0xf0dc, - "sort-alpha-down": 0xf15d, - "sort-alpha-down-alt": 0xf881, - "sort-alpha-up": 0xf15e, - "sort-alpha-up-alt": 0xf882, - "sort-amount-down": 0xf160, - "sort-amount-down-alt": 0xf884, - "sort-amount-up": 0xf161, - "sort-amount-up-alt": 0xf885, - "sort-down": 0xf0dd, - "sort-numeric-down": 0xf162, - "sort-numeric-down-alt": 0xf886, - "sort-numeric-up": 0xf163, - "sort-numeric-up-alt": 0xf887, - "sort-up": 0xf0de, - "soundcloud": 0xf1be, - "sourcetree": 0xf7d3, - "spa": 0xf5bb, - "space-shuttle": 0xf197, - "speakap": 0xf3f3, - "speaker-deck": 0xf83c, - "spell-check": 0xf891, - "spider": 0xf717, - "spinner": 0xf110, - "splotch": 0xf5bc, - "spotify": 0xf1bc, - "spray-can": 0xf5bd, - "square": 0xf0c8, - "square-full": 0xf45c, - "square-root-alt": 0xf698, - "squarespace": 0xf5be, - "stack-exchange": 0xf18d, - "stack-overflow": 0xf16c, - "stackpath": 0xf842, - "stamp": 0xf5bf, - "star": 0xf005, - "star-and-crescent": 0xf699, - "star-half": 0xf089, - "star-half-alt": 0xf5c0, - "star-of-david": 0xf69a, - "star-of-life": 0xf621, - "staylinked": 0xf3f5, - "steam": 0xf1b6, - "steam-square": 0xf1b7, - "steam-symbol": 0xf3f6, - "step-backward": 0xf048, - "step-forward": 0xf051, - "stethoscope": 0xf0f1, - "sticker-mule": 0xf3f7, - "sticky-note": 0xf249, - "stop": 0xf04d, - "stop-circle": 0xf28d, - "stopwatch": 0xf2f2, - "stopwatch-20": 0xe06f, - "store": 0xf54e, - "store-alt": 0xf54f, - "store-alt-slash": 0xe070, - "store-slash": 0xe071, - "strava": 0xf428, - "stream": 0xf550, - "street-view": 0xf21d, - "strikethrough": 0xf0cc, - "stripe": 0xf429, - "stripe-s": 0xf42a, - "stroopwafel": 0xf551, - "studiovinari": 0xf3f8, - "stumbleupon": 0xf1a4, - "stumbleupon-circle": 0xf1a3, - "subscript": 0xf12c, - "subway": 0xf239, - "suitcase": 0xf0f2, - "suitcase-rolling": 0xf5c1, - "sun": 0xf185, - "superpowers": 0xf2dd, - "superscript": 0xf12b, - "supple": 0xf3f9, - "surprise": 0xf5c2, - "suse": 0xf7d6, - "swatchbook": 0xf5c3, - "swift": 0xf8e1, - "swimmer": 0xf5c4, - "swimming-pool": 0xf5c5, - "symfony": 0xf83d, - "synagogue": 0xf69b, - "sync": 0xf021, - "sync-alt": 0xf2f1, - "syringe": 0xf48e, - "table": 0xf0ce, - "table-tennis": 0xf45d, - "tablet": 0xf10a, - "tablet-alt": 0xf3fa, - "tablets": 0xf490, - "tachometer-alt": 0xf3fd, - "tag": 0xf02b, - "tags": 0xf02c, - "tape": 0xf4db, - "tasks": 0xf0ae, - "taxi": 0xf1ba, - "teamspeak": 0xf4f9, - "teeth": 0xf62e, - "teeth-open": 0xf62f, - "telegram": 0xf2c6, - "telegram-plane": 0xf3fe, - "temperature-high": 0xf769, - "temperature-low": 0xf76b, - "tencent-weibo": 0xf1d5, - "tenge": 0xf7d7, - "terminal": 0xf120, - "text-height": 0xf034, - "text-width": 0xf035, - "th": 0xf00a, - "th-large": 0xf009, - "th-list": 0xf00b, - "the-red-yeti": 0xf69d, - "theater-masks": 0xf630, - "themeco": 0xf5c6, - "themeisle": 0xf2b2, - "thermometer": 0xf491, - "thermometer-empty": 0xf2cb, - "thermometer-full": 0xf2c7, - "thermometer-half": 0xf2c9, - "thermometer-quarter": 0xf2ca, - "thermometer-three-quarters": 0xf2c8, - "think-peaks": 0xf731, - "thumbs-down": 0xf165, - "thumbs-up": 0xf164, - "thumbtack": 0xf08d, - "ticket-alt": 0xf3ff, - "tiktok": 0xe07b, - "times": 0xf00d, - "times-circle": 0xf057, - "tint": 0xf043, - "tint-slash": 0xf5c7, - "tired": 0xf5c8, - "toggle-off": 0xf204, - "toggle-on": 0xf205, - "toilet": 0xf7d8, - "toilet-paper": 0xf71e, - "toilet-paper-slash": 0xe072, - "toolbox": 0xf552, - "tools": 0xf7d9, - "tooth": 0xf5c9, - "torah": 0xf6a0, - "torii-gate": 0xf6a1, - "tractor": 0xf722, - "trade-federation": 0xf513, - "trademark": 0xf25c, - "traffic-light": 0xf637, - "trailer": 0xe041, - "train": 0xf238, - "tram": 0xf7da, - "transgender": 0xf224, - "transgender-alt": 0xf225, - "trash": 0xf1f8, - "trash-alt": 0xf2ed, - "trash-restore": 0xf829, - "trash-restore-alt": 0xf82a, - "tree": 0xf1bb, - "trello": 0xf181, - "trophy": 0xf091, - "truck": 0xf0d1, - "truck-loading": 0xf4de, - "truck-monster": 0xf63b, - "truck-moving": 0xf4df, - "truck-pickup": 0xf63c, - "tshirt": 0xf553, - "tty": 0xf1e4, - "tumblr": 0xf173, - "tumblr-square": 0xf174, - "tv": 0xf26c, - "twitch": 0xf1e8, - "twitter": 0xf099, - "twitter-square": 0xf081, - "typo3": 0xf42b, - "uber": 0xf402, - "ubuntu": 0xf7df, - "uikit": 0xf403, - "umbraco": 0xf8e8, - "umbrella": 0xf0e9, - "umbrella-beach": 0xf5ca, - "uncharted": 0xe084, - "underline": 0xf0cd, - "undo": 0xf0e2, - "undo-alt": 0xf2ea, - "uniregistry": 0xf404, - "unity": 0xe049, - "universal-access": 0xf29a, - "university": 0xf19c, - "unlink": 0xf127, - "unlock": 0xf09c, - "unlock-alt": 0xf13e, - "unsplash": 0xe07c, - "untappd": 0xf405, - "upload": 0xf093, - "ups": 0xf7e0, - "usb": 0xf287, - "user": 0xf007, - "user-alt": 0xf406, - "user-alt-slash": 0xf4fa, - "user-astronaut": 0xf4fb, - "user-check": 0xf4fc, - "user-circle": 0xf2bd, - "user-clock": 0xf4fd, - "user-cog": 0xf4fe, - "user-edit": 0xf4ff, - "user-friends": 0xf500, - "user-graduate": 0xf501, - "user-injured": 0xf728, - "user-lock": 0xf502, - "user-md": 0xf0f0, - "user-minus": 0xf503, - "user-ninja": 0xf504, - "user-nurse": 0xf82f, - "user-plus": 0xf234, - "user-secret": 0xf21b, - "user-shield": 0xf505, - "user-slash": 0xf506, - "user-tag": 0xf507, - "user-tie": 0xf508, - "user-times": 0xf235, - "users": 0xf0c0, - "users-cog": 0xf509, - "users-slash": 0xe073, - "usps": 0xf7e1, - "ussunnah": 0xf407, - "utensil-spoon": 0xf2e5, - "utensils": 0xf2e7, - "vaadin": 0xf408, - "vector-square": 0xf5cb, - "venus": 0xf221, - "venus-double": 0xf226, - "venus-mars": 0xf228, - "vest": 0xe085, - "vest-patches": 0xe086, - "viacoin": 0xf237, - "viadeo": 0xf2a9, - "viadeo-square": 0xf2aa, - "vial": 0xf492, - "vials": 0xf493, - "viber": 0xf409, - "video": 0xf03d, - "video-slash": 0xf4e2, - "vihara": 0xf6a7, - "vimeo": 0xf40a, - "vimeo-square": 0xf194, - "vimeo-v": 0xf27d, - "vine": 0xf1ca, - "virus": 0xe074, - "virus-slash": 0xe075, - "viruses": 0xe076, - "vk": 0xf189, - "vnv": 0xf40b, - "voicemail": 0xf897, - "volleyball-ball": 0xf45f, - "volume-down": 0xf027, - "volume-mute": 0xf6a9, - "volume-off": 0xf026, - "volume-up": 0xf028, - "vote-yea": 0xf772, - "vr-cardboard": 0xf729, - "vuejs": 0xf41f, - "walking": 0xf554, - "wallet": 0xf555, - "warehouse": 0xf494, - "watchman-monitoring": 0xe087, - "water": 0xf773, - "wave-square": 0xf83e, - "waze": 0xf83f, - "weebly": 0xf5cc, - "weibo": 0xf18a, - "weight": 0xf496, - "weight-hanging": 0xf5cd, - "weixin": 0xf1d7, - "whatsapp": 0xf232, - "whatsapp-square": 0xf40c, - "wheelchair": 0xf193, - "whmcs": 0xf40d, - "wifi": 0xf1eb, - "wikipedia-w": 0xf266, - "wind": 0xf72e, - "window-close": 0xf410, - "window-maximize": 0xf2d0, - "window-minimize": 0xf2d1, - "window-restore": 0xf2d2, - "windows": 0xf17a, - "wine-bottle": 0xf72f, - "wine-glass": 0xf4e3, - "wine-glass-alt": 0xf5ce, - "wix": 0xf5cf, - "wizards-of-the-coast": 0xf730, - "wodu": 0xe088, - "wolf-pack-battalion": 0xf514, - "won-sign": 0xf159, - "wordpress": 0xf19a, - "wordpress-simple": 0xf411, - "wpbeginner": 0xf297, - "wpexplorer": 0xf2de, - "wpforms": 0xf298, - "wpressr": 0xf3e4, - "wrench": 0xf0ad, - "x-ray": 0xf497, - "xbox": 0xf412, - "xing": 0xf168, - "xing-square": 0xf169, - "y-combinator": 0xf23b, - "yahoo": 0xf19e, - "yammer": 0xf840, - "yandex": 0xf413, - "yandex-international": 0xf414, - "yarn": 0xf7e3, - "yelp": 0xf1e9, - "yen-sign": 0xf157, - "yin-yang": 0xf6ad, - "yoast": 0xf2b1, - "youtube": 0xf167, - "youtube-square": 0xf431, - "zhihu": 0xf63f, -}; diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 35cfc12..0ad4c17 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -1,7 +1,7 @@ import "dart:async"; import "dart:io"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter/material.dart"; import "package:inventree/widget/snacks.dart"; import "package:url_launcher/url_launcher.dart"; @@ -9,7 +9,6 @@ import "package:path/path.dart" as path; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; -import "package:inventree/fa_icon_mapping.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; @@ -309,49 +308,31 @@ class InvenTreeModel { * - Second part specifies the icon * */ - FaIcon? get customIcon { - String icon = (jsondata["icon"] ?? "").toString(); + IconData? get customIcon { + String icon = (jsondata["icon"] ?? "").toString().trim(); // Empty icon (default) if (icon.isEmpty) { return null; } - final split = icon.trim().split(" "); - - // Must have two distinct units - if (split.length != 2) { + // Tabler icon is of the format "ti:: items = icon.split(":"); - // Remove "fa-" leading text (if provided) - if (name.startsWith("fa-")) { - name = name.substring(3); - } - - int iconHex = fontAwesomeIconMap[name] ?? 0; - - // No match for the icon name - if (iconHex == 0) { + if (items.length < 2) { return null; } - switch (style) { - case "fas": - return FaIcon(IconDataSolid(iconHex)); - case "fab": - return FaIcon(IconDataBrands(iconHex)); - case "fa": - return FaIcon(IconDataRegular(iconHex)); - case "fal": - return FaIcon(IconDataLight(iconHex)); - default: - // No match - return null; - } + String key = items[1]; + + key = key.replaceAll("-", "_"); + + // Tabler icon lookup + return TablerIcons.all[key]; } /* Extract any custom barcode data available for the model. @@ -960,13 +941,13 @@ class InvenTreeAttachment extends InvenTreeModel { String fn = filename.toLowerCase(); if (fn.endsWith(".pdf")) { - return FontAwesomeIcons.filePdf; + return TablerIcons.file_type_pdf; } else if (fn.endsWith(".csv")) { - return FontAwesomeIcons.fileCsv; + return TablerIcons.file_type_csv; } else if (fn.endsWith(".doc") || fn.endsWith(".docx")) { - return FontAwesomeIcons.fileWord; + return TablerIcons.file_type_doc; } else if (fn.endsWith(".xls") || fn.endsWith(".xlsx")) { - return FontAwesomeIcons.fileExcel; + return TablerIcons.file_type_xls; } // Image formats @@ -980,11 +961,11 @@ class InvenTreeAttachment extends InvenTreeModel { for (String fmt in img_formats) { if (fn.endsWith(fmt)) { - return FontAwesomeIcons.fileImage; + return TablerIcons.file_type_jpg; } } - return FontAwesomeIcons.fileLines; + return TablerIcons.file; } String get comment => getString("comment"); diff --git a/lib/labels.dart b/lib/labels.dart index 668bbf9..4d053ba 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -1,5 +1,5 @@ import "package:flutter/cupertino.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/api_form.dart"; @@ -89,7 +89,7 @@ Future selectAndPrintLabel( L10().printLabel, "", fields, - icon: FontAwesomeIcons.print, + icon: TablerIcons.printer, onSuccess: (Map data) async { int labelId = (data["label"] ?? -1) as int; var pluginKey = data["plugin"]; diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 880da20..7928eb2 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -4,7 +4,7 @@ import "package:inventree/settings/release.dart"; import "package:flutter/material.dart"; import "package:flutter/services.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/l10.dart"; @@ -91,8 +91,8 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().address), subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.globe), - trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER), + leading: Icon(TablerIcons.globe), + trailing: InvenTreeAPI().isConnected() ? Icon(TablerIcons.circle_check, color: COLOR_SUCCESS) : Icon(TablerIcons.circle_x, color: COLOR_DANGER), ) ); @@ -100,7 +100,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().username), subtitle: Text(InvenTreeAPI().username), - leading: InvenTreeAPI().username.isNotEmpty ? FaIcon(FontAwesomeIcons.user) : FaIcon(FontAwesomeIcons.userSlash, color: COLOR_DANGER), + leading: InvenTreeAPI().username.isNotEmpty ? Icon(TablerIcons.user) : Icon(TablerIcons.user_cancel, color: COLOR_DANGER), ) ); @@ -108,7 +108,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().version), subtitle: Text(InvenTreeAPI().serverVersion.isNotEmpty ? InvenTreeAPI().serverVersion : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.circleInfo), + leading: Icon(TablerIcons.info_circle), ) ); @@ -116,7 +116,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().serverInstance), subtitle: Text(InvenTreeAPI().serverInstance.isNotEmpty ? InvenTreeAPI().serverInstance : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.server), + leading: Icon(TablerIcons.server), ) ); @@ -125,7 +125,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().pluginSupport), subtitle: Text(L10().pluginSupportDetail), - leading: FaIcon(FontAwesomeIcons.plug), + leading: Icon(TablerIcons.plug), ) ); @@ -137,7 +137,7 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().serverNotConnected, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.circleExclamation) + leading: Icon(TablerIcons.exclamation_circle) ) ); } @@ -155,7 +155,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().packageName), subtitle: Text("${info.packageName}"), - leading: FaIcon(FontAwesomeIcons.box) + leading: Icon(TablerIcons.box) ) ); @@ -163,7 +163,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().version), subtitle: Text("${info.version} - Build ${info.buildNumber}"), - leading: FaIcon(FontAwesomeIcons.circleInfo) + leading: Icon(TablerIcons.info_circle) ) ); @@ -171,7 +171,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), onTap: () { _releaseNotes(context); }, @@ -182,7 +182,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().credits), subtitle: Text(L10().appCredits), - leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_ACTION), + leading: Icon(TablerIcons.balloon, color: COLOR_ACTION), onTap: () { _credits(context); } @@ -193,7 +193,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().documentation), subtitle: Text("https://docs.inventree.org/app"), - leading: FaIcon(FontAwesomeIcons.book, color: COLOR_ACTION), + leading: Icon(TablerIcons.book, color: COLOR_ACTION), onTap: () { _openDocs(); }, @@ -204,7 +204,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().translate), subtitle: Text(L10().translateHelp), - leading: FaIcon(FontAwesomeIcons.language, color: COLOR_ACTION), + leading: Icon(TablerIcons.language, color: COLOR_ACTION), onTap: () { _translate(); } @@ -215,7 +215,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().reportBug), subtitle: Text(L10().reportBugDescription), - leading: FaIcon(FontAwesomeIcons.bug, color: COLOR_ACTION), + leading: Icon(TablerIcons.bug, color: COLOR_ACTION), onTap: () { _reportBug(context); }, diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index f5d2ab4..f623f8f 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -3,7 +3,7 @@ import "package:inventree/api.dart"; import "package:one_context/one_context.dart"; import "package:adaptive_theme/adaptive_theme.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; import "package:inventree/app_colors.dart"; @@ -101,7 +101,7 @@ class _InvenTreeAppSettingsState extends State { L10().languageSelect, "", fields, - icon: FontAwesomeIcons.circleCheck, + icon: TablerIcons.circle_check, onSuccess: (Map data) async { String locale_name = (data["locale"] ?? "") as String; @@ -168,12 +168,12 @@ class _InvenTreeAppSettingsState extends State { L10().appSettings, style: TextStyle(fontWeight: FontWeight.bold), ), - leading: FaIcon(FontAwesomeIcons.mobile), + leading: Icon(TablerIcons.device_mobile), ), ListTile( title: Text(L10().darkMode), subtitle: Text(L10().darkModeEnable), - leading: FaIcon(FontAwesomeIcons.moon), + leading: Icon(TablerIcons.moon), trailing: Switch( value: darkMode, onChanged: (bool value) { @@ -226,7 +226,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().labelPrinting), subtitle: Text(L10().labelPrintingDetail), - leading: FaIcon(FontAwesomeIcons.print), + leading: Icon(TablerIcons.printer), trailing: Switch( value: enableLabelPrinting, onChanged: (bool value) { @@ -240,7 +240,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().strictHttps), subtitle: Text(L10().strictHttpsDetails), - leading: FaIcon(FontAwesomeIcons.lock), + leading: Icon(TablerIcons.lock), trailing: Switch( value: strictHttps, onChanged: (bool value) { @@ -254,7 +254,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().language), subtitle: Text(languageName), - leading: FaIcon(FontAwesomeIcons.language), + leading: Icon(TablerIcons.language), onTap: () async { _selectLocale(context); }, @@ -262,7 +262,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().errorReportUpload), subtitle: Text(L10().errorReportUploadDetails), - leading: FaIcon(FontAwesomeIcons.bug), + leading: Icon(TablerIcons.bug), trailing: Switch( value: reportErrors, onChanged: (bool value) { @@ -278,13 +278,13 @@ class _InvenTreeAppSettingsState extends State { L10().sounds, style: TextStyle(fontWeight: FontWeight.bold), ), - leading: FaIcon(FontAwesomeIcons.volumeHigh), + leading: Icon(TablerIcons.volume), ), Divider(), ListTile( title: Text(L10().serverError), subtitle: Text(L10().soundOnServerError), - leading: FaIcon(FontAwesomeIcons.server), + leading: Icon(TablerIcons.server), trailing: Switch( value: serverSounds, onChanged: (bool value) { @@ -298,7 +298,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().barcodeTones), subtitle: Text(L10().soundOnBarcodeAction), - leading: Icon(Icons.qr_code), + leading: Icon(TablerIcons.qrcode), trailing: Switch( value: barcodeSounds, onChanged: (bool value) { diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index ffcf404..d881124 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; @@ -105,7 +105,7 @@ class _InvenTreeBarcodeSettingsState extends State { ListTile( title: Text(L10().homeShowSubscribed), subtitle: Text(L10().homeShowSubscribedDescription), - leading: FaIcon(FontAwesomeIcons.bell), + leading: Icon(TablerIcons.bell), trailing: Switch( value: homeShowSubscribed, onChanged: (bool value) { @@ -76,7 +74,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowPo), subtitle: Text(L10().homeShowPoDescription), - leading: FaIcon(FontAwesomeIcons.cartShopping), + leading: Icon(TablerIcons.shopping_cart), trailing: Switch( value: homeShowPo, onChanged: (bool value) { @@ -90,7 +88,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowSo), subtitle: Text(L10().homeShowSoDescription), - leading: FaIcon(FontAwesomeIcons.truck), + leading: Icon(TablerIcons.truck), trailing: Switch( value: homeShowSo, onChanged: (bool value) { @@ -104,7 +102,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowSuppliers), subtitle: Text(L10().homeShowSuppliersDescription), - leading: FaIcon(FontAwesomeIcons.building), + leading: Icon(TablerIcons.building), trailing: Switch( value: homeShowSuppliers, onChanged: (bool value) { @@ -121,7 +119,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowManufacturers), subtitle: Text(L10().homeShowManufacturersDescription), - leading: FaIcon(FontAwesomeIcons.industry), + leading: Icon(TablerIcons.building_factory_2), trailing: Switch( value: homeShowManufacturers, onChanged: (bool value) { @@ -136,7 +134,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowCustomers), subtitle: Text(L10().homeShowCustomersDescription), - leading: FaIcon(FontAwesomeIcons.userTie), + leading: Icon(TablerIcons.user), trailing: Switch( value: homeShowCustomers, onChanged: (bool value) { diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 57b1c16..b895a38 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; + import "package:inventree/app_colors.dart"; import "package:inventree/user_profile.dart"; import "package:inventree/l10.dart"; @@ -84,12 +85,12 @@ class _InvenTreeLoginState extends State { ListTile( title: Text(L10().loginEnter), subtitle: Text(L10().loginEnterDetails), - leading: FaIcon(FontAwesomeIcons.userCheck), + leading: Icon(TablerIcons.user_check), ), ListTile( title: Text(L10().server), subtitle: Text(widget.profile.server), - leading: FaIcon(FontAwesomeIcons.server), + leading: Icon(TablerIcons.server), ), Divider(), ]; @@ -99,7 +100,7 @@ class _InvenTreeLoginState extends State { if (error.isNotEmpty) { after.add(Divider()); after.add(ListTile( - leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), title: Text(L10().error, style: TextStyle(color: COLOR_DANGER)), subtitle: Text(error, style: TextStyle(color: COLOR_DANGER)), )); @@ -109,7 +110,7 @@ class _InvenTreeLoginState extends State { title: Text(L10().login), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.arrowRightToBracket, color: COLOR_SUCCESS), + icon: Icon(TablerIcons.transition_right, color: COLOR_SUCCESS), onPressed: () async { _doLogin(context); }, @@ -150,7 +151,7 @@ class _InvenTreeLoginState extends State { labelStyle: TextStyle(fontWeight: FontWeight.bold), hintText: L10().enterPassword, suffixIcon: IconButton( - icon: _obscured ? FaIcon(FontAwesomeIcons.eye) : FaIcon(FontAwesomeIcons.solidEyeSlash), + icon: _obscured ? Icon(TablerIcons.eye) : Icon(TablerIcons.eye_off), onPressed: () { setState(() { _obscured = !_obscured; diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index d9d036f..bae7095 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; + import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; @@ -51,7 +52,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().parameters), subtitle: Text(L10().parametersSettingDetail), - leading: FaIcon(FontAwesomeIcons.tableList), + leading: Icon(TablerIcons.list), trailing: Switch( value: partShowParameters, onChanged: (bool value) { @@ -65,7 +66,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().bom), subtitle: Text(L10().bomEnable), - leading: FaIcon(FontAwesomeIcons.list), + leading: Icon(TablerIcons.list), trailing: Switch( value: partShowBom, onChanged: (bool value) { @@ -80,7 +81,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().stockItemHistory), subtitle: Text(L10().stockItemHistoryDetail), - leading: FaIcon(FontAwesomeIcons.clockRotateLeft), + leading: Icon(TablerIcons.history), trailing: Switch( value: stockShowHistory, onChanged: (bool value) { @@ -94,7 +95,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().testResults), subtitle: Text(L10().testResultsDetail), - leading: FaIcon(FontAwesomeIcons.vial), + leading: Icon(TablerIcons.test_pipe), trailing: Switch( value: stockShowTests, onChanged: (bool value) { @@ -108,7 +109,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().confirmScan), subtitle: Text(L10().confirmScanDetail), - leading: FaIcon(FontAwesomeIcons.qrcode), + leading: Icon(TablerIcons.qrcode), trailing: Switch( value: stockConfirmScan, onChanged: (bool value) { diff --git a/lib/settings/select_server.dart b/lib/settings/select_server.dart index cd247b6..5c941aa 100644 --- a/lib/settings/select_server.dart +++ b/lib/settings/select_server.dart @@ -1,8 +1,9 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/settings/login.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; +import "package:inventree/settings/login.dart"; + import "package:inventree/app_colors.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/spinner.dart"; @@ -151,18 +152,18 @@ class _InvenTreeSelectServerState extends State { // Reflect the connection status of the server if (InvenTreeAPI().isConnected()) { - return FaIcon( - FontAwesomeIcons.circleCheck, + return Icon( + TablerIcons.circle_check, color: COLOR_SUCCESS ); } else if (InvenTreeAPI().isConnecting()) { return Spinner( - icon: FontAwesomeIcons.spinner, + icon: TablerIcons.loader_2, color: COLOR_PROGRESS, ); } else { - return FaIcon( - FontAwesomeIcons.circleXmark, + return Icon( + TablerIcons.circle_x, color: COLOR_DANGER, ); } @@ -183,7 +184,7 @@ class _InvenTreeSelectServerState extends State { ), tileColor: profile.selected ? Theme.of(context).secondaryHeaderColor : null, subtitle: Text("${profile.server}"), - leading: profile.hasToken ? FaIcon(FontAwesomeIcons.userCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.userSlash, color: COLOR_WARNING), + leading: profile.hasToken ? Icon(TablerIcons.user_check, color: COLOR_SUCCESS) : Icon(TablerIcons.user_cancel, color: COLOR_WARNING), trailing: _getProfileIcon(profile), onTap: () { _selectProfile(context, profile); @@ -202,7 +203,7 @@ class _InvenTreeSelectServerState extends State { }, child: ListTile( title: Text(L10().profileConnect), - leading: FaIcon(FontAwesomeIcons.server), + leading: Icon(TablerIcons.server), ) ), SimpleDialogOption( @@ -212,7 +213,7 @@ class _InvenTreeSelectServerState extends State { }, child: ListTile( title: Text(L10().profileEdit), - leading: FaIcon(FontAwesomeIcons.penToSquare) + leading: Icon(TablerIcons.edit) ) ), SimpleDialogOption( @@ -222,7 +223,7 @@ class _InvenTreeSelectServerState extends State { }, child: ListTile( title: Text(L10().profileLogout), - leading: FaIcon(FontAwesomeIcons.userSlash), + leading: Icon(TablerIcons.logout), ) ), Divider(), @@ -234,7 +235,7 @@ class _InvenTreeSelectServerState extends State { L10().delete, L10().profileDelete + "?", color: Colors.red, - icon: FontAwesomeIcons.trashCan, + icon: TablerIcons.trash, onAccept: () { _deleteProfile(profile); } @@ -242,7 +243,7 @@ class _InvenTreeSelectServerState extends State { }, child: ListTile( title: Text(L10().profileDelete, style: TextStyle(color: Colors.red)), - leading: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), + leading: Icon(TablerIcons.trash, color: Colors.red), ) ) ], @@ -267,7 +268,7 @@ class _InvenTreeSelectServerState extends State { title: Text(L10().profileSelect), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.circlePlus), + icon: Icon(TablerIcons.circle_plus), onPressed: () { _editProfile(context, createNew: true); }, @@ -316,7 +317,7 @@ class _ProfileEditState extends State { title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.floppyDisk), + icon: Icon(TablerIcons.device_floppy), onPressed: () async { if (formKey.currentState!.validate()) { formKey.currentState!.save(); diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index dbf7e7e..595a15b 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/app_colors.dart"; @@ -49,7 +49,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().server), subtitle: Text(L10().configureServer), - leading: FaIcon(FontAwesomeIcons.server, color: COLOR_ACTION), + leading: Icon(TablerIcons.server, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget())); }, @@ -57,7 +57,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_ACTION), + leading: Icon(TablerIcons.settings, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); } @@ -65,7 +65,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), - leading: FaIcon(FontAwesomeIcons.house, color: COLOR_ACTION), + leading: Icon(TablerIcons.home, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } @@ -73,7 +73,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().barcodes), subtitle: Text(L10().barcodeSettings), - leading: FaIcon(FontAwesomeIcons.barcode, color: COLOR_ACTION), + leading: Icon(TablerIcons.barcode, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeBarcodeSettingsWidget())); } @@ -81,7 +81,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().part), subtitle: Text(L10().partSettings), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePartSettingsWidget())); } @@ -89,7 +89,7 @@ class _InvenTreeSettingsState extends State { Divider(), ListTile( title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.circleInfo, color: COLOR_ACTION), + leading: Icon(TablerIcons.info_circle, color: COLOR_ACTION), onTap: _about, ) ] diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index e182df0..78d4dad 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -2,7 +2,7 @@ import "dart:io"; import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; import "package:url_launcher/url_launcher.dart"; @@ -52,7 +52,7 @@ class _AttachmentWidgetState extends RefreshableState { return [ IconButton( - icon: FaIcon(FontAwesomeIcons.camera), + icon: Icon(TablerIcons.camera), onPressed: () async { FilePickerDialog.pickImageFromCamera().then((File? file) { upload(context, file); @@ -60,7 +60,7 @@ class _AttachmentWidgetState extends RefreshableState { } ), IconButton( - icon: FaIcon(FontAwesomeIcons.fileArrowUp), + icon: Icon(TablerIcons.file_upload), onPressed: () async { FilePickerDialog.pickFileFromDevice().then((File? file) { upload(context, file); @@ -122,7 +122,7 @@ class _AttachmentWidgetState extends RefreshableState { }, child: ListTile( title: Text(L10().delete), - leading: FaIcon(FontAwesomeIcons.trashCan), + leading: Icon(TablerIcons.trash), ) ) ] @@ -171,7 +171,7 @@ class _AttachmentWidgetState extends RefreshableState { tiles.add(ListTile( title: Text(attachment.filename), subtitle: Text(attachment.comment), - leading: FaIcon(attachment.icon, color: COLOR_ACTION), + leading: Icon(attachment.icon, color: COLOR_ACTION), onTap: () async { showLoadingOverlay(context); await attachment.downloadAttachment(); @@ -187,7 +187,7 @@ class _AttachmentWidgetState extends RefreshableState { tiles.add(ListTile( title: Text(attachment.link), subtitle: Text(attachment.comment), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () async { var uri = Uri.tryParse(attachment.link.trimLeft()); if (uri != null && await canLaunchUrl(uri)) { diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 57cdc38..f79992b 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -57,7 +57,7 @@ class _CompanyDetailState extends RefreshableState { if (InvenTreeCompany().canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), tooltip: L10().companyEdit, onPressed: () { editCompany(context); @@ -75,7 +75,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.isCustomer && InvenTreeSalesOrder().canCreate) { actions.add(SpeedDialChild( - child: FaIcon(FontAwesomeIcons.truck), + child: Icon(TablerIcons.truck), label: L10().salesOrderCreate, onTap: () async { _createSalesOrder(context); @@ -85,7 +85,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.isSupplier && InvenTreePurchaseOrder().canCreate) { actions.add(SpeedDialChild( - child: FaIcon(FontAwesomeIcons.cartShopping), + child: Icon(TablerIcons.shopping_cart), label: L10().purchaseOrderCreate, onTap: () async { _createPurchaseOrder(context); @@ -243,8 +243,8 @@ class _CompanyDetailState extends RefreshableState { color: COLOR_DANGER ) ), - leading: FaIcon( - FontAwesomeIcons.circleExclamation, + leading: Icon( + TablerIcons.exclamation_circle, color: COLOR_DANGER ), ) @@ -254,7 +254,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.website.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.website}"), - leading: FaIcon(FontAwesomeIcons.globe, color: COLOR_ACTION), + leading: Icon(TablerIcons.globe, color: COLOR_ACTION), onTap: () async { openLink(widget.company.website); }, @@ -266,7 +266,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.email.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.email}"), - leading: FaIcon(FontAwesomeIcons.at, color: COLOR_ACTION), + leading: Icon(TablerIcons.at, color: COLOR_ACTION), onTap: () async { openLink("mailto:${widget.company.email}"); }, @@ -278,7 +278,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.phone.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.phone}"), - leading: FaIcon(FontAwesomeIcons.phone, color: COLOR_ACTION), + leading: Icon(TablerIcons.phone, color: COLOR_ACTION), onTap: () { openLink("tel:${widget.company.phone}"); }, @@ -291,7 +291,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.link.isNotEmpty) { tiles.add(ListTile( title: Text("${widget.company.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () { widget.company.openLink(); }, @@ -310,7 +310,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().supplierParts), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), trailing: Text(supplierPartCount.toString()), onTap: () { Navigator.push( @@ -329,7 +329,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_ACTION), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), trailing: Text("${outstandingPurchaseOrders}"), onTap: () { Navigator.push( @@ -351,7 +351,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().suppliedParts), - leading: FaIcon(FontAwesomeIcons.shapes), + leading: Icon(TablerIcons.box), trailing: Text("${company.partSuppliedCount}"), ) ); @@ -366,7 +366,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().salesOrders), - leading: FaIcon(FontAwesomeIcons.truck, color: COLOR_ACTION), + leading: Icon(TablerIcons.truck, color: COLOR_ACTION), trailing: Text("${outstandingSalesOrders}"), onTap: () { Navigator.push( @@ -387,7 +387,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.notes.isNotEmpty) { tiles.add(ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky), + leading: Icon(TablerIcons.note), onTap: null, )); } @@ -395,7 +395,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add(ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index a8268e3..2b6a9d4 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -78,7 +78,7 @@ class _SupplierPartDisplayState extends RefreshableState choiceDialog(String title, List items, {Function? onSelecte /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ -Future confirmationDialog(String title, String text, {Color? color, IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { +Future confirmationDialog(String title, String text, {Color? color, IconData icon = TablerIcons.help_circle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; @@ -69,7 +69,7 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa iconColor: color, title: ListTile( title: Text(title, style: TextStyle(color: color)), - leading: FaIcon(icon, color: color), + leading: Icon(icon, color: color), ), content: text.isEmpty ? Text(text) : null, actions: [ @@ -109,7 +109,7 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa * @description = Simple string description of error * @data = Error response (e.g from server) */ -Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.circleExclamation, Function? onDismissed}) async { +Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = TablerIcons.exclamation_circle, Function? onDismissed}) async { List children = []; @@ -180,7 +180,7 @@ Future showErrorDialog(String title, {String description = "", APIResponse builder: (context) => SimpleDialog( title: ListTile( title: Text(title), - leading: FaIcon(icon), + leading: Icon(icon), ), children: children ) @@ -224,7 +224,7 @@ Future showServerError(String url, String title, String description) async showErrorDialog( L10().serverError, description: description, - icon: FontAwesomeIcons.server + icon: TablerIcons.server ); } ); diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 5dd47c8..1fbbbe4 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -120,7 +120,7 @@ class InvenTreeDrawer extends StatelessWidget { // "Home" access tiles.add(ListTile( - leading: FaIcon(FontAwesomeIcons.house, color: COLOR_ACTION), + leading: Icon(TablerIcons.home, color: COLOR_ACTION), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -134,7 +134,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().parts), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), onTap: _parts, ) ); @@ -144,7 +144,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().stock), - leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_ACTION), + leading: Icon(TablerIcons.package, color: COLOR_ACTION), onTap: _stock, ) ); @@ -154,7 +154,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_ACTION), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), onTap: _purchaseOrders, ) ); @@ -164,7 +164,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( title: Text(L10().salesOrders), - leading: FaIcon(FontAwesomeIcons.truck, color: COLOR_ACTION), + leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), onTap: _salesOrders, ) ); @@ -178,7 +178,7 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( - leading: FaIcon(FontAwesomeIcons.bell, color: COLOR_ACTION), + leading: Icon(TablerIcons.bell, color: COLOR_ACTION), trailing: notification_count > 0 ? Text(notification_count.toString()) : null, title: Text(L10().notifications), onTap: _notifications, diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index bff9cf2..8a7d600 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -3,7 +3,7 @@ import "dart:io"; import "package:file_picker/file_picker.dart"; import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:image_picker/image_picker.dart"; import "package:one_context/one_context.dart"; @@ -80,7 +80,7 @@ class FilePickerDialog { actions.add( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.fileArrowUp), + leading: Icon(TablerIcons.arrow_up), title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { @@ -108,7 +108,7 @@ class FilePickerDialog { actions.add( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.camera), + leading: Icon(TablerIcons.camera), title: Text(L10().takePicture), ), onPressed: () async { diff --git a/lib/widget/home.dart b/lib/widget/home.dart index e9034a7..e68c35c 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -1,8 +1,7 @@ import "dart:async"; import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -193,7 +192,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr horizontal: 12 ), child: ListTile( - leading: FaIcon(icon, color: connected && allowed ? COLOR_ACTION : Colors.grey), + leading: Icon(icon, color: connected && allowed ? COLOR_ACTION : Colors.grey), title: Text(label), trailing: trailing, ), @@ -202,7 +201,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr if (!allowed) { showSnackIcon( L10().permissionRequired, - icon: FontAwesomeIcons.circleExclamation, + icon: TablerIcons.exclamation_circle, success: false, ); return; @@ -229,7 +228,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().parts, - FontAwesomeIcons.shapes, + TablerIcons.box, callback: () { _showParts(context); }, @@ -241,7 +240,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().partsStarred, - FontAwesomeIcons.bell, + TablerIcons.bell, callback: () { _showStarredParts(context); } @@ -253,7 +252,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().stock, - FontAwesomeIcons.boxesStacked, + TablerIcons.package, callback: () { _showStock(context); } @@ -265,7 +264,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().purchaseOrders, - FontAwesomeIcons.cartShopping, + TablerIcons.shopping_cart, callback: () { _showPurchaseOrders(context); } @@ -276,7 +275,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().salesOrders, - FontAwesomeIcons.truck, + TablerIcons.truck_delivery, callback: () { _showSalesOrders(context); } @@ -288,7 +287,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().suppliers, - FontAwesomeIcons.building, + TablerIcons.building, callback: () { _showSuppliers(context); } @@ -304,7 +303,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().manufacturers, - FontAwesomeIcons.industry, + TablerIcons.building_factory_2, callback: () { _showManufacturers(context); } @@ -316,7 +315,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr tiles.add(_listTile( context, L10().customers, - FontAwesomeIcons.userTie, + TablerIcons.building_store, callback: () { _showCustomers(context); } @@ -336,8 +335,8 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr bool validAddress = serverAddress != null; bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); - Widget leading = FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER); - Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_ACTION); + Widget leading = Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER); + Widget trailing = Icon(TablerIcons.server, color: COLOR_ACTION); String title = L10().serverNotConnected; String subtitle = L10().profileSelectOrCreate; @@ -346,7 +345,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr } else if (connecting) { title = L10().serverConnecting; subtitle = serverAddress; - leading = Spinner(icon: FontAwesomeIcons.spinner, color: COLOR_PROGRESS); + leading = Spinner(icon: TablerIcons.loader_2, color: COLOR_PROGRESS); } return Center( @@ -400,8 +399,8 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr title: Text(L10().appTitle), actions: [ IconButton( - icon: FaIcon( - FontAwesomeIcons.server, + icon: Icon( + TablerIcons.server, color: connected ? COLOR_SUCCESS : (connecting ? COLOR_PROGRESS: COLOR_DANGER), ), onPressed: _selectProfile, diff --git a/lib/widget/notes_widget.dart b/lib/widget/notes_widget.dart index a5c1146..d871dd0 100644 --- a/lib/widget/notes_widget.dart +++ b/lib/widget/notes_widget.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:flutter_markdown/flutter_markdown.dart"; @@ -47,7 +47,7 @@ class _NotesState extends RefreshableState { if (widget.model.canEdit) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.penToSquare), + icon: Icon(TablerIcons.edit), tooltip: L10().edit, onPressed: () { widget.model.editForm( diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 4c34203..9b5dabe 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; @@ -80,7 +80,7 @@ class _NotificationState extends RefreshableState { L10().notifications, ), subtitle: notifications.isEmpty ? Text(L10().notificationsEmpty) : null, - leading: notifications.isEmpty ? FaIcon(FontAwesomeIcons.bellSlash) : FaIcon(FontAwesomeIcons.bell), + leading: notifications.isEmpty ? Icon(TablerIcons.bell_exclamation) : Icon(TablerIcons.bell), trailing: Text("${notifications.length}"), ) ); @@ -91,7 +91,7 @@ class _NotificationState extends RefreshableState { title: Text(notification.name), subtitle: Text(notification.message), trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.bookmark), + icon: Icon(TablerIcons.bookmark), onPressed: isDismissing ? null : () async { dismissNotification(context, notification); }, diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index d5510d9..bddeb4d 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; @@ -48,7 +48,7 @@ class _POLineDetailWidgetState extends RefreshableState { if (widget.item.canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), onPressed: () { _editLineItem(context); }, @@ -68,7 +68,7 @@ class _POLineDetailWidgetState extends RefreshableState { if (!widget.item.isComplete) { buttons.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.rightToBracket, color: Colors.blue), + child: Icon(TablerIcons.transition_right, color: Colors.blue), label: L10().receiveItem, onTap: () async { receiveLineItem(context); @@ -146,7 +146,7 @@ class _POLineDetailWidgetState extends RefreshableState { order.receive_url, fields, method: "POST", - icon: FontAwesomeIcons.rightToBracket, + icon: TablerIcons.transition_right, onSuccess: (data) async { showSnackIcon(L10().receivedItem, success: true); refresh(context); @@ -167,7 +167,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().internalPart), subtitle: Text(widget.item.partName), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), trailing: api.getThumbnail(widget.item.partImage), onTap: () async { showLoadingOverlay(context); @@ -186,7 +186,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().supplierPart), subtitle: Text(widget.item.SKU), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), onTap: () async { showLoadingOverlay(context); var part = await InvenTreeSupplierPart().get(widget.item.supplierPartId); @@ -210,7 +210,7 @@ class _POLineDetailWidgetState extends RefreshableState { color: widget.item.isComplete ? COLOR_SUCCESS: COLOR_WARNING ) ), - leading: FaIcon(FontAwesomeIcons.boxOpen), + leading: Icon(TablerIcons.progress), ) ); @@ -220,7 +220,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().reference), subtitle: Text(widget.item.reference), - leading: FaIcon(FontAwesomeIcons.hashtag), + leading: Icon(TablerIcons.hash), ) ); } @@ -229,7 +229,7 @@ class _POLineDetailWidgetState extends RefreshableState { tiles.add( ListTile( title: Text(L10().unitPrice), - leading: FaIcon(FontAwesomeIcons.dollarSign), + leading: Icon(TablerIcons.currency_dollar), trailing: Text( renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) ), @@ -242,7 +242,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().notes), subtitle: Text(widget.item.notes), - leading: FaIcon(FontAwesomeIcons.noteSticky), + leading: Icon(TablerIcons.note), ) ); } @@ -253,7 +253,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().link), subtitle: Text(widget.item.link), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () async { await openLink(widget.item.link); }, diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index ea0e308..6f413f5 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/order/po_line_list.dart"; @@ -57,7 +57,7 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart index d285f6e..f19306c 100644 --- a/lib/widget/order/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; @@ -41,7 +41,7 @@ class _PurchaseOrderListWidgetState extends RefreshableState { if (widget.order.canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), onPressed: () { editOrder(context); }, @@ -105,7 +105,7 @@ class _SalesOrderDetailState extends RefreshableState { confirmationDialog( L10().issueOrder, "", - icon: FontAwesomeIcons.paperPlane, + icon: TablerIcons.send, color: Colors.blue, acceptText: L10().issue, onAccept: () async { @@ -121,7 +121,7 @@ class _SalesOrderDetailState extends RefreshableState { confirmationDialog( L10().cancelOrder, "", - icon: FontAwesomeIcons.circleXmark, + icon: TablerIcons.circle_x, color: Colors.red, acceptText: L10().cancel, onAccept: () async { @@ -139,7 +139,7 @@ class _SalesOrderDetailState extends RefreshableState { if (widget.order.isPending) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.paperPlane, color: Colors.blue), + child: Icon(TablerIcons.send, color: Colors.blue), label: L10().issueOrder, onTap: () async { _issueOrder(context); @@ -151,7 +151,7 @@ class _SalesOrderDetailState extends RefreshableState { if (widget.order.isOpen) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circleXmark, color: Colors.red), + child: Icon(TablerIcons.circle_x, color: Colors.red), label: L10().cancelOrder, onTap: () async { _cancelOrder(context); @@ -164,7 +164,7 @@ class _SalesOrderDetailState extends RefreshableState { if (widget.order.isInProgress && InvenTreeSOLineItem().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circlePlus, color: Colors.green), + child: Icon(TablerIcons.circle_plus, color: Colors.green), label: L10().lineItemAdd, onTap: () async { _addLineItem(context); @@ -174,7 +174,7 @@ class _SalesOrderDetailState extends RefreshableState { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.truck, color: Colors.green), + child: Icon(TablerIcons.circle_plus, color: Colors.green), label: L10().shipmentAdd, onTap: () async { _addShipment(context); @@ -207,7 +207,7 @@ class _SalesOrderDetailState extends RefreshableState { if (api.supportsBarcodeSOAllocateEndpoint) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.rightToBracket), + child: Icon(TablerIcons.transition_right), label: L10().allocateStock, onTap: () async { scanBarcode( @@ -299,7 +299,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add(ListTile( title: Text(L10().projectCode), subtitle: Text("${widget.order.projectCode} - ${widget.order.projectCodeDescription}"), - leading: FaIcon(FontAwesomeIcons.list), + leading: Icon(TablerIcons.list), )); } @@ -307,7 +307,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add(ListTile( title: Text(L10().customer), subtitle: Text(customer.name), - leading: FaIcon(FontAwesomeIcons.userTie, color: COLOR_ACTION), + leading: Icon(TablerIcons.user, color: COLOR_ACTION), onTap: () { Navigator.push( context, @@ -323,7 +323,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add(ListTile( title: Text(L10().customerReference), subtitle: Text(widget.order.customerReference), - leading: FaIcon(FontAwesomeIcons.hashtag), + leading: Icon(TablerIcons.hash), )); } @@ -335,7 +335,7 @@ class _SalesOrderDetailState extends RefreshableState { widget.order.completedLineItemCount.toDouble(), maximum: widget.order.lineItemCount.toDouble() ), - leading: FaIcon(FontAwesomeIcons.clipboardCheck), + leading: Icon(TablerIcons.clipboard_check), trailing: Text("${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), )); @@ -345,7 +345,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add(ListTile( title: Text(L10().targetDate), subtitle: Text(widget.order.targetDate), - leading: FaIcon(FontAwesomeIcons.calendarDays), + leading: Icon(TablerIcons.calendar), )); } @@ -353,7 +353,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), onTap: () { Navigator.push( context, @@ -369,7 +369,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( @@ -407,4 +407,4 @@ class _SalesOrderDetailState extends RefreshableState { ]; } -} \ No newline at end of file +} diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart index a97de80..37a8405 100644 --- a/lib/widget/order/sales_order_list.dart +++ b/lib/widget/order/sales_order_list.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; import "package:inventree/widget/paginator.dart"; @@ -39,7 +39,7 @@ class _SalesOrderListWidgetState extends RefreshableState if (InvenTreeSalesOrder().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circlePlus), + child: Icon(TablerIcons.circle_plus), label: L10().salesOrderCreate, onTap: () { _createSalesOrder(context); diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index a416898..c2d4181 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -6,7 +6,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/sales_order.dart"; @@ -52,7 +52,7 @@ class _SOLineDetailWidgetState extends RefreshableState { if (widget.item.canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), onPressed: () { _editLineItem(context); }), @@ -87,7 +87,7 @@ class _SOLineDetailWidgetState extends RefreshableState { order!.allocate_url, fields, method: "POST", - icon: FontAwesomeIcons.rightToBracket, + icon: TablerIcons.transition_right, onSuccess: (data) async { refresh(context); } @@ -122,7 +122,7 @@ class _SOLineDetailWidgetState extends RefreshableState { if (order != null && order!.isOpen) { buttons.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.rightToBracket, color: Colors.blue), + child: Icon(TablerIcons.transition_right, color: Colors.blue), label: L10().allocateStock, onTap: () async { _allocateStock(context); @@ -143,7 +143,7 @@ class _SOLineDetailWidgetState extends RefreshableState { if (api.supportsBarcodeSOAllocateEndpoint) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.rightToBracket), + child: Icon(TablerIcons.transition_right), label: L10().allocateStock, onTap: () async { scanBarcode( @@ -184,7 +184,7 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().part), subtitle: Text(widget.item.partName), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), trailing: api.getThumbnail(widget.item.partImage), onTap: () async { showLoadingOverlay(context); @@ -202,7 +202,7 @@ class _SOLineDetailWidgetState extends RefreshableState { tiles.add( ListTile( title: Text(L10().availableStock), - leading: FaIcon(FontAwesomeIcons.boxesStacked), + leading: Icon(TablerIcons.packages), trailing: Text(simpleNumberString(widget.item.availableStock)) ) ); @@ -210,7 +210,7 @@ class _SOLineDetailWidgetState extends RefreshableState { // Allocated quantity tiles.add( ListTile( - leading: FaIcon(FontAwesomeIcons.clipboardCheck), + leading: Icon(TablerIcons.clipboard_check), title: Text(L10().allocated), subtitle: ProgressBar(widget.item.allocatedRatio), trailing: Text( @@ -233,7 +233,7 @@ class _SOLineDetailWidgetState extends RefreshableState { color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING ), ), - leading: FaIcon(FontAwesomeIcons.truck) + leading: Icon(TablerIcons.truck) ) ); @@ -243,7 +243,7 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().reference), subtitle: Text(widget.item.reference), - leading: FaIcon(FontAwesomeIcons.hashtag) + leading: Icon(TablerIcons.hash) ) ); } @@ -254,7 +254,7 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().notes), subtitle: Text(widget.item.notes), - leading: FaIcon(FontAwesomeIcons.noteSticky), + leading: Icon(TablerIcons.note), ) ); } @@ -265,7 +265,7 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().link), subtitle: Text(widget.item.link), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () async { await openLink(widget.item.link); }, diff --git a/lib/widget/order/so_shipment_list.dart b/lib/widget/order/so_shipment_list.dart index 92ddc9f..a1e0dc7 100644 --- a/lib/widget/order/so_shipment_list.dart +++ b/lib/widget/order/so_shipment_list.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/paginator.dart"; @@ -47,7 +47,7 @@ class _PaginatedSOShipmentListState extends PaginatedSearchState extends Sta L10().filteringOptions, "", fields, - icon: FontAwesomeIcons.circleCheck, + icon: TablerIcons.circle_check, onSuccess: (Map data) async { // Extract data from the processed form @@ -487,8 +487,8 @@ abstract class PaginatedSearchState extends Sta Widget buildSearchInput(BuildContext context) { return ListTile( trailing: GestureDetector( - child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, + child: Icon( + searchController.text.isEmpty ? TablerIcons.search : TablerIcons.backspace, color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_ACTION, ), onTap: () { @@ -526,7 +526,7 @@ class NoResultsWidget extends StatelessWidget { description, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_WARNING), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_WARNING), ); } diff --git a/lib/widget/part/bom_list.dart b/lib/widget/part/bom_list.dart index d9e16bb..b599a62 100644 --- a/lib/widget/part/bom_list.dart +++ b/lib/widget/part/bom_list.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; @@ -48,7 +48,7 @@ class _BillOfMaterialsState extends RefreshableState { @override List appBarActions(BuildContext context) => [ IconButton( - icon: FaIcon(FontAwesomeIcons.filter), + icon: Icon(TablerIcons.filter), onPressed: () async { setState(() { showFilterOptions = !showFilterOptions; diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart index 35be18c..bc7ab08 100644 --- a/lib/widget/part/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; @@ -41,7 +41,7 @@ class _CategoryDisplayState extends RefreshableState { if (InvenTreePartCategory().canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), tooltip: L10().editCategory, onPressed: () { _editCategoryDialog(context); @@ -61,7 +61,7 @@ class _CategoryDisplayState extends RefreshableState { if (InvenTreePart().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.shapes), + child: Icon(TablerIcons.box), label: L10().partCreateDetail, onTap: _newPart, ) @@ -71,7 +71,7 @@ class _CategoryDisplayState extends RefreshableState { if (InvenTreePartCategory().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.sitemap), + child: Icon(TablerIcons.sitemap), label: L10().categoryCreateDetail, onTap: () { _newCategory(context); @@ -123,7 +123,7 @@ class _CategoryDisplayState extends RefreshableState { if (widget.category == null) { return Card( child: ListTile( - leading: FaIcon(FontAwesomeIcons.shapes), + leading: Icon(TablerIcons.packages), title: Text( L10().partCategoryTopLevel, style: TextStyle(fontStyle: FontStyle.italic), @@ -138,7 +138,7 @@ class _CategoryDisplayState extends RefreshableState { style: TextStyle(fontWeight: FontWeight.bold) ), subtitle: Text("${widget.category?.description}"), - leading: widget.category!.customIcon ?? FaIcon(FontAwesomeIcons.sitemap), + leading: widget.category!.customIcon != null ? Icon(widget.category!.customIcon) : Icon(TablerIcons.sitemap) ), ]; @@ -147,8 +147,8 @@ class _CategoryDisplayState extends RefreshableState { ListTile( title: Text(L10().parentCategory), subtitle: Text("${widget.category?.parentPathString}"), - leading: FaIcon( - FontAwesomeIcons.turnUp, + leading: Icon( + TablerIcons.arrow_move_up, color: COLOR_ACTION, ), onTap: () async { diff --git a/lib/widget/part/category_list.dart b/lib/widget/part/category_list.dart index a203102..cc5a40e 100644 --- a/lib/widget/part/category_list.dart +++ b/lib/widget/part/category_list.dart @@ -98,7 +98,7 @@ class _PaginatedPartCategoryListState extends PaginatedSearchState { if (InvenTreePart().canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), tooltip: L10().editPart, onPressed: () { _editPartDialog(context); @@ -109,7 +108,7 @@ class _PartDisplayState extends RefreshableState { if (InvenTreeStockItem().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.box), + child: Icon(TablerIcons.packages), label: L10().stockItemCreate, onTap: () { _newStockItem(context); @@ -121,7 +120,7 @@ class _PartDisplayState extends RefreshableState { if (labels.isNotEmpty) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.print), + child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { selectAndPrintLabel( @@ -329,8 +328,8 @@ class _PartDisplayState extends RefreshableState { color: COLOR_DANGER ) ), - leading: FaIcon( - FontAwesomeIcons.circleExclamation, + leading: Icon( + TablerIcons.exclamation_circle, color: COLOR_DANGER ), ) @@ -363,7 +362,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().partCategory), subtitle: Text("${part.categoryName}"), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_ACTION), + leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), onTap: () async { if (part.categoryId > 0) { @@ -384,7 +383,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().partCategory), subtitle: Text(L10().partCategoryTopLevel), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_ACTION), + leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), onTap: () { Navigator.push(context, MaterialPageRoute( builder: (context) => CategoryDisplayWidget(null))); @@ -398,7 +397,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().variants), - leading: FaIcon(FontAwesomeIcons.shapes, color: COLOR_ACTION), + leading: Icon(TablerIcons.versions, color: COLOR_ACTION), trailing: Text(variantCount.toString()), onTap: () { Navigator.push( @@ -421,7 +420,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), - leading: FaIcon(FontAwesomeIcons.boxesStacked), + leading: Icon(TablerIcons.packages), trailing: Text( part.stockString(), style: TextStyle( @@ -439,7 +438,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().onOrder), subtitle: Text(L10().onOrderDetails), - leading: FaIcon(FontAwesomeIcons.cartShopping), + leading: Icon(TablerIcons.shopping_cart), trailing: Text("${part.onOrderString}"), onTap: () { // TODO - Order views @@ -456,7 +455,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_ACTION), + leading: Icon(TablerIcons.list_tree, color: COLOR_ACTION), trailing: Text(bomCount.toString()), onTap: () { Navigator.push(context, MaterialPageRoute( @@ -471,7 +470,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().building), - leading: FaIcon(FontAwesomeIcons.screwdriverWrench), + leading: Icon(TablerIcons.tools), trailing: Text("${simpleNumberString(part.building)}"), onTap: () { // TODO @@ -487,7 +486,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().usedIn), subtitle: Text(L10().usedInDetails), - leading: FaIcon(FontAwesomeIcons.layerGroup, color: COLOR_ACTION), + leading: Icon(TablerIcons.stack_2, color: COLOR_ACTION), trailing: Text(usedInCount.toString()), onTap: () { Navigator.push( @@ -507,7 +506,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("${part.keywords}"), - leading: FaIcon(FontAwesomeIcons.tags), + leading: Icon(TablerIcons.tags), ) ); } @@ -517,7 +516,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("${part.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () { part.openLink(); }, @@ -532,7 +531,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().usedIn), subtitle: Text(L10().usedInDetails), - leading: FaIcon(FontAwesomeIcons.sitemap), + leading: Icon(TablerIcons.sitemap), trailing: Text("${part.usedInCount}"), onTap: () { // TODO @@ -547,7 +546,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.industry, color: COLOR_ACTION), + leading: Icon(TablerIcons.building_factory, color: COLOR_ACTION), trailing: Text("${part.supplierCount}"), onTap: () { Navigator.push( @@ -566,7 +565,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), trailing: Text(""), onTap: () { Navigator.push( @@ -580,7 +579,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/part/part_image_widget.dart b/lib/widget/part/part_image_widget.dart index 68b12bd..41da371 100644 --- a/lib/widget/part/part_image_widget.dart +++ b/lib/widget/part/part_image_widget.dart @@ -1,8 +1,7 @@ import "dart:io"; import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/inventree/part.dart"; @@ -47,7 +46,7 @@ class _PartImageState extends RefreshableState { // File upload actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.fileArrowUp), + icon: Icon(TablerIcons.file_upload), onPressed: () async { FilePickerDialog.pickFile( diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index c2ce12b..8296b7e 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -1,5 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -85,7 +86,7 @@ mixin BaseWidgetProperties { }, ), IconButton( - icon: Icon(Icons.search, color: COLOR_ACTION), + icon: Icon(TablerIcons.search, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { diff --git a/lib/widget/search.dart b/lib/widget/search.dart index a899c83..dfa0d13 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -1,7 +1,7 @@ import "dart:async"; import "package:async/async.dart"; import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -357,8 +357,8 @@ class _SearchDisplayState extends RefreshableState { }, ), trailing: GestureDetector( - child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, + child: Icon( + searchController.text.isEmpty ? TablerIcons.search : TablerIcons.backspace, color: searchController.text.isEmpty ? COLOR_ACTION : COLOR_DANGER, ), onTap: () { @@ -379,7 +379,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().parts), - leading: FaIcon(FontAwesomeIcons.shapes), + leading: Icon(TablerIcons.box), trailing: Text("${nPartResults}"), onTap: () { Navigator.push( @@ -402,7 +402,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().partCategories), - leading: FaIcon(FontAwesomeIcons.sitemap), + leading: Icon(TablerIcons.sitemap), trailing: Text("${nCategoryResults}"), onTap: () { Navigator.push( @@ -425,7 +425,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockItems), - leading: FaIcon(FontAwesomeIcons.boxesStacked), + leading: Icon(TablerIcons.package), trailing: Text("${nStockResults}"), onTap: () { Navigator.push( @@ -448,7 +448,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockLocations), - leading: FaIcon(FontAwesomeIcons.locationDot), + leading: Icon(TablerIcons.location), trailing: Text("${nLocationResults}"), onTap: () { Navigator.push( @@ -471,7 +471,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.building), + leading: Icon(TablerIcons.building), trailing: Text("${nSupplierResults}"), onTap: () { Navigator.push( @@ -496,7 +496,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.cartShopping), + leading: Icon(TablerIcons.shopping_cart), trailing: Text("${nPurchaseOrderResults}"), onTap: () { Navigator.push( @@ -518,7 +518,7 @@ class _SearchDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().searching), - leading: FaIcon(FontAwesomeIcons.magnifyingGlass), + leading: Icon(TablerIcons.search), trailing: CircularProgressIndicator(), ) ); @@ -531,7 +531,7 @@ class _SearchDisplayState extends RefreshableState { L10().queryNoResults, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.magnifyingGlassMinus), + leading: Icon(TablerIcons.zoom_cancel), ) ); } else { diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index b5341af..66f5f15 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -1,5 +1,5 @@ import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; import "package:inventree/helpers.dart"; @@ -32,14 +32,14 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc // Select an icon if we do not have an action if (icon == null && onAction == null) { - icon = FontAwesomeIcons.circleCheck; + icon = TablerIcons.circle_check; } } else if (success != null && success == false) { backgroundColor = Colors.deepOrange; if (icon == null && onAction == null) { - icon = FontAwesomeIcons.circleExclamation; + icon = TablerIcons.exclamation_circle; } } @@ -51,7 +51,7 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc ]; if (icon != null) { - childs.add(FaIcon(icon)); + childs.add(Icon(icon)); } OneContext().showSnackBar(builder: (context) => SnackBar( diff --git a/lib/widget/spinner.dart b/lib/widget/spinner.dart index 5e9d598..3ac68c5 100644 --- a/lib/widget/spinner.dart +++ b/lib/widget/spinner.dart @@ -1,6 +1,4 @@ import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; class Spinner extends StatefulWidget { @@ -31,7 +29,7 @@ class _SpinnerState extends State with SingleTickerProviderStateMixin { duration: Duration(milliseconds: 2000), ) ..repeat(); - _child = FaIcon( + _child = Icon( widget.icon, color: widget.color ); diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 0251667..377325f 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -1,7 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; @@ -70,7 +69,7 @@ class _LocationDisplayState extends RefreshableState { if (location != null && InvenTreeStockLocation().canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), tooltip: L10().editLocation, onPressed: () { _editLocationDialog(context); @@ -92,7 +91,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeStockItem().canEdit) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.qrcode), + child: Icon(TablerIcons.qrcode), label: L10().barcodeScanItem, onTap: () { scanBarcode( @@ -125,7 +124,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeStockLocation().canEdit) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.qrcode), + child: Icon(TablerIcons.qrcode), label: L10().transferStockLocation, onTap: () { scanBarcode( @@ -160,7 +159,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeStockLocation().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.sitemap), + child: Icon(TablerIcons.sitemap), label: L10().locationCreate, onTap: () async { _newLocation(context); @@ -173,7 +172,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeStockItem().canCreate) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.boxesStacked), + child: Icon(TablerIcons.packages), label: L10().stockItemCreate, onTap: () async { _newStockItem(context); @@ -185,7 +184,7 @@ class _LocationDisplayState extends RefreshableState { if (widget.location != null && labels.isNotEmpty) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.print), + child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { selectAndPrintLabel( @@ -334,7 +333,7 @@ class _LocationDisplayState extends RefreshableState { L10().stockTopLevel, style: TextStyle(fontStyle: FontStyle.italic) ), - leading: FaIcon(FontAwesomeIcons.boxesStacked), + leading: Icon(TablerIcons.packages), ) ); } else { @@ -342,8 +341,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text("${location!.name}"), subtitle: Text("${location!.description}"), - leading: location!.customIcon ?? - FaIcon(FontAwesomeIcons.boxesStacked), + leading: location!.customIcon == null ? Icon(TablerIcons.packages) : Icon(location!.customIcon) ), ]; @@ -352,7 +350,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().parentLocation), subtitle: Text("${location!.parentPathString}"), - leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_ACTION), + leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), onTap: () async { int parentId = location?.parentId ?? -1; diff --git a/lib/widget/stock/location_list.dart b/lib/widget/stock/location_list.dart index a8bc2fe..c8506a9 100644 --- a/lib/widget/stock/location_list.dart +++ b/lib/widget/stock/location_list.dart @@ -85,7 +85,7 @@ class _PaginatedStockLocationListState extends PaginatedSearchState { if (widget.item.canEdit) { actions.add( IconButton( - icon: Icon(Icons.edit_square), + icon: Icon(TablerIcons.edit), tooltip: L10().editItem, onPressed: () { _editStockItem(context); @@ -94,7 +94,7 @@ class _StockItemDisplayState extends RefreshableState { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circleCheck, color: Colors.blue), + child: Icon(TablerIcons.circle_check, color: Colors.blue), label: L10().countStock, onTap: _countStockDialog, ) @@ -102,7 +102,7 @@ class _StockItemDisplayState extends RefreshableState { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circleMinus, color: Colors.red), + child: Icon(TablerIcons.circle_minus, color: Colors.red), label: L10().removeStock, onTap: _removeStockDialog, ) @@ -110,7 +110,7 @@ class _StockItemDisplayState extends RefreshableState { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.circlePlus, color: Colors.green), + child: Icon(TablerIcons.circle_plus, color: Colors.green), label: L10().addStock, onTap: _addStockDialog, ) @@ -120,7 +120,7 @@ class _StockItemDisplayState extends RefreshableState { // Transfer item actions.add( SpeedDialChild( - child: Icon(Icons.trolley), + child: Icon(TablerIcons.transfer), label: L10().transferStock, onTap: () { _transferStockDialog(context); @@ -132,7 +132,7 @@ class _StockItemDisplayState extends RefreshableState { if (labels.isNotEmpty) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.print), + child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { selectAndPrintLabel( @@ -150,7 +150,7 @@ class _StockItemDisplayState extends RefreshableState { if (widget.item.canDelete) { actions.add( SpeedDialChild( - child: FaIcon(FontAwesomeIcons.trashCan, color: Colors.red), + child: Icon(TablerIcons.trash, color: Colors.red), label: L10().stockItemDelete, onTap: () { _deleteItem(context); @@ -284,7 +284,7 @@ class _StockItemDisplayState extends RefreshableState { confirmationDialog( L10().stockItemDelete, L10().stockItemDeleteConfirm, - icon: FontAwesomeIcons.trashCan, + icon: TablerIcons.trash, color: Colors.red, acceptText: L10().delete, onAccept: () async { @@ -353,7 +353,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.addStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.circlePlus, + icon: TablerIcons.circle_plus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -394,7 +394,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.removeStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.circleMinus, + icon: TablerIcons.circle_minus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -425,7 +425,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.countStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.clipboardCheck, + icon: TablerIcons.clipboard_check, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -446,7 +446,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.transferStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.dolly, + icon: TablerIcons.transfer, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -506,8 +506,8 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().stockLocation), subtitle: Text("${widget.item.locationPathString}"), - leading: FaIcon( - FontAwesomeIcons.locationDot, + leading: Icon( + TablerIcons.location, color: COLOR_ACTION, ), onTap: () async { @@ -529,7 +529,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().stockLocation), - leading: FaIcon(FontAwesomeIcons.locationDot), + leading: Icon(TablerIcons.location), subtitle: Text(L10().locationNotSet), ) ); @@ -540,7 +540,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().serialNumber), - leading: FaIcon(FontAwesomeIcons.hashtag), + leading: Icon(TablerIcons.hash), subtitle: Text("${widget.item.serialNumber}"), ) ); @@ -548,7 +548,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: widget.item.allocated > 0 ? Text(L10().quantityAvailable) : Text(L10().quantity), - leading: FaIcon(FontAwesomeIcons.cubes), + leading: Icon(TablerIcons.packages), trailing: Text("${widget.item.quantityString()}"), ) ); @@ -558,7 +558,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().status), - leading: FaIcon(FontAwesomeIcons.circleInfo), + leading: Icon(TablerIcons.help_circle), trailing: Text( api.StockStatus.label(widget.item.status), style: TextStyle( @@ -574,7 +574,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_ACTION), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage, hideIfNull: true), onTap: () async { showLoadingOverlay(context); @@ -596,7 +596,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().inProduction), - leading: FaIcon(FontAwesomeIcons.screwdriverWrench), + leading: Icon(TablerIcons.tools), subtitle: Text(L10().inProductionDetail), onTap: () { // TODO: Click through to the "build order" @@ -610,7 +610,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().batchCode), subtitle: Text(widget.item.batch), - leading: FaIcon(FontAwesomeIcons.layerGroup), + leading: Icon(TablerIcons.clipboard_text), ) ); } @@ -620,7 +620,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().packaging), subtitle: Text(widget.item.packaging), - leading: FaIcon(FontAwesomeIcons.boxesPacking), + leading: Icon(TablerIcons.package), ) ); } @@ -632,7 +632,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastUpdated), subtitle: Text(widget.item.updatedDateString), - leading: FaIcon(FontAwesomeIcons.calendarDays) + leading: Icon(TablerIcons.calendar) ) ); } @@ -643,7 +643,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastStocktake), subtitle: Text(widget.item.stocktakeDateString), - leading: FaIcon(FontAwesomeIcons.calendarDays) + leading: Icon(TablerIcons.calendar) ) ); } @@ -652,7 +652,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("${widget.item.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_ACTION), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () { widget.item.openLink(); }, @@ -664,7 +664,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().testResults), - leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_ACTION), + leading: Icon(TablerIcons.list_check, color: COLOR_ACTION), trailing: Text("${widget.item.testResultCount}"), onTap: () { Navigator.push( @@ -683,7 +683,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().purchasePrice), - leading: FaIcon(FontAwesomeIcons.dollarSign), + leading: Icon(TablerIcons.currency_dollar), trailing: Text( renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) ) @@ -697,7 +697,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_ACTION), + leading: Icon(TablerIcons.history, color: COLOR_ACTION), trailing: Text("${widget.item.trackingItemCount}"), onTap: () { Navigator.push( @@ -716,7 +716,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_ACTION), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), onTap: () { Navigator.push( context, @@ -729,7 +729,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_ACTION), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( diff --git a/lib/widget/stock/stock_item_test_results.dart b/lib/widget/stock/stock_item_test_results.dart index b6315d9..c65422d 100644 --- a/lib/widget/stock/stock_item_test_results.dart +++ b/lib/widget/stock/stock_item_test_results.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; @@ -42,7 +42,7 @@ class _StockItemTestResultDisplayState extends RefreshableState Date: Wed, 14 Aug 2024 20:29:45 +1000 Subject: [PATCH 489/746] New Crowdin updates (#518) * New translations app_en.arb (Swedish) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/sv_SE/app_sv_SE.arb | 486 +++++++++++++++++------------------ lib/l10n/zh_CN/app_zh_CN.arb | 6 +- 2 files changed, 246 insertions(+), 246 deletions(-) diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 208df40..1e75a68 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -84,134 +84,134 @@ "@barcodeNotAssigned": {}, "barcodeScanPart": "Skanna artikelstreckkod", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Skanna streckkod för att ta emot del", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Streckkodsskanning pausad", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tryck eller håll ned för att pausa skanning", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "Skanna för att tilldela streckkod", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Skanner indata", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Välj streckkodsläsare indatakälla", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Streckkod Skanna Fördröjning", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Fördröjning mellan streckkodsskanningar", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "Skanna en InvenTree streckkod", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Skanna lagervaror till denna plats", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "Skanna lagerplats", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Enkelt skanningsläge", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Pausa streckkodsläsare efter varje skanning", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "Skannad till plats", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "Objektet skannades inte in", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "Skanna lagervara", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Streckkods Toner", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "Ta bort streckkod", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "Streckkoden känns inte igen", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "Batchkod", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "Stycklista", "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Visa stycklista", "@bomEnable": {}, "build": "Bygg", "@build": {}, - "building": "Building", + "building": "Bygger", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Intern kamera", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Använd intern kamera för att läsa streckkoder", "@cameraInternalDetail": {}, "cancel": "Avbryt", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Avbryt order", "@cancelOrder": {}, "category": "Kategori", "@category": {}, "categoryCreate": "Ny kategori", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "Skapa ny artikelkategori", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Artikel kategori uppdaterad", "@categoryUpdated": {}, "company": "Företag", "@company": {}, - "companyEdit": "Edit Company", + "companyEdit": "Redigera företag", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "Inga företag som matchar frågan", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "Företagsdetaljer uppdaterade", "@companyUpdated": {}, - "companies": "Companies", + "companies": "Företag", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "Konfigurera serverinställningar", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Bekräfta överföring", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "confirmScanDetail": "Bekräfta lageröverföringsdetaljer vid skanning av streckkoder", + "connectionRefused": "Anslutning nekad", "@connectionRefused": {}, - "count": "Count", + "count": "Antal", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "Antal Lager", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "Krediter", "@credits": {}, - "customer": "Customer", + "customer": "Kund", "@customer": {}, "customers": "Kunder", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Kundreferens", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Skadad", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "Mörkt läge", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Aktivera mörkt läge", "@darkModeEnable": {}, "delete": "Radera", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Borttagning misslyckades", "@deleteFailed": {}, - "deletePart": "Delete Part", + "deletePart": "Ta bort del", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "Ta bort denna del från databasen", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Borttagning lyckad", "@deleteSuccess": {}, "description": "Beskrivning", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "Förstörd", "@destroyed": {}, - "details": "Details", + "details": "Detaljer", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "Dokumentation", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "Laddar ner fil", "@downloading": {}, "downloadError": "Nedladdningsfel", "@downloadError": {}, @@ -225,7 +225,7 @@ "@editLocation": {}, "editNotes": "Redigera anteckningar", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Redigera parameter", "@editParameter": {}, "editPart": "Redigera artikel", "@editPart": { @@ -249,110 +249,110 @@ "@errorDelete": {}, "errorDetails": "Felinformation", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "Fel vid hämtning av data från servern", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Fel vid begäran om användarroller från servern", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Fel vid begäran av plugin-data från servern", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "Felrapportering", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "Ladda upp felrapporter", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Ladda upp anonyma felrapporter och kraschloggar", "@errorReportUploadDetails": {}, "feedback": "Feedback", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Det gick inte att skicka feedback", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Feedback inskickat", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Aktiv", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Visa aktiva komponenter", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Sammansatt", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Visa sammansatta delar", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Komponent", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Visa komponentdelar", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Extern", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Visa lager på externa platser", "@filterExternalDetail": {}, "filterInStock": "I lager", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Visa artiklar som har lager", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serialiserad", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Visa serialiserade lagervaror", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Mall", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Visa mallartiklar", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Spårbar", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Visa spårbara artiklar", "@filterTrackableDetail": {}, - "filterVirtual": "Virtual", + "filterVirtual": "Virtuell", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Visa virtuella artiklar", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Filtreringsalternativ", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Formatera undantag", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "JSON-dataformat undantag", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Formulär fel", "@formError": {}, - "history": "History", + "history": "Historik", "@history": { "description": "history" }, - "home": "Home", + "home": "Hem", "@homeScreen": {}, - "homeScreen": "Home Screen", - "homeScreenSettings": "Configure home screen settings", + "homeScreen": "Startsidan", + "homeScreenSettings": "Konfigurera inställningar för startskärmen", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Visa inköpsorder", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Visa knappen för inköpsorder på startskärmen", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Visa försäljningsorder", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Visa knappen för försäljningsorder på startskärmen", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Prenumererade artiklar", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Visa prenumererade artiklar på startskärmen", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "Visa leverantörer", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Visa leverantörsknapp på startskärmen", "@homeShowSupplierDescription": {}, "homeShowManufacturers": "Visa tillverkare", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Visa tillverkarknapp på startskärmen", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Visa kunder", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Visa kund knappen på startskärmen", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Bilduppladdning misslyckades", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Bild uppladdad", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Inaktiv", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Detta företag är markerat som inaktivt", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "Denna artikel är markerad som inaktiv", "@inactiveDetail": {}, "includeSubcategories": "Inkludera underkategorier", "@includeSubcategories": {}, @@ -362,101 +362,101 @@ "@includeSublocations": {}, "includeSublocationsDetail": "Show results from sublocations", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "Ofullständig profilinformation", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "Internt artikelnummer", "@internalPartNumber": {}, - "info": "Info", + "info": "Information", "@info": {}, - "inProduction": "In Production", + "inProduction": "Under produktion", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "Denna lagervara är i produktion", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Intern artikel", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "Ogiltigt värdnamn", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "Angivet värdnamn är inte giltigt", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "Ogiltig Artikel", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "Ogiltig artikelkategori", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "Ogiltig lagerplats", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "Ogiltig lagervara", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Ogiltig leverantörs artikel", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "Felaktigt användarnamn / lösenord kombination", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "Ärende", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Utfärdad datum", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Ärende order", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "Föremålet finns redan på plats", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Objektet har tagits bort", "@itemDeleted": {}, "keywords": "Nyckelord", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Utskrift av etiketter", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Aktivera etikettutskrift", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Etikettmall", "@labelTemplate": {}, "language": "Språk", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Standard systemspråk", "@languageDefault": {}, "languageSelect": "Välj språk", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Senaste inventering", "@lastStocktake": {}, "lastUpdated": "Senast uppdaterad", "@lastUpdated": {}, - "level": "Level", + "level": "Nivå", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Lägg till radobjekt", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Rad objekt", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "Radobjekt", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Rad uppdaterad", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Hitta lagerobjekt", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Hitta lagerplats", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Ny plats", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "Skapa ny lagerplats", "@locationCreateDetail": {}, - "locationNotSet": "No location specified", + "locationNotSet": "Ingen plats specificerad", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "Lagerplatsen uppdaterad", "@locationUpdated": {}, - "login": "Login", + "login": "Logga in", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Ange inloggningsuppgifter", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Användarnamn och lösenord sparas inte lokalt", "@loginEnterDetails": {}, - "link": "Link", + "link": "Länk", "@link": {}, - "lost": "Lost", + "lost": "Förlorad", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Tillverkarens artikelnummer", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Tillverkare", "@manufacturer": {}, "manufacturers": "Tillverkare", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Data saknas", "@missingData": {}, "name": "Namn", "@name": {}, @@ -572,115 +572,115 @@ "@plugin": {}, "pluginPrinter": "Printer", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "Stöd för tillägg aktiverat", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Servern stöder anpassade plugins", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "Utskrift av etiketter misslyckades", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "Etikett skickad till skrivare", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Profil", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "Lägg till serverprofil", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "Anslut till server", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "Redigera Server profil", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "Radera serverprofil", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Utloggning profil", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "Profilnamn", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "Inga profiler tillgängliga", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "Ingen profil vald", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "Välj InvenTree Server", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "Välj server eller skapa en ny profil", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "Tryck för att skapa eller välj en profil", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Projektkod", "@projectCode": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "Inköpsorder", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Ny inköpsorder", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "Redigera inköpsorder", "@purchaseOrderEdit": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "Inköpsorder", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "Inköpsorder uppdaterad", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "Inköpspris", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Antal", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Tillgängligt antal", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Antal är tomt", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Antalet är ogiltigt", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Antal måste vara positiv", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Ange sökfråga", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "Inga resultat hittades", "@queryNoResults": {}, - "received": "Received", + "received": "Mottaget", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Visa mottagna artiklar", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Ta emot artikel", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "Mottagen lagerartikel", "@receivedItem": {}, "reference": "Referens", "@reference": {}, - "refresh": "Refresh", + "refresh": "Uppdatera", "@refresh": {}, - "refreshing": "Refreshing", + "refreshing": "Uppdaterar", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Avvisad", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "Utgivningsnoteringar", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Ta bort", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "Ta bort lager", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Rapportera bugg", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "Skicka in felrapport (kräver GitHub-konto)", "@reportBugDescription": {}, - "results": "Results", + "results": "Resultat", "@results": {}, - "request": "Request", + "request": "Begäran", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "Begäran misslyckades", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "Begäran lyckades", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "Begär data", "@requestingData": {}, - "required": "Required", + "required": "Krävs", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "Felaktig begäran", "@response400": {}, - "response401": "Unauthorized", + "response401": "Ej autentiserad", "@response401": {}, "response403": "Permission Denied", "@response403": {}, @@ -796,125 +796,125 @@ "@serverDetails": {}, "serverMissingData": "Server response missing required fields", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Gammal server version", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Serverinställningar", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Servern måste börja med http[s]", "@serverStart": {}, "settings": "Inställningar", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Serverinstans", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Servern är inte ansluten", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Servern är inte vald", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Frakt", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Lägg till frakt", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Skickad", "@shipped": {}, "sku": "SKU", "@sku": {}, - "sounds": "Sounds", + "sounds": "Ljud", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Spela upp ljudsignal vid streckkodsåtgärd", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Spela upp ljud vid serverfel", "@soundOnServerError": {}, "status": "Status", "@status": {}, "statusCode": "Statuskod", "@statusCode": {}, - "stock": "Stock", + "stock": "Lager", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Nuvarande lagersaldo", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "Lager artikel", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "Lager Artiklar", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "Ny lagerartikel", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "Skapa ny lagerartikel på denna plats", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "Ta bort lagerartikel", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Är du säker du vill ta bort denna lagerartikel?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "Kunde inte ta bort lagerartikel", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "Lagerartikel borttagen", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "Lagerhistorik", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Visa historisk lagerspårningsinformation", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "Lagerartikel överförd", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "Lagerartikel uppdaterad", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "Inga lagerartiklar tillgängliga", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "Lagerartiklar Anteckningar", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "Lagerartikel uppdaterad", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "Lagerartikelns uppdatering misslyckades", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "Lagerplats", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "Lagerplatser", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "Högsta nivå lagerplats", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Använd strikt HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Tvinga strikt kontroll av HTTPs certifikat", "@strictHttpsDetails": {}, "subcategory": "Underkategori", "@subcategory": {}, "subcategories": "Underkategorier", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "Underplacering", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "Underplaceringar", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "Inga Underplaceringar", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "Inga underplaceringar tillgängliga", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "Skicka Feedback", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "Levererade delar", "@suppliedParts": {}, "supplier": "Leverantör", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Leverantörsartikel", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Redigera leverantörsartikel", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Leverantör Artikel Nummer", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Leverantör artikel nummer uppdaterad", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Leverantörsartikel", "@supplierParts": {}, "suppliers": "Leverantörer", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "Leverantörens referens", "@supplierReference": {}, - "takePicture": "Take Picture", + "takePicture": "Ta bild", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "Måldatum", "@targetDate": {}, "templatePart": "Parent Template Part", "@templatePart": {}, diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 472dab1..27595ab 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -28,7 +28,7 @@ }, "address": "地址", "@address": {}, - "appAbout": "关于 InventTree", + "appAbout": "关于 InvenTree", "@appAbout": {}, "appCredits": "额外 app 凭据", "@appCredits": {}, @@ -42,7 +42,7 @@ "@appReleaseNotes": {}, "appSettings": "应用设置", "@appSettings": {}, - "appSettingsDetails": "配置 InventTree app 设置项", + "appSettingsDetails": "配置 InvenTree app 设置项", "@appSettingsDetails": {}, "attachments": "附件", "@attachments": {}, @@ -968,7 +968,7 @@ "@transferStockLocationDetail": {}, "translate": "转移", "@translate": {}, - "translateHelp": "协助翻译 InventTree 应用", + "translateHelp": "协助翻译 InvenTree 应用", "@translateHelp": {}, "unitPrice": "单价", "@unitPrice": {}, From 30cfcc5ffe9d6fb6a2eb781b151824884cebe474 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 18 Aug 2024 16:13:08 +1000 Subject: [PATCH 490/746] New Crowdin updates (#519) * New translations app_en.arb (Swedish) * New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 22 +-- lib/l10n/sv_SE/app_sv_SE.arb | 268 +++++++++++++++++------------------ 2 files changed, 145 insertions(+), 145 deletions(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 0c3c22c..b679add 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -183,7 +183,7 @@ "@customer": {}, "customers": "Klienci", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Numer referencyjny klienta", "@customerReference": {}, "damaged": "Uszkodzone", "@damaged": {}, @@ -251,7 +251,7 @@ "@errorDetails": {}, "errorFetch": "Błąd pobierania danych z serwea", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Błąd podczas wczytywania ról użytkownika z serwera", "@errorUserRoles": {}, "errorPluginInfo": "Error requesting plugin data from server", "@errorPluginInfo": {}, @@ -289,11 +289,11 @@ "@filterInStockDetail": {}, "filterSerialized": "Serializowane", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Pokaż serializowane elementy magazynowe", "@filterSerializedDetail": {}, "filterTemplate": "Szablon", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Pokaż części szablonu", "@filterTemplateDetail": {}, "filterTrackable": "Możliwość śledzenia", "@filterTrackable": {}, @@ -350,17 +350,17 @@ "@imageUploadSuccess": {}, "inactive": "Nieaktywny", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Ta firma jest oznaczona jako nieaktywna", "@inactiveCompany": {}, "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", "@inactiveDetail": {}, "includeSubcategories": "Zawieraj podkategorie", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "Pokaż wyniki z podkategorii", "@includeSubcategoriesDetail": {}, "includeSublocations": "Zawieraj sublokacje", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Pokaż wyniki z sublokacji", "@includeSublocationsDetail": {}, "incompleteDetails": "Niekompletne szczegóły profilu", "@incompleteDetails": {}, @@ -386,7 +386,7 @@ "@invalidStockLocation": {}, "invalidStockItem": "Nieprawidłowa część magazynowa", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Nieprawidłowy element dostawcy", "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nieprawidłowy login lub hasło", "@invalidUsernamePassword": {}, @@ -398,7 +398,7 @@ "@issueOrder": {}, "itemInLocation": "Część jest już w lokacji", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Element został usunięty", "@itemDeleted": {}, "keywords": "Słowa kluczowe", "@keywords": {}, @@ -496,11 +496,11 @@ "@orientationSystem": {}, "outstanding": "Outstanding", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Pokaż oczekujące zamówienia", "@outstandingOrderDetail": {}, "overdue": "Zaległe", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Pokaż zaległe zamówienia", "@overdueDetail": {}, "packaging": "Opakowanie", "@packaging": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 1e75a68..2c39b3b 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -358,9 +358,9 @@ "@includeSubcategories": {}, "includeSubcategoriesDetail": "Visa resultat från underkategorier", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "Inkludera underplats", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Visa resultat från underplatser", "@includeSublocationsDetail": {}, "incompleteDetails": "Ofullständig profilinformation", "@incompleteDetails": {}, @@ -460,117 +460,117 @@ "@missingData": {}, "name": "Namn", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "Ej ansluten", "@notConnected": {}, "notes": "Anteckningar", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Aviseringar", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Inga olästa aviseringar", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Inget svar från servern", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Inga resultat", "@noResults": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Inga underkategorier tillgängliga", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Ogiltigt nummer", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "På order", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Artiklar på beställning för närvarande", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Skärmorientering", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Skärmorientering (kräver omstart)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Liggande", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Porträtt", "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Utestående", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Visa utestående order", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Försenad", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Visa försenade ordrar", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Paketering", "@packaging": {}, - "packageName": "Package Name", + "packageName": "Paketets namn", "@packageName": {}, "parameters": "Parametrar", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Visa artikelparametrar", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "Föregående", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Föregående Kategori", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "Föregående Plats", "@parentLocation": {}, - "part": "Part", + "part": "Artkel", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Ny Artikel", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Skapa ny artikel i denna kategori", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Artikel uppdaterad", "@partEdited": {}, - "parts": "Parts", + "parts": "Artiklar", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Artikel inte markerad som säljbart", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "Inga Artiklar", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "Inga artiklar som matchar sökfrågan", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "Artikel inställningar", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "Prenumererade artiklar", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "Inga stjärnmärkta artiklar tillgängliga", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "Artikel leverantörer", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "Artikel Kategori", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "Artikel kategori på toppnivå", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "Artikelkategorier", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Artikel Detaljer", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Artikel Anteckningar", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Artikellager", "@partStock": { "description": "part stock" }, "password": "Lösenord", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "Lösenordet får inte vara tomt", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Ditt konto har inte de rättigheter som krävs för att utföra denna åtgärd", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Särskilda behörigheter krävs", "@permissionRequired": {}, - "printLabel": "Print Label", + "printLabel": "Skriv ut etikett", "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "Skrivare", "@pluginPrinter": {}, "pluginSupport": "Stöd för tillägg aktiverat", "@pluginSupport": {}, @@ -682,65 +682,65 @@ "@response400": {}, "response401": "Ej autentiserad", "@response401": {}, - "response403": "Permission Denied", + "response403": "Åtkomst nekad", "@response403": {}, - "response404": "Resource Not Found", + "response404": "Resursen hittades inte", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "Metoden är inte tillåten", "@response405": {}, - "response429": "Too Many Requests", + "response429": "För många förfrågningar", "@response429": {}, - "response500": "Internal Server Error", + "response500": "Internt serverfel", "@response500": {}, - "response501": "Not Implemented", + "response501": "Ej implementerat", "@response501": {}, - "response502": "Bad Gateway", + "response502": "Felaktig Gateway", "@response502": {}, - "response503": "Service Unavailable", + "response503": "Tjänsten är inte tillgänglig", "@response503": {}, "response504": "Gateway Timeout", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "HTTP-versionen stöds inte", "@response505": {}, - "responseData": "Response data", + "responseData": "Svarsdata", "@responseData": {}, - "responseInvalid": "Invalid Response Code", + "responseInvalid": "Ogiltig svarskod", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "Okänt svar", "@responseUnknown": {}, - "result": "Result", + "result": "Resultat", "@result": { "description": "" }, - "returned": "Returned", + "returned": "Returnerad", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Försäljningsorder", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "Försäljningsordrar", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Ny försäljningsorder", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Redigera försäljningsorder", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Försäljningsorder uppdaterad", "@salesOrderUpdated": {}, "save": "Spara", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "Skanna streckkod", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scanna leverantörsartikel streckkod", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "Skanna till plats", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Skanna det här objektet till plats", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Extern skanner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Använd extern skanner för att läsa streckkoder (wedge läge)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Skanna Mottagna artiklar", "@scanReceivedParts": {}, "search": "Sök", "@search": { @@ -748,53 +748,53 @@ }, "searching": "Söker", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "Sök efter plats", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "Sök efter artiklar", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "Sök i lager", "@searchStock": {}, - "select": "Select", + "select": "Välj", "@select": {}, - "selectFile": "Select File", + "selectFile": "Välj fil", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Välj bild", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Välj en plats", "@selectLocation": {}, - "send": "Send", + "send": "Skicka", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Serienummer", "@serialNumber": {}, "serialNumbers": "Serienummer", "@serialNumbers": {}, "server": "Server", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Serveradress", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Nödvändig API-version", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Server API-version", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Autentiseringsfel", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Certifikat Fel", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Server HTTPS-certifikat är ogiltigt", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Ansluten till server", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Ansluter till server", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Kunde inte ansluta till servern", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Servernamn kan inte vara tomt", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Serverfel", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Serverdetaljer", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "Serversvar saknar obligatoriska fält", "@serverMissingData": {}, "serverOld": "Gammal server version", "@serverOld": {}, @@ -916,94 +916,94 @@ "@takePicture": {}, "targetDate": "Måldatum", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "Huvudmall Artikel", "@templatePart": {}, - "testName": "Test Name", + "testName": "Test namn", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "Test passerat eller misslyckats", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "Tester som krävs", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "Testresultat", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Visa testresultat för lagerposten", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "Lägg till testresultat", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "Inga testresultat", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "Inga tillgängliga testresultat", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "Fel vid uppladdning av testresultat", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "Testresultat uppladdat", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "Överskriden tidsgräns", "@timeout": { "description": "" }, - "tokenError": "Token Error", + "tokenError": "Token fel", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "Token saknas", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "Åtkomsttoken saknas från svar", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Totalpris", "@totalPrice": {}, - "transfer": "Transfer", + "transfer": "Överföring", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "Överföra lager", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "Flytta objekt till en annan plats", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Flytta lagerplats", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Flytta denna lagerplats till en annan", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "Översätt", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "Hjälp till att översätta appen InvenTree", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Enhetspris", "@unitPrice": {}, - "units": "Units", + "units": "Enheter", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "Okänt svar", "@unknownResponse": {}, - "upload": "Upload", + "upload": "Ladda Upp", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "Det gick inte att ladda upp filen", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "Fil har laddats upp", "@uploadSuccess": {}, - "usedIn": "Used In", + "usedIn": "Används i", "@usedIn": {}, - "usedInDetails": "Assemblies which require this part", + "usedInDetails": "Sammanställning som kräver denna artikel", "@usedInDetails": {}, "username": "Användarnamn", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "Användarnamn kan inte vara tomt", "@usernameEmpty": {}, - "value": "Value", + "value": "Värde", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "Du måste ange ett värde", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "Värde krävs", "@valueRequired": {}, - "variants": "Variants", + "variants": "Varianter", "@variants": {}, "version": "Version", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "Visa leverantörsartikel", "@viewSupplierPart": {}, - "website": "Website", + "website": "Webbplats", "@website": {} } \ No newline at end of file From 4558fff36c0da007a2f3b4ea5f037bc0e329a268 Mon Sep 17 00:00:00 2001 From: Andrew W Date: Wed, 21 Aug 2024 22:45:14 +1200 Subject: [PATCH 491/746] Move function return to right line on scan success (#521) Issue #520 --- lib/barcode/stock.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart index b9671e2..b084759 100644 --- a/lib/barcode/stock.dart +++ b/lib/barcode/stock.dart @@ -44,8 +44,8 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { if (result && OneContext.hasContext) { OneContext().pop(); - return; } + return; } } From 7b60c857fd09bf2508b65b94e7d192c0b9161fb0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 23 Aug 2024 08:10:30 +1000 Subject: [PATCH 492/746] New Crowdin updates (#522) * New translations app_en.arb (Spanish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) --- lib/l10n/es_ES/app_es_ES.arb | 8 ++++---- lib/l10n/tr_TR/app_tr_TR.arb | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 846ce3e..13371a9 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -390,11 +390,11 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación de nombre de usuario / contraseña no válida", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "", "@issue": {}, "issueDate": "Fecha de problema", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Emitir pedido", "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, @@ -496,7 +496,7 @@ "@orientationSystem": {}, "outstanding": "Outstanding", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Mostrar pedidos destacados", "@outstandingOrderDetail": {}, "overdue": "Overdue", "@overdue": {}, @@ -950,7 +950,7 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Falta el token de acceso de la respuesta", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Precio total", "@totalPrice": {}, "transfer": "Transferir", "@transfer": { diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index a5d4c3e..bc813d4 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -62,7 +62,7 @@ "@available": {}, "availableStock": "Stokta hazır", "@availableStock": {}, - "barcodes": "Barkod *", + "barcodes": "Barkodlar", "@barcodes": {}, "barcodeSettings": "Barkod Ayarları", "@barcodeSettings": {}, @@ -100,7 +100,7 @@ "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Barkod taramaları arasındaki gecikme", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Bir Iventree barkodu tara", + "barcodeScanGeneral": "Bir InvenTree barkodu tara", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Stok öğelerini konum içine tara", "@barcodeScanInItems": {}, @@ -183,7 +183,7 @@ "@customer": {}, "customers": "Müşteriler", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Müşteri Referansı", "@customerReference": {}, "damaged": "Hasarlı", "@damaged": {}, @@ -398,7 +398,7 @@ "@issueOrder": {}, "itemInLocation": "Parça zaten konumda", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Öge kaldırıldı", "@itemDeleted": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, @@ -450,7 +450,7 @@ "@link": {}, "lost": "Kayıp", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Üretici Parça Numarası", "@manufacturerPartNumber": {}, "manufacturer": "Üretici", "@manufacturer": {}, @@ -500,7 +500,7 @@ "@outstandingOrderDetail": {}, "overdue": "Overdue", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Gecikmiş siparişleri göster", "@overdueDetail": {}, "packaging": "Paketleme", "@packaging": {}, @@ -718,7 +718,7 @@ "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Yeni Satış Siparişi", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", "@salesOrderEdit": {}, @@ -738,7 +738,7 @@ "@scanIntoLocationDetail": {}, "scannerExternal": "External Scanner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Barkodları okumak için harici tarayıcı kullan (keyboard wedge modu)", "@scannerExternalDetail": {}, "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, From 922243918676b3c052719108927aca22ce6f869f Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 23 Aug 2024 08:13:22 +1000 Subject: [PATCH 493/746] Update release notes (#523) --- assets/release_notes.md | 2 ++ pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 44cd352..5fced5e 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,8 @@ - Support "ON_HOLD" status for Purchase Orders - Support "ON_HOLD" status for Sales Orders - Change base icon package from FontAwesome to TablerIcons +- Bug fixes for barcode scanning +- Translation updates ### 0.16.1 - July 2024 --- diff --git a/pubspec.yaml b/pubspec.yaml index 5e2e3b7..75aebf6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.2+87 +version: 0.16.2+88 environment: sdk: ">=2.19.5 <3.13.0" From 82aace9cc4af9103e66f3fdefeed6e398c6f2c46 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 25 Aug 2024 12:08:56 +1000 Subject: [PATCH 494/746] New Crowdin updates (#526) * New translations app_en.arb (Arabic) * New translations app_en.arb (Indonesian) --- lib/l10n/ar_SA/app_ar_SA.arb | 8 ++++---- lib/l10n/id_ID/app_id_ID.arb | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 2f370ff..67193c5 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -1,6 +1,6 @@ { "@@locale": "ar", - "appTitle": "InvenTree", + "appTitle": "", "@appTitle": { "description": "InvenTree application title string" }, @@ -78,7 +78,7 @@ "@barcodeInUse": {}, "barcodeMissingHash": "Barcode hash data missing from response", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "", "@barcodeNoMatch": {}, "barcodeNotAssigned": "Barcode not assigned", "@barcodeNotAssigned": {}, @@ -110,7 +110,7 @@ "@barcodeScanSingle": {}, "barcodeScanSingleDetail": "Pause barcode scanner after each scan", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "تم فحصها في الموقع", "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Item not scanned in", "@barcodeScanIntoLocationFailure": {}, @@ -227,7 +227,7 @@ "@editNotes": {}, "editParameter": "Edit Parameter", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "تعديل المنتج", "@editPart": { "description": "edit part" }, diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 6be7331..2b88272 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -104,7 +104,7 @@ "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scan stock items into this location", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "", "@barcodeScanLocation": {}, "barcodeScanSingle": "Single Scan Mode", "@barcodeScanSingle": {}, @@ -154,7 +154,7 @@ "@categoryUpdated": {}, "company": "Company", "@company": {}, - "companyEdit": "Edit Company", + "companyEdit": "Rubah Perusahaan", "@companyEdit": {}, "companyNoResults": "No companies matching query", "@companyNoResults": {}, @@ -201,7 +201,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, - "description": "Description", + "description": "Deskripsi", "@description": {}, "destroyed": "Destroyed", "@destroyed": {}, From c52885fc6b02fa6110668da9f31a871309cb7bb4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 25 Aug 2024 12:14:57 +1000 Subject: [PATCH 495/746] Attachments fix (#528) * Bump version * Fix for viewing and uploading attachment files - Make sure we use the correct attribute! --- assets/release_notes.md | 7 +++++++ lib/inventree/model.dart | 14 +++++++++++++- lib/widget/attachment_widget.dart | 11 ++++++----- pubspec.yaml | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 5fced5e..bc02280 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,10 @@ +### 0.16.3 - August 2024 +--- + +- Fixes bug relating to viewing attachment files +- Fixes bug relating to uploading attachment files + + ### 0.16.2 - August 2024 --- diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 0ad4c17..2ee6256 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -1001,11 +1001,23 @@ class InvenTreeAttachment extends InvenTreeModel { String url = URL; if (InvenTreeAPI().supportsModernAttachments) { - // All attachments are stored in a consolidated table + + if (modelType.isEmpty) { + sentryReportMessage("uploadAttachment called with empty 'modelType'"); + return false; + } + url = "attachment/"; data["model_id"] = modelId.toString(); data["model_type"] = modelType; + } else { + + if (REFERENCE_FIELD.isEmpty) { + sentryReportMessage("uploadAttachment called with empty 'REFERENCE_FIELD'"); + return false; + } + data[REFERENCE_FIELD] = modelId.toString(); } diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 78d4dad..bc700f4 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -76,7 +76,11 @@ class _AttachmentWidgetState extends RefreshableState { showLoadingOverlay(context); - final bool result = await widget.attachmentClass.uploadAttachment(file, widget.attachmentClass.MODEL_TYPE, widget.modelId); + final bool result = await widget.attachmentClass.uploadAttachment( + file, + widget.attachmentClass.REF_MODEL_TYPE, + widget.modelId + ); hideLoadingOverlay(); @@ -137,7 +141,7 @@ class _AttachmentWidgetState extends RefreshableState { Map filters = {}; if (InvenTreeAPI().supportsModernAttachments) { - filters["model_type"] = widget.attachmentClass.MODEL_TYPE; + filters["model_type"] = widget.attachmentClass.REF_MODEL_TYPE; filters["model_id"] = widget.modelId.toString(); } else { filters[widget.attachmentClass.REFERENCE_FIELD] = widget.modelId.toString(); @@ -148,10 +152,7 @@ class _AttachmentWidgetState extends RefreshableState { ).then((var results) { attachments.clear(); - print("Found ${results.length} results:"); - for (var result in results) { - print(result.toString()); if (result is InvenTreeAttachment) { attachments.add(result); } diff --git a/pubspec.yaml b/pubspec.yaml index 75aebf6..a00d686 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.2+88 +version: 0.16.3+89 environment: sdk: ">=2.19.5 <3.13.0" From 23f27af4e60aa2f6b9c1a0ecaea56fb4a62a1781 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Sep 2024 09:35:03 +1000 Subject: [PATCH 496/746] Update CI workflow (#532) --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ada4375..889cad0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -59,8 +59,8 @@ jobs: cd inventree_server invoke install invoke migrate - invoke import-fixtures - invoke server -a 127.0.0.1:8000 & + invoke dev.import-fixtures + invoke dev.server -a 127.0.0.1:8000 & invoke wait sleep 30 - name: Unit Tests From 51ae10af7fd017157ca25a34e4155a2b501889ab Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Sep 2024 09:52:56 +1000 Subject: [PATCH 497/746] New Crowdin updates (#529) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Turkish) * New translations app_en.arb (Dutch) * New translations app_en.arb (Spanish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Italian) * New translations app_en.arb (Italian) --- lib/l10n/es_ES/app_es_ES.arb | 134 ++++++++++++++-------------- lib/l10n/id_ID/app_id_ID.arb | 168 +++++++++++++++++------------------ lib/l10n/it_IT/app_it_IT.arb | 32 +++---- lib/l10n/nl_NL/app_nl_NL.arb | 86 +++++++++--------- lib/l10n/tr_TR/app_tr_TR.arb | 128 +++++++++++++------------- 5 files changed, 274 insertions(+), 274 deletions(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 13371a9..8658316 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -82,23 +82,23 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Código de barras no asignado", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Escanear código de barras de parte", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Escanear código de barras para recibir parte", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Escaneo de código de barras en pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Toque o mantenga pulsado para pausar el escaneo", "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Entrada de escáner", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Seleccionar fuente de entrada del escáner de código de barras", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Retraso de escaneo de código de barras", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Retraso entre escaneos de código de barras", "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Escanear un código de barras de InvenTree", "@barcodeScanGeneral": {}, @@ -106,9 +106,9 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear a la ubicación de Inventario", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Modo de escaneo único", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Pausar el escáner de código de barras después de cada escaneado", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", "@barcodeScanIntoLocationSuccess": {}, @@ -134,15 +134,15 @@ "@build": {}, "building": "Construyendo", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Cámara interna", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Cancelar orden", "@cancelOrder": {}, "category": "Categoria", "@category": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Configure las opciones de su servidor", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmar transferencia", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Confirmar detalles de transferencia de stock al escanear códigos de barras", "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Contar", @@ -179,11 +179,11 @@ }, "credits": "Créditos", "@credits": {}, - "customer": "Customer", + "customer": "Cliente", "@customer": {}, "customers": "Clientes", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Referencia del Cliente", "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, @@ -225,7 +225,7 @@ "@editLocation": {}, "editNotes": "Editar notas", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Editar Parámetro", "@editParameter": {}, "editPart": "Editar Pieza", "@editPart": { @@ -233,7 +233,7 @@ }, "editItem": "Editar artículo de stock", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Editar Ítem de Línea", "@editLineItem": {}, "enterPassword": "Introduzca contraseña", "@enterPassword": {}, @@ -251,9 +251,9 @@ "@errorDetails": {}, "errorFetch": "Error obteniendo datos del servidor", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Error solicitando roles de usuario desde el servidor", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Error al solicitar datos del plugin desde el servidor", "@errorPluginInfo": {}, "errorReporting": "Reporte de errores", "@errorReporting": {}, @@ -279,9 +279,9 @@ "@filterComponent": {}, "filterComponentDetail": "Mostrar piezas del componente", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Externo", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Mostrar stock en ubicaciones externas", "@filterExternalDetail": {}, "filterInStock": "En Existencia", "@filterInStock": {}, @@ -324,9 +324,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Mostrar Órdenes de Venta", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Mostrar botón de órdenes de ventas en la pantalla de inicio", "@homeShowSoDescription": {}, "homeShowSubscribed": "Piezas Destacadas", "@homeShowSubscribed": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inactivo", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Esta empresa está marcada como inactiva", "@inactiveCompany": {}, "inactiveDetail": "Esta pieza está marcada como inactiva", "@inactiveDetail": {}, @@ -372,7 +372,7 @@ "@inProduction": {}, "inProductionDetail": "El artículo de inventario está en producción", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Pieza Interna", "@internalPart": {}, "invalidHost": "Nombre de host no válido", "@invalidHost": {}, @@ -386,7 +386,7 @@ "@invalidStockLocation": {}, "invalidStockItem": "Artículo de stock inválido", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Parte de proveedor no válida", "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación de nombre de usuario / contraseña no válida", "@invalidUsernamePassword": {}, @@ -398,13 +398,13 @@ "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "El artículo ha sido eliminado", "@itemDeleted": {}, "keywords": "Palabras claves", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Impresión de etiquetas", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Habilitar impresión de etiquetas", "@labelPrintingDetail": {}, "labelTemplate": "Plantilla de etiqueta", "@labelTemplate": {}, @@ -420,13 +420,13 @@ "@lastUpdated": {}, "level": "Nivel", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Agregar Línea de Pedido", "@lineItemAdd": {}, "lineItem": "Artículo del pedido", "@lineItem": {}, "lineItems": "Ítems de línea", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Línea de Pedido Actualizada", "@lineItemUpdated": {}, "locateItem": "Localizar artículo de stock", "@locateItem": {}, @@ -442,15 +442,15 @@ "@locationUpdated": {}, "login": "Iniciar sesión", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Introduzca los datos de inicio de sesión", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Nombre de usuario y contraseña no se almacenan localmente", "@loginEnterDetails": {}, "link": "Enlace", "@link": {}, "lost": "Perdido", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Número de pieza del fabricante", "@manufacturerPartNumber": {}, "manufacturer": "Fabricante", "@manufacturer": {}, @@ -484,23 +484,23 @@ "@onOrder": {}, "onOrderDetails": "Artículos actualmente en pedido", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Orientación de la pantalla", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Orientación de la pantalla (requiere reiniciar)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Orientación Horizontal", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Vertical", "@orientationPortrait": {}, "orientationSystem": "Sistema", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Pendiente", "@outstanding": {}, "outstandingOrderDetail": "Mostrar pedidos destacados", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Vencido", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Mostrar pedidos vencidos", "@overdueDetail": {}, "packaging": "Empaquetado", "@packaging": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Parte no marcada como vendible", "@partNotSalable": {}, "partsNone": "Sin piezas", "@partsNone": {}, @@ -590,7 +590,7 @@ "@profileEdit": {}, "profileDelete": "Borrar perfil del servidor", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Cerrar sesión", "@profileLogout": {}, "profileName": "Nombre de Perfil", "@profileName": {}, @@ -604,11 +604,11 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Toca para crear o seleccionar un perfil", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Código del proyecto", "@projectCode": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Nueva orden de compra", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, @@ -636,7 +636,7 @@ "@queryNoResults": {}, "received": "Recibido", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Mostrar artículos recibidos", "@receivedFilterDetail": {}, "receiveItem": "Artículo recibido", "@receiveItem": {}, @@ -714,15 +714,15 @@ }, "returned": "Devuelto", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Orden de venta", "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Nueva orden de venta", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Editar orden de venta", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Orden de venta actualizada", "@salesOrderUpdated": {}, "save": "Guardar", "@save": { @@ -730,17 +730,17 @@ }, "scanBarcode": "Escanear código de barras", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Escanear código de barras del proveedor", "@scanSupplierPart": {}, "scanIntoLocation": "Escanear en la ubicación", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Escanear este item en la ubicación", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Escáner externo", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Usar escáner externo para leer códigos de barras (modo cuña)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Escanear partes recibidas", "@scanReceivedParts": {}, "search": "Buscar", "@search": { @@ -766,7 +766,7 @@ "@send": {}, "serialNumber": "Número de serie", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Números de serie", "@serialNumbers": {}, "server": "Servidor", "@server": {}, @@ -810,11 +810,11 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Envíos", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Añadir envío", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Enviado", "@shipped": {}, "sku": "SKU", "@sku": {}, @@ -898,15 +898,15 @@ "@suppliedParts": {}, "supplier": "Proveedor", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Pieza del proveedor", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Editar Pieza del Proveedor", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Número de pieza del proveedor", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Pieza del proveedor actualizada", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Piezas del Proveedor", "@supplierParts": {}, "suppliers": "Proveedores", "@suppliers": {}, @@ -928,7 +928,7 @@ "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Mostrar los resultados de prueba de artículos de stock", "@testResultsDetail": {}, "testResultAdd": "Añadir Resultado de Prueba", "@testResultAdd": {}, @@ -970,7 +970,7 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Precio Unitario", "@unitPrice": {}, "units": "Unidades", "@units": {}, diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 2b88272..e1bc338 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -8,31 +8,31 @@ "@ok": { "description": "OK" }, - "about": "About", + "about": "Tentang", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "Rincian Akun", "@accountDetails": {}, - "actions": "Actions", + "actions": "Tindakan", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "Tidak ada aksi yang tersedia", "@actionsNone": {}, - "add": "Add", + "add": "Tambah", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "Tambah Stok", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "Alamat", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "Tentang InvenTree", "@appAbout": {}, "appCredits": "Additional app credits", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "Rincian Aplikasi", "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, @@ -40,13 +40,13 @@ "@allocateStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "Pengaturan Aplikasi", "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, "attachments": "Attachments", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "Melampirkan Gambar", "@attachImage": { "description": "Attach an image" }, @@ -56,11 +56,11 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "Select attachment", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "Perhatian", "@attention": {}, - "available": "Available", + "available": "Tersedia", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "Stok Tersedia", "@availableStock": {}, "barcodes": "Barcodes", "@barcodes": {}, @@ -134,25 +134,25 @@ "@build": {}, "building": "Building", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Kamera Internal", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "Batalkan", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Batalkan Pesanan", "@cancelOrder": {}, - "category": "Category", + "category": "Kategori", "@category": {}, - "categoryCreate": "New Category", + "categoryCreate": "Kategori Baru", "@categoryCreate": {}, "categoryCreateDetail": "Create new part category", "@categoryCreateDetail": {}, "categoryUpdated": "Part category updated", "@categoryUpdated": {}, - "company": "Company", + "company": "Perusahaan", "@company": {}, "companyEdit": "Rubah Perusahaan", "@companyEdit": {}, @@ -160,11 +160,11 @@ "@companyNoResults": {}, "companyUpdated": "Company details updated", "@companyUpdated": {}, - "companies": "Companies", + "companies": "Perusahaan", "@companies": {}, "configureServer": "Configure server settings", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Konfirmasi Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", "connectionRefused": "Connection Refused", @@ -179,9 +179,9 @@ }, "credits": "Credits", "@credits": {}, - "customer": "Customer", + "customer": "Pelanggan", "@customer": {}, - "customers": "Customers", + "customers": "Pelanggan", "@customers": {}, "customerReference": "Customer Reference", "@customerReference": {}, @@ -191,7 +191,7 @@ "@darkMode": {}, "darkModeEnable": "Enable dark mode", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "Hapus", "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, @@ -205,25 +205,25 @@ "@description": {}, "destroyed": "Destroyed", "@destroyed": {}, - "details": "Details", + "details": "Detail", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "Dokumentasi", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "Mengunduh File", "@downloading": {}, - "downloadError": "Download Error", + "downloadError": "Unduh Mengalami Galat", "@downloadError": {}, - "edit": "Edit", + "edit": "Sunting", "@edit": { "description": "edit" }, - "editCategory": "Edit Category", + "editCategory": "Sunting Kategori", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "Ubah Lokasi", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "Ubah Catatan", "@editNotes": {}, "editParameter": "Edit Parameter", "@editParameter": {}, @@ -235,11 +235,11 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, - "enterPassword": "Enter password", + "enterPassword": "Masukkan Kata Sandi", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "Masukkan Nama Pengguna", "@enterUsername": {}, - "error": "Error", + "error": "Galat", "@error": { "description": "Error" }, @@ -261,13 +261,13 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, - "feedback": "Feedback", + "feedback": "Umpan Balik", "@feedback": {}, "feedbackError": "Error submitting feedback", "@feedbackError": {}, "feedbackSuccess": "Feedback submitted", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Aktif", "@filterActive": {}, "filterActiveDetail": "Show active parts", "@filterActiveDetail": {}, @@ -275,7 +275,7 @@ "@filterAssembly": {}, "filterAssemblyDetail": "Show assembled parts", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Komponen", "@filterComponent": {}, "filterComponentDetail": "Show component parts", "@filterComponentDetail": {}, @@ -311,11 +311,11 @@ "@formatExceptionJson": {}, "formError": "Form Error", "@formError": {}, - "history": "History", + "history": "Riwayat", "@history": { "description": "history" }, - "home": "Home", + "home": "Beranda", "@homeScreen": {}, "homeScreen": "Home Screen", "homeScreenSettings": "Configure home screen settings", @@ -328,7 +328,7 @@ "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Penjelasan Suku Cadang", "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, @@ -340,7 +340,7 @@ "@homeShowManufacturers": {}, "homeShowManufacturersDescription": "Show manufacturers button on home screen", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Tunjukkan Pelanggan", "@homeShowCustomers": {}, "homeShowCustomersDescription": "Show customers button on home screen", "@homeShowCustomersDescription": {}, @@ -348,7 +348,7 @@ "@imageUploadFailure": {}, "imageUploadSuccess": "Gambar telah diunggah", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Tidak Aktif", "@inactive": {}, "inactiveCompany": "This company is marked as inactive", "@inactiveCompany": {}, @@ -366,7 +366,7 @@ "@incompleteDetails": {}, "internalPartNumber": "Internal Part Number", "@internalPartNumber": {}, - "info": "Info", + "info": "Informasi", "@info": {}, "inProduction": "In Production", "@inProduction": {}, @@ -400,7 +400,7 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, - "keywords": "Keywords", + "keywords": "Kata Kunci", "@keywords": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, @@ -408,11 +408,11 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, - "language": "Language", + "language": "Bahasa", "@language": {}, "languageDefault": "Default system language", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Pilih Bahasa", "@languageSelect": {}, "lastStocktake": "Last Stocktake", "@lastStocktake": {}, @@ -432,7 +432,7 @@ "@locateItem": {}, "locateLocation": "Locate stock location", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Lokasi Baru", "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, @@ -446,7 +446,7 @@ "@loginEnter": {}, "loginEnterDetails": "Username and password are not stored locally", "@loginEnterDetails": {}, - "link": "Link", + "link": "Pranala", "@link": {}, "lost": "Lost", "@lost": {}, @@ -458,27 +458,27 @@ "@manufacturers": {}, "missingData": "Missing Data", "@missingData": {}, - "name": "Name", + "name": "Nama", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "Tidak Tersambung", "@notConnected": {}, - "notes": "Notes", + "notes": "Catatan", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Notifikasi", "@notifications": {}, "notificationsEmpty": "No unread notifications", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Tidak ada respon dari server", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Tidak ada hasil", "@noResults": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Nomor tidak valid", "@numberInvalid": {}, "onOrder": "On Order", "@onOrder": {}, @@ -492,7 +492,7 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Sistem", "@orientationSystem": {}, "outstanding": "Outstanding", "@outstanding": {}, @@ -514,7 +514,7 @@ "@parent": {}, "parentCategory": "Parent Category", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "Lokasi Orang Tua", "@parentLocation": {}, "part": "Part", "@part": { @@ -558,7 +558,7 @@ "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "Kata Sandi", "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, @@ -570,7 +570,7 @@ "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "Mesin Cetak", "@pluginPrinter": {}, "pluginSupport": "Plugin Support Enabled", "@pluginSupport": {}, @@ -592,7 +592,7 @@ "@profileDelete": {}, "profileLogout": "Logout Profile", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "Profil Nama", "@profileName": {}, "profileNone": "No profiles available", "@profileNone": {}, @@ -618,7 +618,7 @@ "@purchaseOrderUpdated": {}, "purchasePrice": "Purchase Price", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Jumlah", "@quantity": { "description": "Quantity" }, @@ -634,7 +634,7 @@ "@queryEmpty": {}, "queryNoResults": "No results for query", "@queryNoResults": {}, - "received": "Received", + "received": "Telah diterima", "@received": {}, "receivedFilterDetail": "Show received items", "@receivedFilterDetail": {}, @@ -648,7 +648,7 @@ "@refresh": {}, "refreshing": "Refreshing", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Ditolak", "@rejected": {}, "releaseNotes": "Release Notes", "@releaseNotes": {}, @@ -664,9 +664,9 @@ "@reportBug": {}, "reportBugDescription": "Submit bug report (requires GitHub account)", "@reportBugDescription": {}, - "results": "Results", + "results": "Hasil", "@results": {}, - "request": "Request", + "request": "Permintaan", "@request": {}, "requestFailed": "Request Failed", "@requestFailed": {}, @@ -708,7 +708,7 @@ "@responseInvalid": {}, "responseUnknown": "Unknown Response", "@responseUnknown": {}, - "result": "Result", + "result": "Hasil", "@result": { "description": "" }, @@ -742,11 +742,11 @@ "@scannerExternalDetail": {}, "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, - "search": "Search", + "search": "Cari", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Mencari", "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, @@ -754,15 +754,15 @@ "@searchParts": {}, "searchStock": "Search Stock", "@searchStock": {}, - "select": "Select", + "select": "Pilih", "@select": {}, - "selectFile": "Select File", + "selectFile": "Pilih Berkas", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Pilih Gambar", "@selectImage": {}, "selectLocation": "Select a location", "@selectLocation": {}, - "send": "Send", + "send": "Kirim", "@send": {}, "serialNumber": "Serial Number", "@serialNumber": {}, @@ -802,7 +802,7 @@ "@serverSettings": {}, "serverStart": "Server must start with http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Pengaturan", "@settings": {}, "serverInstance": "Server Instance", "@serverInstance": {}, @@ -826,9 +826,9 @@ "@soundOnServerError": {}, "status": "Status", "@status": {}, - "statusCode": "Status Code", + "statusCode": "Kode Status", "@statusCode": {}, - "stock": "Stock", + "stock": "Persediaan", "@stock": { "description": "stock" }, @@ -840,7 +840,7 @@ }, "stockItems": "Stock Items", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "Unit Persediaan Baru", "@stockItemCreate": {}, "stockItemCreateDetail": "Create new stock item in this location", "@stockItemCreateDetail": {}, @@ -912,7 +912,7 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, - "takePicture": "Take Picture", + "takePicture": "Ambil Gambar", "@takePicture": {}, "targetDate": "Target Date", "@targetDate": {}, @@ -940,7 +940,7 @@ "@testResultUploadFail": {}, "testResultUploadPass": "Hasil tes telah diunggah", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "Waktu Habis", "@timeout": { "description": "" }, @@ -950,7 +950,7 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Access token missing from response", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Total Harga", "@totalPrice": {}, "transfer": "Transfer", "@transfer": { @@ -966,7 +966,7 @@ "@transferStockLocation": {}, "transferStockLocationDetail": "Transfer this stock location into another", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "Terjemahkan", "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, @@ -976,7 +976,7 @@ "@units": {}, "unknownResponse": "Unknown Response", "@unknownResponse": {}, - "upload": "Upload", + "upload": "Unggah", "@upload": {}, "uploadFailed": "File upload failed", "@uploadFailed": {}, @@ -1000,7 +1000,7 @@ "@valueRequired": {}, "variants": "Variants", "@variants": {}, - "version": "Version", + "version": "Versi", "@version": {}, "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index ce96d7e..9b85ec7 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -84,7 +84,7 @@ "@barcodeNotAssigned": {}, "barcodeScanPart": "Scansiona codice a barre del prodotto", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Scansione codice a barre per ricevere la parte", "@barcodeReceivePart": {}, "barcodeScanPaused": "Scansione codice a barre in pausa", "@barodeScanPaused": {}, @@ -94,11 +94,11 @@ "@barcodeScanAssign": {}, "barcodeScanController": "Input scanner", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Seleziona sorgente d'ingresso scanner per codici a barre", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Ritardo scansione codice a barre", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Ritardo tra scansioni di codici a barre", "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Scansiona un codice a barre InvenTree", "@barcodeScanGeneral": {}, @@ -106,9 +106,9 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Scansiona Ubicazione magazzino", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Modalità scansione singola", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Sospendi scanner di codici a barre dopo ogni scansione", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Scansionato nell'ubicazione", "@barcodeScanIntoLocationSuccess": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Scansiona codice a barre", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scansiona codice a barre del fornitore", "@scanSupplierPart": {}, "scanIntoLocation": "Scansiona nell'ubicazione", "@scanIntoLocation": {}, @@ -766,7 +766,7 @@ "@send": {}, "serialNumber": "Numero seriale", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Numeri di serie", "@serialNumbers": {}, "server": "Server", "@server": {}, @@ -810,13 +810,13 @@ "@serverNotConnected": {}, "serverNotSelected": "Server non selezionato", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Spedizioni", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Aggiungi Spedizione", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Spedito", "@shipped": {}, - "sku": "SKU", + "sku": "Codice articolo", "@sku": {}, "sounds": "Audio", "@sounds": {}, @@ -902,7 +902,7 @@ "@supplierPart": {}, "supplierPartEdit": "Modifica Fornitore Articolo", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Codice articolo fornitore", "@supplierPartNumber": {}, "supplierPartUpdated": "Articolo Fornitore Aggiornato", "@supplierPartUpdated": {}, @@ -928,7 +928,7 @@ "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Visualizzazione dei risultati dei test sugli articoli in magazzino", "@testResultsDetail": {}, "testResultAdd": "Aggiungi Risultato Test", "@testResultAdd": {}, @@ -950,7 +950,7 @@ "@tokenMissing": {}, "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Prezzo Totale", "@totalPrice": {}, "transfer": "Trasferisci", "@transfer": { @@ -970,7 +970,7 @@ "@translate": {}, "translateHelp": "Aiuta a tradurre l'app InvenTree", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Prezzo Unitario", "@unitPrice": {}, "units": "Unità", "@units": {}, diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index b842802..d077b62 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "App details", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Toegewezen", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Voorraad Toewijzen", "@allocateStock": {}, "appReleaseNotes": "App release notities weergeven", "@appReleaseNotes": {}, @@ -82,19 +82,19 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Streepjescode niet toegewezen", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Scan barcode van onderdeel", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Scan streepjescode om deel te ontvangen", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Barcode scannen gepauzeerd", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tik of houd om scannen te pauzeren", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, "barcodeScanController": "Scanner Input", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Selecteer de invoerbron voor barcodescanner", "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barcode Scan vertraging", "@barcodeScanDelay": {}, @@ -106,9 +106,9 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Scan voorraadlocatie", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Enkele scan modus", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Pauzeer de barcodescanner na elke scan", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Gescand naar locatie", "@barcodeScanIntoLocationSuccess": {}, @@ -134,9 +134,9 @@ "@build": {}, "building": "Produceren", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Interne Camera", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Gebruik interne camera om barcodes te lezen", "@cameraInternalDetail": {}, "cancel": "Annuleer", "@cancel": { @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Configureer server instellingen", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Bevestig Overdracht", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Bevestig voorraadoverdrachtsgegevens bij het scannen van streepjescodes", "connectionRefused": "Verbinding geweigerd", "@connectionRefused": {}, "count": "Tellen", @@ -179,11 +179,11 @@ }, "credits": "Credits", "@credits": {}, - "customer": "Customer", + "customer": "Klant", "@customer": {}, "customers": "Klanten", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Klant referentie", "@customerReference": {}, "damaged": "Beschadigd", "@damaged": {}, @@ -253,7 +253,7 @@ "@errorFetch": {}, "errorUserRoles": "Fout bij het aanvragen van de gebruikersrollen op de server", "@errorUserRoles": {}, - "errorPluginInfo": "Fout bij het aanvragen van plugin gegevens van de server", + "errorPluginInfo": "Fout bij het aanvragen van plug-in gegevens van de server", "@errorPluginInfo": {}, "errorReporting": "Fout bij Rapportage", "@errorReporting": {}, @@ -287,7 +287,7 @@ "@filterInStock": {}, "filterInStockDetail": "Toon onderdelen op voorraad", "@filterInStockDetail": {}, - "filterSerialized": "Geserialiseerd", + "filterSerialized": "Geserialiseerde producten", "@filterSerialized": {}, "filterSerializedDetail": "Toon geserialiseerde voorraad items", "@filterSerializedDetail": {}, @@ -324,9 +324,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Toon Verkooporders", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Toon verkooporder knop op startscherm", "@homeShowSoDescription": {}, "homeShowSubscribed": "Geabonneerde Onderdelen", "@homeShowSubscribed": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Inactief", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Dit bedrijf is gemarkeerd als inactief", "@inactiveCompany": {}, "inactiveDetail": "Dit onderdeel is gemarkeerd als inactief", "@inactiveDetail": {}, @@ -398,7 +398,7 @@ "@issueOrder": {}, "itemInLocation": "Artikel al op locatie", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Item is verwijderd", "@itemDeleted": {}, "keywords": "Trefwoorden", "@keywords": {}, @@ -420,7 +420,7 @@ "@lastUpdated": {}, "level": "Niveau", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Regel item toevoegen", "@lineItemAdd": {}, "lineItem": "Regelartikel", "@lineItem": {}, @@ -440,11 +440,11 @@ "@locationNotSet": {}, "locationUpdated": "Voorraadlocatie bijgewerkt", "@locationUpdated": {}, - "login": "Login", + "login": "Inloggen", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Inloggegevens invoeren", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Gebruikersnaam en wachtwoord worden niet lokaal opgeslagen", "@loginEnterDetails": {}, "link": "Link", "@link": {}, @@ -496,11 +496,11 @@ "@orientationSystem": {}, "outstanding": "Openstaand", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Toon openstaande bestellingen", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Achterstallig", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Toon achterstallige bestellingen", "@overdueDetail": {}, "packaging": "Verpakkingen", "@packaging": {}, @@ -508,7 +508,7 @@ "@packageName": {}, "parameters": "Parameters", "@parameters": {}, - "parametersSettingDetail": "Onderdeelparameters weergeven", + "parametersSettingDetail": "Onderdeel parameters weergeven", "@parametersSettingDetail": {}, "parent": "Bovenliggend", "@parent": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Onderdeel niet gemarkeerd als verkoopbaar", "@partNotSalable": {}, "partsNone": "Geen onderdelen", "@partsNone": {}, @@ -590,7 +590,7 @@ "@profileEdit": {}, "profileDelete": "Serverprofiel Verwijderen", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Profiel uitloggen", "@profileLogout": {}, "profileName": "Profielnaam", "@profileName": {}, @@ -714,15 +714,15 @@ }, "returned": "Teruggestuurd", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Verkooporder", "@salesOrder": {}, "salesOrders": "Verkooporders", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Nieuwe verkooporder", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Verkooporder bewerken", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Verkooporder bijgewerkt", "@salesOrderUpdated": {}, "save": "Bewaren", "@save": { @@ -730,17 +730,17 @@ }, "scanBarcode": "Streepjescode Scannen", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scan barcode leveranciersdeel", "@scanSupplierPart": {}, "scanIntoLocation": "Scan Naar Locatie", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scan dit item naar een locatie", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Externe scanner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Gebruik externe scanner om barcodes te lezen (wig modus)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Scan ontvangen onderdelen", "@scanReceivedParts": {}, "search": "Zoeken", "@search": { @@ -810,11 +810,11 @@ "@serverNotConnected": {}, "serverNotSelected": "Server niet geselecteerd", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Verzendingen", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Verzending toevoegen", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Verzonden", "@shipped": {}, "sku": "Artikelnummer", "@sku": {}, @@ -948,7 +948,7 @@ "@tokenError": {}, "tokenMissing": "Ontbrekende Token", "@tokenMissing": {}, - "tokenMissingFromResponse": "Toegangstoken ontbreekt in antwoord", + "tokenMissingFromResponse": "Toegang token ontbreekt in antwoord", "@tokenMissingFromResponse": {}, "totalPrice": "Totaalprijs", "@totalPrice": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index bc813d4..f3e1904 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -30,15 +30,15 @@ "@address": {}, "appAbout": "InvenTree Hakkında", "@appAbout": {}, - "appCredits": "Uygulama kredisi ekle", + "appCredits": "Ek uygulama kredileri", "@appCredits": {}, - "appDetails": "Uygulama Detayları", + "appDetails": "Uygulama Ayrıntıları", "@appDetails": {}, "allocated": "Tahsis edildi", "@allocated": {}, "allocateStock": "Tahsisli stok", "@allocateStock": {}, - "appReleaseNotes": "Uygulama yayınlama notları", + "appReleaseNotes": "Uygulama yayınlama notlarını göster", "@appReleaseNotes": {}, "appSettings": "Uygulama Ayarları", "@appSettings": {}, @@ -92,7 +92,7 @@ "@barcodeScanPause": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Tarayıcı Girişi", "@barcodeScanController": {}, "barcodeScanControllerDetail": "Barkod tarayıcı girdi kaynağını seç", "@barcodeScanControllerDetail": {}, @@ -102,13 +102,13 @@ "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Bir InvenTree barkodu tara", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Stok öğelerini konum içine tara", + "barcodeScanInItems": "Stok ögelerini bu konum içine tara", "@barcodeScanInItems": {}, "barcodeScanLocation": "Stok konumu tara", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Tekli Tarama modu", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Her tarama sonrasında barkod tarayıcıyı duraklat", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Konuma tarandı", "@barcodeScanIntoLocationSuccess": {}, @@ -128,15 +128,15 @@ "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Malzeme Lisitesini Görüntüle", + "bomEnable": "Malzeme Listesini Görüntüle", "@bomEnable": {}, "build": "Oluştur", "@build": {}, "building": "Oluşturma", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Dahili Kamera", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Barkodları okumak için dahili kamera kullan", "@cameraInternalDetail": {}, "cancel": "İptal", "@cancel": { @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Sunucu ayarlarınızı yapılandırın", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Aktarımı Onayla", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Barkodları tararken stok aktarım ayrıntılarını onayla", "connectionRefused": "Bağlantı reddedildi", "@connectionRefused": {}, "count": "Sayım", @@ -179,7 +179,7 @@ }, "credits": "Katkıda Bulunanlar", "@credits": {}, - "customer": "Customer", + "customer": "Müşteri", "@customer": {}, "customers": "Müşteriler", "@customers": {}, @@ -187,9 +187,9 @@ "@customerReference": {}, "damaged": "Hasarlı", "@damaged": {}, - "darkMode": "Koyu Mod", + "darkMode": "Koyu Tema", "@darkMode": {}, - "darkModeEnable": "Karanlık modu etkinleştir", + "darkModeEnable": "Koyu temayı etkinleştir", "@darkModeEnable": {}, "delete": "Sil", "@delete": {}, @@ -233,7 +233,7 @@ }, "editItem": "Parçayı Düzenle", "@editItem": {}, - "editLineItem": "Satır Öğesini Düzenle", + "editLineItem": "Satır Ögesini Düzenle", "@editLineItem": {}, "enterPassword": "Şifrenizi girin", "@enterPassword": {}, @@ -269,7 +269,7 @@ "@feedbackSuccess": {}, "filterActive": "Aktif", "@filterActive": {}, - "filterActiveDetail": "Aktif öğeleri göster", + "filterActiveDetail": "Aktif parçaları göster", "@filterActiveDetail": {}, "filterAssembly": "Birleştirilmiş", "@filterAssembly": {}, @@ -281,11 +281,11 @@ "@filterComponentDetail": {}, "filterExternal": "Harici", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Stoku harici konumlarda göster", "@filterExternalDetail": {}, "filterInStock": "Stokta mevcut", "@filterInStock": {}, - "filterInStockDetail": "Stoğu olan parçaları göster", + "filterInStockDetail": "Stoku olan parçaları göster", "@filterInStockDetail": {}, "filterSerialized": "Sıralandırılmış", "@filterSerialized": {}, @@ -293,15 +293,15 @@ "@filterSerializedDetail": {}, "filterTemplate": "Şablon", "@filterTemplate": {}, - "filterTemplateDetail": "Şablonlar öğelerini göster", + "filterTemplateDetail": "Şablon parçaları göster", "@filterTemplateDetail": {}, "filterTrackable": "Takip edilebilir", "@filterTrackable": {}, - "filterTrackableDetail": "Takip edilebilir öğeleri göster", + "filterTrackableDetail": "Takip edilebilir parçaları göster", "@filterTrackableDetail": {}, "filterVirtual": "Sanal", "@filterVirtual": {}, - "filterVirtualDetail": "Sanal öğeleri göster", + "filterVirtualDetail": "Sanal parçaları göster", "@filterVirtualDetail": {}, "filteringOptions": "Süzgeç Seçenekleri", "@filteringOptions": {}, @@ -324,9 +324,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Satış Siparişlerini Göster", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Satış siparişleri tuşunu giriş ekranında göster", "@homeShowSoDescription": {}, "homeShowSubscribed": "Parça bildirimlerine abone ol", "@homeShowSubscribed": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Pasif", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Bu şirket inaktif olarak imlendi", "@inactiveCompany": {}, "inactiveDetail": "Bu parça pasif olarak işaretlendi", "@inactiveDetail": {}, @@ -394,7 +394,7 @@ "@issue": {}, "issueDate": "Sorun Tarihi", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Sipariş Ver", "@issueOrder": {}, "itemInLocation": "Parça zaten konumda", "@itemInLocation": {}, @@ -420,17 +420,17 @@ "@lastUpdated": {}, "level": "Düzey", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Satır Ögesi Ekle", "@lineItemAdd": {}, "lineItem": "Parça Sırası", "@lineItem": {}, "lineItems": "Parçalar Sırası", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Satır ögesi güncellendi", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Stok ögesi bul", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Stok konumu bul", "@locateLocation": {}, "locationCreate": "Yeni Konum", "@locationCreate": {}, @@ -494,11 +494,11 @@ "@orientationPortrait": {}, "orientationSystem": "Sistem", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Beklemede", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Bekleyen siparişleri göster", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Gecikmede", "@overdue": {}, "overdueDetail": "Gecikmiş siparişleri göster", "@overdueDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Parça satılabilir olarak imlenmemiş", "@partNotSalable": {}, "partsNone": "Parça Yok", "@partsNone": {}, @@ -574,7 +574,7 @@ "@pluginPrinter": {}, "pluginSupport": "Eklenti Desteği Etkin", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Sunucu özel eklentileri destekler", "@pluginSupportDetail": {}, "printLabelFailure": "Etiket yazdırılamadı", "@printLabelFailure": {}, @@ -636,7 +636,7 @@ "@queryNoResults": {}, "received": "Alınan", "@received": {}, - "receivedFilterDetail": "Alınan öğeleri göster", + "receivedFilterDetail": "Alınan ögeleri göster", "@receivedFilterDetail": {}, "receiveItem": "Alınan Öğeler", "@receiveItem": {}, @@ -714,15 +714,15 @@ }, "returned": "Geri Dönen", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Satış Siparişi", "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, "salesOrderCreate": "Yeni Satış Siparişi", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Satış Siparişini Düzenle", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Satış siparişi güncellendi", "@salesOrderUpdated": {}, "save": "Kaydet", "@save": { @@ -730,17 +730,17 @@ }, "scanBarcode": "Barkod Tara", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Sağlayıcı parça barkodunu tara", "@scanSupplierPart": {}, "scanIntoLocation": "Konuma Tara", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Bu ögeyi konuma tara", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Harici Tarayıcı", "@scannerExternal": {}, "scannerExternalDetail": "Barkodları okumak için harici tarayıcı kullan (keyboard wedge modu)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Alınan Parçaları Tara", "@scanReceivedParts": {}, "search": "Ara", "@search": { @@ -810,13 +810,13 @@ "@serverNotConnected": {}, "serverNotSelected": "Sunucu bulunamadı", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Gönderiler", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Gönderi Ekle", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Gönderildi", "@shipped": {}, - "sku": "Stok No", + "sku": "SKU", "@sku": {}, "sounds": "Sesler", "@sounds": {}, @@ -832,7 +832,7 @@ "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Şimdiki mevcut stok miktarı", "@stockDetails": {}, "stockItem": "Stok Kalemi", "@stockItem": { @@ -846,21 +846,21 @@ "@stockItemCreateDetail": {}, "stockItemDelete": "Stok parçasını sil", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Bu parçayı silmek istediğinize emin misiniz?", + "stockItemDeleteConfirm": "Bu stock ögesini silmek istediğinize emin misiniz?", "@stockItemDeleteConfirm": {}, "stockItemDeleteFailure": "Stok parçası silinemedi", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stok parçası silindi", + "stockItemDeleteSuccess": "Stok ögesi silindi", "@stockItemDeleteSuccess": {}, "stockItemHistory": "Stok Geçmişi", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Stok takip bilgisini göster", + "stockItemHistoryDetail": "Geçmiş stok takip bilgisini göster", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stok kalemi transfer edildi", + "stockItemTransferred": "Stok ögesi aktarıldı", "@stockItemTransferred": {}, - "stockItemUpdated": "Stok kalemi güncellendi", + "stockItemUpdated": "Stok ögesi güncellendi", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Uygun stok kalemi yok", + "stockItemsNotAvailable": "Kullanılabilir stok ögesi yok", "@stockItemsNotAvailable": {}, "stockItemNotes": "Stok Kalemi Notları", "@stockItemNotes": {}, @@ -876,9 +876,9 @@ "@stockLocations": {}, "stockTopLevel": "Üst seviye stok konumu", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Katı HTTPS Kullan", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "HTTPS sertifikalarını katı kontrole zorla", "@strictHttpsDetails": {}, "subcategory": "Alt kategori", "@subcategory": {}, @@ -900,11 +900,11 @@ "@supplier": {}, "supplierPart": "Tedarikçi Parçası", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Sağlayıcı Parçasını Düzenle", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Sağlayıcı Parça Numarası", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Sağlayıcı Parçası Güncellendi", "@supplierPartUpdated": {}, "supplierParts": "Tedarikçi Parçaları", "@supplierParts": {}, @@ -928,7 +928,7 @@ "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Stok ögesi test sonuçlarını görüntüle", "@testResultsDetail": {}, "testResultAdd": "Test Sonucu Ekle", "@testResultAdd": {}, @@ -960,11 +960,11 @@ "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Öğeyi farklı bir lokasyona aktarın", + "transferStockDetail": "Ögeyi farklı bir konuma aktar", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Stok Konumunu Aktar", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Bu stok konumunu başka bir konuma aktar", "@transferStockLocationDetail": {}, "translate": "Çeviri", "@translate": {}, @@ -998,7 +998,7 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Değer gereklidir", "@valueRequired": {}, - "variants": "Çeşitler", + "variants": "Türevler", "@variants": {}, "version": "Sürüm", "@version": {}, From 31cda0823ae1a303698a677eaca6a69d60c67a36 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Sep 2024 09:53:04 +1000 Subject: [PATCH 498/746] Label fix (#533) * Bug fix for stock item label printing - Simple typo - Closes https://github.com/inventree/inventree-app/issues/531 * Update version --- assets/release_notes.md | 5 +++++ lib/widget/stock/stock_detail.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index bc02280..ad1449e 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.16.4 - September 2024 +--- + +- Fixes bug related to printing stock item labels + ### 0.16.3 - August 2024 --- diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 88a0ba1..93b02b1 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -259,7 +259,7 @@ class _StockItemDisplayState extends RefreshableState { // Request information on labels available for this stock item if (allowLabelPrinting) { - String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "stock"; + String model_type = api.supportsModernLabelPrinting ? InvenTreeStockItem().MODEL_TYPE : "stock"; String item_key = api.supportsModernLabelPrinting ? "items" : "item"; // Clear the existing labels list diff --git a/pubspec.yaml b/pubspec.yaml index a00d686..d2505d2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.3+89 +version: 0.16.4+90 environment: sdk: ">=2.19.5 <3.13.0" From 6c0b3cccc30d89e501bff4e560e2a53fc101ab0a Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 Sep 2024 17:50:07 +1000 Subject: [PATCH 499/746] New Crowdin updates (#534) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 +- lib/l10n/lt_LT/app_lt_LT.arb | 1009 ++++++++++++++++++++++++++++++++++ lib/l10n/vi_VN/app_vi_VN.arb | 20 +- 3 files changed, 1020 insertions(+), 11 deletions(-) create mode 100644 lib/l10n/lt_LT/app_lt_LT.arb diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index c8ed9f7..b1ad192 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -42,7 +42,7 @@ "@appReleaseNotes": {}, "appSettings": "Réglages de l'application", "@appSettings": {}, - "appSettingsDetails": "Configuration des paramètres de l’application InvenTree", + "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", "@appSettingsDetails": {}, "attachments": "Pieces jointes", "@attachments": {}, diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb new file mode 100644 index 0000000..3b3fda3 --- /dev/null +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -0,0 +1,1009 @@ +{ + "@@locale": "lt", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "About", + "@about": {}, + "accountDetails": "Account Details", + "@accountDetails": {}, + "actions": "Actions", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "Add", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Address", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "attachments": "Attachments", + "@attachments": {}, + "attachImage": "Attach Image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "Available", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode Settings", + "@barcodeSettings": {}, + "barcodeAssign": "Assign Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode assigned", + "@barcodeAssigned": {}, + "barcodeError": "Barcode scan error", + "@barcodeError": {}, + "barcodeInUse": "Barcode already assigned", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "No match for barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scan part barcode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap or hold to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Select barcode scanner input source", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan Delay", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Delay between barcode scans", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan an InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan stock items into this location", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan stock location", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Single Scan Mode", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scanned into location", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item not scanned in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan stock item", + "@barcodeScanItem": {}, + "barcodeTones": "Barcode Tones", + "@barcodeTones": {}, + "barcodeUnassign": "Unassign Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barcode is not recognized", + "@barcodeUnknown": {}, + "batchCode": "Batch Code", + "@batchCode": {}, + "billOfMaterials": "Bill of Materials", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Display Bill of Materials", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancel Order", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "delete": "Delete", + "@delete": {}, + "deleteFailed": "Delete operation failed", + "@deleteFailed": {}, + "deletePart": "Delete Part", + "@deletePart": {}, + "deletePartDetail": "Remove this part from the database", + "@deletePartDetail": {}, + "deleteSuccess": "Delete operation successful", + "@deleteSuccess": {}, + "description": "Description", + "@description": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloading": "Downloading File", + "@downloading": {}, + "downloadError": "Download Error", + "@downloadError": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "enterPassword": "Enter password", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "Error deleting database entry", + "@errorDelete": {}, + "errorDetails": "Error Details", + "@errorDetails": {}, + "errorFetch": "Error fetching data from server", + "@errorFetch": {}, + "errorUserRoles": "Error requesting user roles from server", + "@errorUserRoles": {}, + "errorPluginInfo": "Error requesting plugin data from server", + "@errorPluginInfo": {}, + "errorReporting": "Error Reporting", + "@errorReporting": {}, + "errorReportUpload": "Upload Error Reports", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "@errorReportUploadDetails": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Active", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "External", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "In Stock", + "@filterInStock": {}, + "filterInStockDetail": "Show parts which have stock", + "@filterInStockDetail": {}, + "filterSerialized": "Serialized", + "@filterSerialized": {}, + "filterSerializedDetail": "Show serialized stock items", + "@filterSerializedDetail": {}, + "filterTemplate": "Template", + "@filterTemplate": {}, + "filterTemplateDetail": "Show template parts", + "@filterTemplateDetail": {}, + "filterTrackable": "Trackable", + "@filterTrackable": {}, + "filterTrackableDetail": "Show trackable parts", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Show virtual parts", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtering Options", + "@filteringOptions": {}, + "formatException": "Format Exception", + "@formatException": {}, + "formatExceptionJson": "JSON data format exception", + "@formatExceptionJson": {}, + "formError": "Form Error", + "@formError": {}, + "history": "History", + "@history": { + "description": "history" + }, + "home": "Home", + "@homeScreen": {}, + "homeScreen": "Home Screen", + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@homeShowPo": {}, + "homeShowPoDescription": "Show purchase order button on home screen", + "@homeShowPoDescription": {}, + "homeShowSo": "Show Sales Orders", + "@homeShowSo": {}, + "homeShowSoDescription": "Show sales order button on home screen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Show Suppliers", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Show Customers", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Image uploaded", + "@imageUploadSuccess": {}, + "inactive": "Inactive", + "@inactive": {}, + "inactiveCompany": "This company is marked as inactive", + "@inactiveCompany": {}, + "inactiveDetail": "This part is marked as inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Include Subcategories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Show results from subcategories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocations", + "@includeSublocations": {}, + "includeSublocationsDetail": "Show results from sublocations", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Incomplete profile details", + "@incompleteDetails": {}, + "internalPartNumber": "Internal Part Number", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Production", + "@inProduction": {}, + "inProductionDetail": "This stock item is in production", + "@inProductionDetail": {}, + "internalPart": "Internal Part", + "@internalPart": {}, + "invalidHost": "Invalid hostname", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Invalid Part", + "@invalidPart": {}, + "invalidPartCategory": "Invalid Part Category", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "language": "Language", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Select Language", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Level", + "@level": {}, + "lineItemAdd": "Add Line Item", + "@lineItemAdd": {}, + "lineItem": "Line Item", + "@lineItem": {}, + "lineItems": "Line Items", + "@lineItems": {}, + "lineItemUpdated": "Line item updated", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Login", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Notes", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifications", + "@notifications": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "No Results", + "@noResults": {}, + "noSubcategories": "No Subcategories", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "No subcategories available", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Invalid number", + "@numberInvalid": {}, + "onOrder": "On Order", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Screen Orientation", + "@orientation": {}, + "orientationDetail": "Screen orientation (requires restart)", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "Portrait", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Overdue", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Packaging", + "@packaging": {}, + "packageName": "Package Name", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Display part parameters", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "New Part", + "@partCreate": {}, + "partCreateDetail": "Create new part in this category", + "@partCreateDetail": {}, + "partEdited": "Part updated", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partSettings": "Part Settings", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "No starred parts available", + "@partsStarredNone": {}, + "partSuppliers": "Part Suppliers", + "@partSuppliers": {}, + "partCategory": "Part Category", + "@partCategory": {}, + "partCategoryTopLevel": "Top level part category", + "@partCategoryTopLevel": {}, + "partCategories": "Part Categories", + "@partCategories": {}, + "partDetails": "Part Details", + "@partDetails": {}, + "partNotes": "Part Notes", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "printLabel": "Print Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Enabled", + "@pluginSupport": {}, + "pluginSupportDetail": "The server supports custom plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label printing failed", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sent to printer", + "@printLabelSuccess": {}, + "profile": "Profile", + "@profile": {}, + "profileAdd": "Add Server Profile", + "@profileAdd": {}, + "profileConnect": "Connect to Server", + "@profileConnect": {}, + "profileEdit": "Edit Server Profile", + "@profileEdit": {}, + "profileDelete": "Delete Server Profile", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "profileName": "Profile Name", + "@profileName": {}, + "profileNone": "No profiles available", + "@profileNone": {}, + "profileNotSelected": "No Profile Selected", + "@profileNotSelected": {}, + "profileSelect": "Select InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Select server or create a new profile", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tap to create or select a profile", + "@profileTapToCreate": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrder": "Purchase Order", + "@purchaseOrder": {}, + "purchaseOrderCreate": "New Purchase Order", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Edit Purchase Order", + "@purchaseOrderEdit": {}, + "purchaseOrders": "Purchase Orders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Purchase order updated", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Quantity", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Quantity is empty", + "@quantityEmpty": {}, + "quantityInvalid": "Quantity is invalid", + "@quantityInvalid": {}, + "quantityPositive": "Quantity must be positive", + "@quantityPositive": {}, + "queryEmpty": "Enter search query", + "@queryEmpty": {}, + "queryNoResults": "No results for query", + "@queryNoResults": {}, + "received": "Received", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Receive Item", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Refresh", + "@refresh": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Rejected", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Remove", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "results": "Results", + "@results": {}, + "request": "Request", + "@request": {}, + "requestFailed": "Request Failed", + "@requestFailed": {}, + "requestSuccessful": "Request successful", + "@requestSuccessful": {}, + "requestingData": "Requesting Data", + "@requestingData": {}, + "required": "Required", + "@required": { + "description": "This field is required" + }, + "response400": "Bad Request", + "@response400": {}, + "response401": "Unauthorized", + "@response401": {}, + "response403": "Permission Denied", + "@response403": {}, + "response404": "Resource Not Found", + "@response404": {}, + "response405": "Method Not Allowed", + "@response405": {}, + "response429": "Too Many Requests", + "@response429": {}, + "response500": "Internal Server Error", + "@response500": {}, + "response501": "Not Implemented", + "@response501": {}, + "response502": "Bad Gateway", + "@response502": {}, + "response503": "Service Unavailable", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP Version Not Supported", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "Unknown Response", + "@responseUnknown": {}, + "result": "Result", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@salesOrder": {}, + "salesOrders": "Sales Orders", + "@salesOrders": {}, + "salesOrderCreate": "New Sales Order", + "@saleOrderCreate": {}, + "salesOrderEdit": "Edit Sales Order", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Save", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Into Location", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "External Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Search", + "@search": { + "description": "search" + }, + "searching": "Searching", + "@searching": {}, + "searchLocation": "Search for location", + "@searchLocation": {}, + "searchParts": "Search Parts", + "@searchParts": {}, + "searchStock": "Search Stock", + "@searchStock": {}, + "select": "Select", + "@select": {}, + "selectFile": "Select File", + "@selectFile": {}, + "selectImage": "Select Image", + "@selectImage": {}, + "selectLocation": "Select a location", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serial Number", + "@serialNumber": {}, + "serialNumbers": "Serial Numbers", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Server Address", + "@serverAddress": {}, + "serverApiRequired": "Required API Version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Authentication Error", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "@serverCertificateInvalid": {}, + "serverConnected": "Connected to Server", + "@serverConnected": {}, + "serverConnecting": "Connecting to server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Could not connect to server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Server Error", + "@serverError": {}, + "serverDetails": "Server Details", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Old Server Version", + "@serverOld": {}, + "serverSettings": "Server Settings", + "@serverSettings": {}, + "serverStart": "Server must start with http[s]", + "@serverStart": {}, + "settings": "Settings", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@serverNotConnected": {}, + "serverNotSelected": "Server not selected", + "@serverNotSelected": {}, + "shipments": "Shipments", + "@shipments": {}, + "shipmentAdd": "Add Shipment", + "@shipmentAdd": {}, + "shipped": "Shipped", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stock", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Stock Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stock Items", + "@stockItems": {}, + "stockItemCreate": "New Stock Item", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Create new stock item in this location", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Delete Stock Item", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Display historical stock tracking information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stock item transferred", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stock item updated", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "No stock items available", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Stock Item Notes", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Stock item updated", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Stock item update failed", + "@stockItemUpdateFailure": {}, + "stockLocation": "Stock Location", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Stock Locations", + "@stockLocations": {}, + "stockTopLevel": "Top level stock location", + "@stockTopLevel": {}, + "strictHttps": "Use Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subcategory", + "@subcategory": {}, + "subcategories": "Subcategories", + "@subcategories": {}, + "sublocation": "Sublocation", + "@sublocation": {}, + "sublocations": "Sublocations", + "@sublocations": {}, + "sublocationNone": "No Sublocations", + "@sublocationNone": {}, + "sublocationNoneDetail": "No sublocations available", + "@sublocationNoneDetail": {}, + "submitFeedback": "Submit Feedback", + "@submitFeedback": {}, + "suppliedParts": "Supplied Parts", + "@suppliedParts": {}, + "supplier": "Supplier", + "@supplier": {}, + "supplierPart": "Supplier Part", + "@supplierPart": {}, + "supplierPartEdit": "Edit Supplier Part", + "@supplierPartEdit": {}, + "supplierPartNumber": "Supplier Part Number", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Supplier Part Updated", + "@supplierPartUpdated": {}, + "supplierParts": "Supplier Parts", + "@supplierParts": {}, + "suppliers": "Suppliers", + "@suppliers": {}, + "supplierReference": "Supplier Reference", + "@supplierReference": {}, + "takePicture": "Take Picture", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Test Name", + "@testName": {}, + "testPassedOrFailed": "Test passed or failed", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "Test Results", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Display stock item test results", + "@testResultsDetail": {}, + "testResultAdd": "Add Test Result", + "@testResultAdd": {}, + "testResultNone": "No Test Results", + "@testResultNone": {}, + "testResultNoneDetail": "No test results available", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error uploading test result", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfer Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transfer item to a different location", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer Stock Location", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transfer this stock location into another", + "@transferStockLocationDetail": {}, + "translate": "Translate", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Username", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Value", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Value cannot be empty", + "@valueCannotBeEmpty": {}, + "valueRequired": "Value is required", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {} +} \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 03929c2..087f2b8 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -34,9 +34,9 @@ "@appCredits": {}, "appDetails": "Chi tiết về ứng dụng", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Được phân bố", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Phân kho", "@allocateStock": {}, "appReleaseNotes": "Hiển thị ghi chú phát hành ứng dụng", "@appReleaseNotes": {}, @@ -82,7 +82,7 @@ "@barcodeNoMatch": {}, "barcodeNotAssigned": "Mã vạch chưa được quét", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Quét mã hàng hóa", "@barcodeScanPart": {}, "barcodeReceivePart": "Quét mã vạch để nhận sản phẩm", "@barcodeReceivePart": {}, @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Cấu hình thiết lập máy chủ", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Xác nhận chuyển tiền", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Xác nhận chi tiết chuyển tiền khi quét mã", "connectionRefused": "Kết nối bị từ chối", "@connectionRefused": {}, "count": "Đếm", @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Không hoạt động", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Đánh dáu không hoạt động cho công ty này", "@inactiveCompany": {}, "inactiveDetail": "Phần này được đánh dấu là không hoạt động", "@inactiveDetail": {}, @@ -530,7 +530,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Đánh dấu không thể bán cho hàng hoá", "@partNotSalable": {}, "partsNone": "Không có phụ tùng", "@partsNone": {}, @@ -730,7 +730,7 @@ }, "scanBarcode": "Quét mã vạch", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Quét mã nhà cung cấp hàng hoá", "@scanSupplierPart": {}, "scanIntoLocation": "Quét vào điểm bán", "@scanIntoLocation": {}, @@ -810,9 +810,9 @@ "@serverNotConnected": {}, "serverNotSelected": "Chưa chọn máy chủ", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Vận chuyển", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Thêm phương thức vận chuyển", "@shipmentAdd": {}, "shipped": "Đã vận chuyển", "@shipped": {}, From ad48e5e1724d841a1bc34760e7fa0e379a7fdc6c Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 27 Sep 2024 22:28:00 +1000 Subject: [PATCH 500/746] New Crowdin updates (#536) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Russian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Indonesian) --- lib/l10n/et_EE/app_et_EE.arb | 40 +- lib/l10n/he_IL/app_he_IL.arb | 904 +++++++++++++++++------------------ lib/l10n/id_ID/app_id_ID.arb | 30 +- lib/l10n/ru_RU/app_ru_RU.arb | 2 +- lib/l10n/uk_UA/app_uk_UA.arb | 26 +- 5 files changed, 501 insertions(+), 501 deletions(-) diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index ceca1b5..c5b340b 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -130,7 +130,7 @@ "@bom": {}, "bomEnable": "Display Bill of Materials", "@bomEnable": {}, - "build": "Build", + "build": "Ehita", "@build": {}, "building": "Building", "@building": {}, @@ -166,7 +166,7 @@ "@configureServer": {}, "confirmScan": "Kinnita ülekanne", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Kinnitage laoseisu ülekande üksikasjad vöötkoodide skaneerimisel", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -215,7 +215,7 @@ "@downloading": {}, "downloadError": "Allalaadimise viga", "@downloadError": {}, - "edit": "Edit", + "edit": "Muuda", "@edit": { "description": "edit" }, @@ -267,7 +267,7 @@ "@feedbackError": {}, "feedbackSuccess": "Feedback submitted", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Aktiivne", "@filterActive": {}, "filterActiveDetail": "Show active parts", "@filterActiveDetail": {}, @@ -315,7 +315,7 @@ "@history": { "description": "history" }, - "home": "Home", + "home": "Avaleht", "@homeScreen": {}, "homeScreen": "Home Screen", "homeScreenSettings": "Configure home screen settings", @@ -440,7 +440,7 @@ "@locationNotSet": {}, "locationUpdated": "Stock location updated", "@locationUpdated": {}, - "login": "Login", + "login": "Logi sisse", "@login": {}, "loginEnter": "Enter login details", "@loginEnter": {}, @@ -492,7 +492,7 @@ "@orientationLandscape": {}, "orientationPortrait": "Portrait", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Süsteem", "@orientationSystem": {}, "outstanding": "Outstanding", "@outstanding": {}, @@ -516,7 +516,7 @@ "@parentCategory": {}, "parentLocation": "Parent Location", "@parentLocation": {}, - "part": "Part", + "part": "Osa", "@part": { "description": "Part (single)" }, @@ -562,7 +562,7 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Teie kontol ei ole vajalikke õigusi selle toimingu sooritamiseks", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, @@ -580,7 +580,7 @@ "@printLabelFailure": {}, "printLabelSuccess": "Label sent to printer", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Profiil", "@profile": {}, "profileAdd": "Add Server Profile", "@profileAdd": {}, @@ -652,7 +652,7 @@ "@rejected": {}, "releaseNotes": "Release Notes", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Eemalda", "@remove": { "description": "remove" }, @@ -724,7 +724,7 @@ "@salesOrderEdit": {}, "salesOrderUpdated": "Sales order updated", "@salesOrderUpdated": {}, - "save": "Save", + "save": "Salvesta", "@save": { "description": "Save" }, @@ -754,7 +754,7 @@ "@searchParts": {}, "searchStock": "Search Stock", "@searchStock": {}, - "select": "Select", + "select": "Vali", "@select": {}, "selectFile": "Select File", "@selectFile": {}, @@ -762,7 +762,7 @@ "@selectImage": {}, "selectLocation": "Select a location", "@selectLocation": {}, - "send": "Send", + "send": "Saada", "@send": {}, "serialNumber": "Serial Number", "@serialNumber": {}, @@ -802,7 +802,7 @@ "@serverSettings": {}, "serverStart": "Server must start with http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Seaded", "@settings": {}, "serverInstance": "Server Instance", "@serverInstance": {}, @@ -846,7 +846,7 @@ "@stockItemCreateDetail": {}, "stockItemDelete": "Delete Stock Item", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Kas olete kindel, et soovite selle üksuse kustutada?", "@stockItemDeleteConfirm": {}, "stockItemDeleteFailure": "Could not delete stock item", "@stockItemDeleteFailure": {}, @@ -878,7 +878,7 @@ "@stockTopLevel": {}, "strictHttps": "Use Strict HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Kohusta ranget HTTPS-sertifikaatide kontrollimist", "@strictHttpsDetails": {}, "subcategory": "Subcategory", "@subcategory": {}, @@ -896,7 +896,7 @@ "@submitFeedback": {}, "suppliedParts": "Supplied Parts", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "Tarnija", "@supplier": {}, "supplierPart": "Supplier Part", "@supplierPart": {}, @@ -986,11 +986,11 @@ "@usedIn": {}, "usedInDetails": "Assemblies which require this part", "@usedInDetails": {}, - "username": "Username", + "username": "Kasutajanimi", "@username": {}, "usernameEmpty": "Username cannot be empty", "@usernameEmpty": {}, - "value": "Value", + "value": "Väärtus", "@value": { "description": "value" }, diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 48f0acd..abb4092 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -8,507 +8,507 @@ "@ok": { "description": "OK" }, - "about": "About", + "about": "אודות", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "פרטי חשבון", "@accountDetails": {}, - "actions": "Actions", + "actions": "פעולות", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "אין פעולות זמינות", "@actionsNone": {}, - "add": "Add", + "add": "הוסף", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "הוסף מלאי", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "כתובת", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "אודות InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "קרדיטים נוספים לאפליקציה", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "פרטי האפליקציה", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "מוקצה", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "הקצאת מלאי", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": " הצג הערות פרסום של האפליקציה", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "הגדרות אפליקציה", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "הגדר את הגדרות אפליקציית Inventree", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "קבצים מצורפים", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "צירוף תמונה", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "לא נמצאו קבצים מצורפים", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "לא נמצאו קבצים מצורפים", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "בחר קובץ מצורף", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "תשומת לב", "@attention": {}, - "available": "Available", + "available": "זמין", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "מלאי זמין", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "ברקודים", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "הגדרות ברקוד", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "הקצה ברקוד", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "סרוק ברקוד מותאם אישית להקצאה", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "הוקצה ברקוד", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "שגיאת סריקת ברקוד", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "הברקוד כבר הוקצה", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "נתוני גיבוב ברקוד חסרים בתגובה", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "אין התאמה לברקוד", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "ברקוד לא הוקצה", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "סרוק ברקוד של פריט", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "סרוק ברקוד כדי לקבל פריט", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "סריקת ברקוד מושהית", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "בקש או החזק כדי להשהות את הסריקה", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "סרוק כדי להקצות ברקוד", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "קלט סורק", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "בחר מקור קלט של סורק ברקוד", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "השהיית סריקת ברקוד", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "עיכוב בין סריקת ברקוד", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "סרוק ברקוד של InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "סרוק פריטי מלאי למיקום זה", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "סרוק את מיקום המלאי", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "מצב סריקה בודדת", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "השהה את סורק הברקוד לאחר כל סריקה", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "נסרק למיקום", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "פריט לא נסרק פנימה", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "סרוק פריט במלאי", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "צלילי ברקוד", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "בטל הקצאת ברקוד", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "הברקוד אינו מזוהה", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "קוד אצווה", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "שטר חומרים [Bom]", "@billOfMaterials": {}, - "bom": "BOM", + "bom": "שטר חומרים [Bom]", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "הצג את כתב החומרים", "@bomEnable": {}, "build": "Build", "@build": {}, "building": "Building", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "מצלמה פנימית", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "השתמש במצלמה פנימית לקריאת ברקודים", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "ביטול", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "ביטול הזמנה", "@cancelOrder": {}, - "category": "Category", + "category": "קטגוריה", "@category": {}, - "categoryCreate": "New Category", + "categoryCreate": "קטגוריה חדשה", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "צור קטגוריית פריטים חדשה", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "קטגוריית הפריט עודכנה", "@categoryUpdated": {}, - "company": "Company", + "company": "חברה", "@company": {}, - "companyEdit": "Edit Company", + "companyEdit": "ערוך חברה", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "אין חברות שתואמות לשאילתה", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "פרטי החברה עודכנו", "@companyUpdated": {}, - "companies": "Companies", + "companies": "חברות", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "קבע את הגדרות השרת", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "אשר העברה", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "confirmScanDetail": "אשר את פרטי העברת המלאי בעת סריקת ברקודים", + "connectionRefused": "החיבור סורב", "@connectionRefused": {}, - "count": "Count", + "count": "ספירה", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "ספירת מלאי", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "קרדיטים", "@credits": {}, - "customer": "Customer", + "customer": "לקוח", "@customer": {}, - "customers": "Customers", + "customers": "לקוחות", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "הפניה ללקוח", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "מלאי פגום", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "מצב כהה", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "הפעל מצב כהה", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "מחק", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "פעולת המחיקה נכשלה", "@deleteFailed": {}, - "deletePart": "Delete Part", + "deletePart": "מחק פריט", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "הסר פריט זה ממסד הנתונים", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "פעולת המחיקה הצליחה", "@deleteSuccess": {}, - "description": "Description", + "description": "תיאור", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "מושמד", "@destroyed": {}, - "details": "Details", + "details": "פרטים", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "תיעוד", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "מוריד קובץ", "@downloading": {}, - "downloadError": "Download Error", + "downloadError": "שגיאת הורדה", "@downloadError": {}, - "edit": "Edit", + "edit": "ערוך", "@edit": { "description": "edit" }, - "editCategory": "Edit Category", + "editCategory": "ערוך קטגוריה", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "ערוך מיקום", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "ערוך הערות", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "ערוך פרמטר", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "ערוך פריט", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "ערוך פריט מלאי", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "ערוך פריט", "@editLineItem": {}, - "enterPassword": "Enter password", + "enterPassword": "הזן סיסמה", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "הזן שם משתמש", "@enterUsername": {}, - "error": "Error", + "error": "שגיאה", "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "שגיאה ביצירת ערך מסד הנתונים", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "שגיאה במחיקת ערך ממסד הנתונים", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "פרטי שגיאה", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "שגיאה באחזור נתונים מהשרת", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "שגיאה בבקשת תפקידי משתמש מהשרת", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "שגיאה בבקשת נתוני פלגאין מהשרת", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "דווח על שגיאות ", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "העלה דוחות שגיאה", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "העלאת דוחות שגיאה אנונימיים ויומני קריסה", "@errorReportUploadDetails": {}, - "feedback": "Feedback", + "feedback": "משוב", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "שגיאה בהגשת משוב", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "נשלח משוב", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "פעיל", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "הצג פריטים פעילים", "@filterActiveDetail": {}, "filterAssembly": "Assembled", "@filterAssembly": {}, "filterAssemblyDetail": "Show assembled parts", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "רכיב", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "הצג פריטי רכיבים", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "חיצוני", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "הצג מלאי במקומות חיצוניים", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "במלאי", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "הצג פריטים שיש להם מלאי", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "בסדרה", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "הצג פריטי מלאי בסדרה", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "תבנית", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "הצג חלקי תבנית", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "ניתן למעקב", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "הצג פריטים שניתנים למעקב", "@filterTrackableDetail": {}, - "filterVirtual": "Virtual", + "filterVirtual": "וירטואלי", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "הצג פריטים וירטואלים", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "אפשרויות סינון", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "חריגה בפורמט", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "חריגה בפורמט הנתונים של JSON", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "שגיאת טופס", "@formError": {}, - "history": "History", + "history": "היסטוריה", "@history": { "description": "history" }, - "home": "Home", + "home": "בית", "@homeScreen": {}, - "homeScreen": "Home Screen", - "homeScreenSettings": "Configure home screen settings", + "homeScreen": "מסך הבית", + "homeScreenSettings": "הגדר את הגדרות מסך הבית", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "הצג הזמנות רכש", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "הצג את לחצן הזמנת רכש במסך הבית", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "הצג הזמנות מכירה", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "הצג את לחצן הזמנות מכירה במסך הבית", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "פריטי מנויים", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "הצכ פריטים רשומים במסך הבית", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "הצג ספקים", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "הצג לחצן ספקים במסך הבית", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "הצג יצרנים", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "הצג את לחצן היצרן במסך הבית", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "הצג לקוחות", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "הצג את לחצן הלקוחות במסך הבית", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "העלאת התמונה נכשלה", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "התמונה הועלתה", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "לא פעיל", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "חברה זו מסומנת כלא פעילה", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "פריט זה מסומן כלא פעיל", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "כלול קטגוריות משנה", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "הצג תוצאות מקטגוריות משנה", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "כלול מיקומי משנה", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "הצג תוצאות ממיקומי משנה", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "פרטי פרופיל לא מלאים", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "מספר פריט פנימי", "@internalPartNumber": {}, - "info": "Info", + "info": "מידע", "@info": {}, - "inProduction": "In Production", + "inProduction": "בתהליך ייצור", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "פריט מלאי זה נמצא בייצור", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "פריט פנימי", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "שם מארח לא חוקי", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "שם המארח שסופק אינו חוקי", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "פריט לא חוקי", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "קטגוריית פריט לא חוקית", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "מיקום מלאי לא חוקי", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "פריט מלאי לא חוקי", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "פריט ספק לא חוקי", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "שילוב שם משתמש/סיסמה לא תקין", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "להנפיק", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "תאריך הנפקה", "@issueDate": {}, "issueOrder": "Issue Order", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "הפריט כבר נמצא במיקום", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "הפרריט הוסר", "@itemDeleted": {}, - "keywords": "Keywords", + "keywords": "מילות מפתח", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "הדפסת תווית", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "אפשר הדפסת תווית", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "תבנית תווית", "@labelTemplate": {}, - "language": "Language", + "language": "שפה", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "שפת מערכת ברירת מחדל", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "בחירת שפה", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "סקר אחרון", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "עודכן לאחרונה", "@lastUpdated": {}, - "level": "Level", + "level": "רמה", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "הוסף שורת פריט", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "שורת פריט", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "שורת פריט", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "שורת פריט עודכנה", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "אתר פריט במלאי", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "אתר את מיקום המלאי", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "מיקום חדש", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "צור מיקום מלאי חדש", "@locationCreateDetail": {}, - "locationNotSet": "No location specified", + "locationNotSet": "לא צוין מיקום", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "מיקום המלאי עודכן", "@locationUpdated": {}, - "login": "Login", + "login": "כניסה למערכת", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "הזן פרטי כניסה", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "שם המשתמש והכניסה אינם מאוחסנים באופן מקומי", "@loginEnterDetails": {}, - "link": "Link", + "link": "קישור", "@link": {}, - "lost": "Lost", + "lost": "אבודים", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "מספר פריט של היצרן", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "יצרן", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "יצרנים", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "נתונים חסרים", "@missingData": {}, - "name": "Name", + "name": "שם", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "לא מחובר", "@notConnected": {}, - "notes": "Notes", + "notes": "הערות", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "התראות", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "אין התראות שלא נקראו", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "אין תגובה מהשרת", "@noResponse": {}, - "noResults": "No Results", + "noResults": "אין תוצאות", "@noResults": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "אין קטגורית משנה", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "אין קטכוריות משנה זמינות", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "מספר לא חוקי", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "בהזמנה", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "פריטים בהזמנה כרגע", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "כוון מסך", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "כוון מסך [דורש הפעלה מחדש]", "@orientationDetail": {}, "orientationLandscape": "Landscape", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "דיוקן [פורטרט]", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "מערכת", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "הזמנות יוצאות דופן", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "הצג הזמנות יוצאות דופן", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "באיחור", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "הצג הזמנות באיחור", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "אריזה", "@packaging": {}, - "packageName": "Package Name", + "packageName": "שם החבילה", "@packageName": {}, - "parameters": "Parameters", + "parameters": "פרמטרים", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "הצגת פרמטרים של פריטים", "@parametersSettingDetail": {}, "parent": "Parent", "@parent": {}, @@ -516,494 +516,494 @@ "@parentCategory": {}, "parentLocation": "Parent Location", "@parentLocation": {}, - "part": "Part", + "part": "פריט", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "פריט חדש", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "צור פריט חדש בקטגוריה זו", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "פריט עודכן", "@partEdited": {}, - "parts": "Parts", + "parts": "פריטים", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "פריט לא סומן כניתן למכירה", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "אין פריטים", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "אין פריטים התואמים לשאילתה", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "הגדרות פריט", "@partSettings": {}, "partsStarred": "Subscribed Parts", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "אין פריטים זמינים שמסומנים בכוכב", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "ספקי פריטים", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "קטגוריית פריט", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "קטגוריית פריטים ברמה עליונה", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "קטגוריית פריטים", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "פרטי פריט", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "הערות פריט", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "מלאי פריט", "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "סיסמה", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "הסיסמה לא יכולה להיות ריקה", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "לחשבון זה אין את ההרשאות לבצע פעולה זו", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "נדרשת הרשאה", "@permissionRequired": {}, - "printLabel": "Print Label", + "printLabel": "הדפס תווית", "@printLabel": {}, - "plugin": "Plugin", + "plugin": "תוסף", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "מדפסת", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "תמיחכה בפלגאין מופעלת", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "השרת תומך בתוספים מותאמים אישית", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "הדפסת התווית נכשלה", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "תווית נשלחה למדפסת", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "פרופיל", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "הוסף פרופיל שרת", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "התחבר לשרת", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "ערוך פרופיל שרת", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "מחק את פרופיל השרת", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "ניתוק פרופיל", "@profileLogout": {}, "profileName": "Profile Name", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "אין פרופילים זמינים", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "לא נבחר פרופיל", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "בחר שרת InvenTree", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "בחר שרת או צור פרופיל חדש", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "הקש כדי לבחור או ליצור פרופיל", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "קוד פרויקט ", "@projectCode": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "הזמנת רכש", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "הזמנת רכש חדשה", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "ערוך הזמנת רכש", "@purchaseOrderEdit": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "הזמנות רכש", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "הזמנות רכש עודכנו", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "מחיר רכישה", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "כמות", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "כמות זמינה", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "הכמות ריקה", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "הכמות לא חוקית", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "הכמות חייבת להיות חיובית", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "הזן שאילתת חיפוש", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "אין תוצאות לשאילתה", "@queryNoResults": {}, - "received": "Received", + "received": "התקבל", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "הצג פריטים שהתקבלו", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "קבל פריט", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "פריט מלאי שהתקבל", "@receivedItem": {}, - "reference": "Reference", + "reference": "הפניה", "@reference": {}, - "refresh": "Refresh", + "refresh": "רענון", "@refresh": {}, - "refreshing": "Refreshing", + "refreshing": "מרענן", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "נדחה", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "הערות פרסום", "@releaseNotes": {}, - "remove": "Remove", + "remove": "להסיר", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "הסר מלאי", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "דווח על באג", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "שלח דוח באג [דורש חשבון בגיט-האב]", "@reportBugDescription": {}, - "results": "Results", + "results": "תוצאות", "@results": {}, - "request": "Request", + "request": "בקשה", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "הבקשה נכשלה", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "הבקשה מוצלחת", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "מבקש נתונים", "@requestingData": {}, - "required": "Required", + "required": "דרוש", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "בקשה לא תקינה", "@response400": {}, - "response401": "Unauthorized", + "response401": "לא מורשה", "@response401": {}, - "response403": "Permission Denied", + "response403": "הרשאה נדחיתה", "@response403": {}, - "response404": "Resource Not Found", + "response404": "משאב לא נמצא", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "שיטה לא מורשית", "@response405": {}, - "response429": "Too Many Requests", + "response429": "יותר מידי בקשות", "@response429": {}, - "response500": "Internal Server Error", + "response500": "שגיאת שרת פנימית", "@response500": {}, - "response501": "Not Implemented", + "response501": "לא מיושם", "@response501": {}, - "response502": "Bad Gateway", + "response502": "קישור GetAway לא תקין", "@response502": {}, - "response503": "Service Unavailable", + "response503": "השירות אינו זמין", "@response503": {}, - "response504": "Gateway Timeout", + "response504": "טיים אאוט גט אוואי", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "גרסת HTTP לא נתמכת", "@response505": {}, "responseData": "Response data", "@responseData": {}, "responseInvalid": "Invalid Response Code", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "תגובה לא ידועה", "@responseUnknown": {}, - "result": "Result", + "result": "תוצאה", "@result": { "description": "" }, - "returned": "Returned", + "returned": "החזרות", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "הזמנת מכירה", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "הזמנת מכירות", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "הזמנת מכירה חדשה", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "ערוך הזמנת מכירות", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "הזמנת מכירות עודכנה", "@salesOrderUpdated": {}, - "save": "Save", + "save": "שמור", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "סרוק ברקוד", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "סרוק ברקוד פריט של ספק", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "סרוק למיקום", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "סרוק פריט זה למיקום", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "סורק חיצוני", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "השתמש בסורק חיצוני לסריקת ברקודים [מצב טריז]", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "סרוק פריטים שהתקבלו", "@scanReceivedParts": {}, - "search": "Search", + "search": "חפש", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "מחפש", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "חפש מיקום", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "חיפוש פריטים", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "חפש מלאי", "@searchStock": {}, - "select": "Select", + "select": "בחר", "@select": {}, - "selectFile": "Select File", + "selectFile": "בחר קובץ", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "בחר תמונה", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "בחר מיקום", "@selectLocation": {}, - "send": "Send", + "send": "שלח", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "מספר סידורי", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "מספרים סידוריים", "@serialNumbers": {}, - "server": "Server", + "server": "שרת", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "כתובת שרת", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "גרסת API נדרשת", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "גרסת API של שרת", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "שגיאת אימות", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "שגיאת אישור", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "אישור HTTPS של השרת אינו חוקי", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "מחובר לשרת", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "מתחבר לשרת", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "לא ניתן להתחבר לשרת", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "השרת לא יכול להיות ריק", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "שגיאת שרת", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "פרטי שרת", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "בתגובת השרת חסרים שדות חובה", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "גרסת שרת ישנה", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "הגדרות שרת", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "השרת חייב להתחיל עם Http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "הגדרות", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "מופע שרת", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "השרת לא מחובר", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "השרת לא נבחר", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "משלוחים", "@shipments": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, "shipped": "Shipped", "@shipped": {}, - "sku": "SKU", + "sku": "מק\"ט [מספר קטלוגי] ", "@sku": {}, - "sounds": "Sounds", + "sounds": "צלילים", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "השמעת צליל בפעולת ברקוד", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "השמעת צליל בשגיאת שרת", "@soundOnServerError": {}, - "status": "Status", + "status": "סטטוס", "@status": {}, - "statusCode": "Status Code", + "statusCode": "סטטוס קוד", "@statusCode": {}, - "stock": "Stock", + "stock": "מלאי", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "כמות מלאי נוכחית זמינה", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "פריט במלאי", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "פריטים במלאי", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "פריט מלאי חדש", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "צור פריט מלאי חדש במיקום זה", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "מחק פריט מלאי", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "האם את/ה בטוח/ה שמעוניינ/ת למחוק את פריט המלאי הזה? ", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "לא ניתן למחוק פריט במלאי", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "פריט מלאי נמחק", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "היסטוריית מלאי", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "הצג מידע היסטורי על מעקב אחר מלאי", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "פריט המלאי הועבר", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "פריט המלאי עודכן", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "אין פריטים זמינים במלאי", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "הערות למלאי", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "פריט המלאי עודכן", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "עדכון פריט מלאי נכשל", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "מיקום מלאי", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "מיקום מלאים", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "מיקום מלאי ברמה עליונה ", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "השתמש ב - HTTPS קפדני", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "אכוף בדיקה קפדנית של אישורי Http's", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "קטגוריית משנה", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "קטגוריות משנה", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "מיקום משנה", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "מיקומי משנה", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "אין תת-מיקומים", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "אין מיקומי משנה זמינים", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "שלח משוב", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "פריטי ספקים", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "ספק", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "פריט ספק", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "ערוך פריט ספק", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "מספר פריט ספק", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "פריט הספק עודכן", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "פריטי ספק", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "ספקים", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "הפנייה לספק", "@supplierReference": {}, - "takePicture": "Take Picture", + "takePicture": "צלם תמונה", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "תאריך יעד", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "פריט תבנית אב", "@templatePart": {}, - "testName": "Test Name", + "testName": "שם הבדיקה", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "המבחן עבר או נכשל", "@testPassedOrFailed": {}, "testsRequired": "Required Tests", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "תוצאות המבחן", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "הצגת תוצאות בדיקת פריט במלאי", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "הוסף תוצאות בדיקה", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "אין תוצאות בדיקה", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "אין תוצאות בדיקה זמינות", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "שגיאה בהעלאת תוצאות הבדיקה", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "תוצאת הבדיקה הועלתה", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "פסק זמן [דילאיי]", "@timeout": { "description": "" }, - "tokenError": "Token Error", + "tokenError": "שגיאת טוקן", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "טוקן חסר", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "גישת טוקן חסרה בתגובה", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "מחיר כולל", "@totalPrice": {}, - "transfer": "Transfer", + "transfer": "העבר", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "העברת מלאי", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "העברת פריט למקום אחר", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "העברת מיקום מלאי", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "העבר את מיקום המלאי הזה למיקום אחר", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "תרגם", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "עזרו לתרגם את אפליקציית InvenTree", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "מחיר ליחידה", "@unitPrice": {}, - "units": "Units", + "units": "יחידות", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "תגובה לא ידועה", "@unknownResponse": {}, - "upload": "Upload", + "upload": "העלה", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "העלאת הקובץ נכשלה", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "הקובץ הועלה", "@uploadSuccess": {}, - "usedIn": "Used In", + "usedIn": "בשימוש ב ", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", "@usedInDetails": {}, - "username": "Username", + "username": "שם משתמש", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "שם משתמש לא יכול להיות ריק", "@usernameEmpty": {}, - "value": "Value", + "value": "ערך", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "ערך לא יכול להיות ריק", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "נדרש ערך", "@valueRequired": {}, - "variants": "Variants", + "variants": "גרסאות", "@variants": {}, - "version": "Version", + "version": "גרסה", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "צפה בפריט הספק", "@viewSupplierPart": {}, - "website": "Website", + "website": "אתר", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index e1bc338..287e4c7 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -187,7 +187,7 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, - "darkMode": "Dark Mode", + "darkMode": "Mode Gelap", "@darkMode": {}, "darkModeEnable": "Enable dark mode", "@darkModeEnable": {}, @@ -317,7 +317,7 @@ }, "home": "Beranda", "@homeScreen": {}, - "homeScreen": "Home Screen", + "homeScreen": "Tampilan Beranda", "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -580,11 +580,11 @@ "@printLabelFailure": {}, "printLabelSuccess": "Label sent to printer", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Profil", "@profile": {}, "profileAdd": "Add Server Profile", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "Sambung ke Server", "@profileConnect": {}, "profileEdit": "Edit Server Profile", "@profileEdit": {}, @@ -638,13 +638,13 @@ "@received": {}, "receivedFilterDetail": "Show received items", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Item yang diterima", "@receiveItem": {}, "receivedItem": "Received Stock Item", "@receivedItem": {}, "reference": "Reference", "@reference": {}, - "refresh": "Refresh", + "refresh": "Segarkan", "@refresh": {}, "refreshing": "Refreshing", "@refreshing": {}, @@ -652,7 +652,7 @@ "@rejected": {}, "releaseNotes": "Release Notes", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Hapus", "@remove": { "description": "remove" }, @@ -660,7 +660,7 @@ "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Laporkan Masalah", "@reportBug": {}, "reportBugDescription": "Submit bug report (requires GitHub account)", "@reportBugDescription": {}, @@ -752,7 +752,7 @@ "@searchLocation": {}, "searchParts": "Search Parts", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "Cari Persediaan", "@searchStock": {}, "select": "Pilih", "@select": {}, @@ -764,7 +764,7 @@ "@selectLocation": {}, "send": "Kirim", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Nomor Seri", "@serialNumber": {}, "serialNumbers": "Serial Numbers", "@serialNumbers": {}, @@ -790,7 +790,7 @@ "@serverCouldNotConnect": {}, "serverEmpty": "Server cannot be empty", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Galat Server", "@serverError": {}, "serverDetails": "Server Details", "@serverDetails": {}, @@ -852,7 +852,7 @@ "@stockItemDeleteFailure": {}, "stockItemDeleteSuccess": "Stock item deleted", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "Riwayat Stok", "@stockItemHistory": {}, "stockItemHistoryDetail": "Display historical stock tracking information", "@stockItemHistoryDetail": {}, @@ -880,7 +880,7 @@ "@strictHttps": {}, "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "Subkategori", "@subcategory": {}, "subcategories": "Subcategories", "@subcategories": {}, @@ -970,7 +970,7 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Harga Unit", "@unitPrice": {}, "units": "Units", "@units": {}, @@ -986,7 +986,7 @@ "@usedIn": {}, "usedInDetails": "Assemblies which require this part", "@usedInDetails": {}, - "username": "Username", + "username": "Nama Pengguna", "@username": {}, "usernameEmpty": "Username cannot be empty", "@usernameEmpty": {}, diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index d572768..3a8dd6b 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -166,7 +166,7 @@ "@configureServer": {}, "confirmScan": "Подтвердить перенос", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Подтвердите детали перевода по складу при сканировании штрих-кодов", "connectionRefused": "Отказано в подключении", "@connectionRefused": {}, "count": "Количество", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 638e8f6..2aaefd0 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -166,7 +166,7 @@ "@configureServer": {}, "confirmScan": "Confirm Transfer", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Підтверджувати інформацію про передавання запасів під час сканування штрих-кодів", "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -253,13 +253,13 @@ "@errorFetch": {}, "errorUserRoles": "Error requesting user roles from server", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Помилка запиту даних плагіна з сервера", "@errorPluginInfo": {}, "errorReporting": "Error Reporting", "@errorReporting": {}, "errorReportUpload": "Upload Error Reports", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Вивантажувати анонімні звіти про помилки та журнали помилок", "@errorReportUploadDetails": {}, "feedback": "Feedback", "@feedback": {}, @@ -322,7 +322,7 @@ "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Показувати кнопку замовлення на домашньому екрані", "@homeShowPoDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, @@ -338,7 +338,7 @@ "@homeShowSupplierDescription": {}, "homeShowManufacturers": "Show Manufacturers", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Показувати кнопку виробника на головному екрані", "@homeShowManufacturersDescription": {}, "homeShowCustomers": "Show Customers", "@homeShowCustomers": {}, @@ -444,7 +444,7 @@ "@login": {}, "loginEnter": "Enter login details", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Ім'я користувача та пароль не зберігаються локально", "@loginEnterDetails": {}, "link": "Link", "@link": {}, @@ -562,7 +562,7 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Ваш обліковий запис не має необхідних прав для виконання цієї дії", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, @@ -662,7 +662,7 @@ }, "reportBug": "Report Bug", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "Відправити звіт про помилку (потрібен обліковий запис GitHub)", "@reportBugDescription": {}, "results": "Results", "@results": {}, @@ -738,7 +738,7 @@ "@scanIntoLocationDetail": {}, "scannerExternal": "External Scanner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Використовувати зовнішній сканер для читання штрих-кодів (wedge режим)", "@scannerExternalDetail": {}, "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, @@ -794,7 +794,7 @@ "@serverError": {}, "serverDetails": "Server Details", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "На сервері відсутні обов'язкові поля для відповіді", "@serverMissingData": {}, "serverOld": "Old Server Version", "@serverOld": {}, @@ -846,7 +846,7 @@ "@stockItemCreateDetail": {}, "stockItemDelete": "Delete Stock Item", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Ви впевнені, що хочете видалити цей товар?", "@stockItemDeleteConfirm": {}, "stockItemDeleteFailure": "Could not delete stock item", "@stockItemDeleteFailure": {}, @@ -854,7 +854,7 @@ "@stockItemDeleteSuccess": {}, "stockItemHistory": "Stock History", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Відображення історичної інформації відстеження запасів", "@stockItemHistoryDetail": {}, "stockItemTransferred": "Stock item transferred", "@stockItemTransferred": {}, @@ -878,7 +878,7 @@ "@stockTopLevel": {}, "strictHttps": "Use Strict HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Застосувати обмежену перевірку HTTP-сертифікатів", "@strictHttpsDetails": {}, "subcategory": "Subcategory", "@subcategory": {}, From 538a3d6ff6bdced1c4812acab73a7bc21bf2179a Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 27 Sep 2024 23:08:46 +1000 Subject: [PATCH 501/746] Allow null values for decimal fields (#539) * Allow null values for decimal fields - fixes https://github.com/inventree/inventree-app/issues/538 * Update release notes * Fix initial value --- assets/release_notes.md | 5 +++++ lib/api_form.dart | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index ad1449e..e195b37 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.16.5 - September 2024 +--- + +- Allow blank values to be entered into numerical fields + ### 0.16.4 - September 2024 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index e5278b8..9522280 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -471,7 +471,14 @@ class APIFormField { // Construct a floating point numerical input field Widget _constructFloatField() { - double initial = double.tryParse(value.toString()) ?? 0; + // Initial value: try to cast to a valid number + String initial = ""; + + double? initialNumber = double.tryParse(value.toString()); + + if (initialNumber != null) { + initial = simpleNumberString(initialNumber); + } return TextFormField( decoration: InputDecoration( @@ -481,9 +488,15 @@ class APIFormField { helperStyle: _helperStyle(), hintText: placeholderText, ), - initialValue: simpleNumberString(initial), + initialValue: initial, keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), validator: (value) { + value = value?.trim() ?? ""; + + // Allow empty numbers, *if* this field is not required + if (value.isEmpty && !required) { + return null; + } double? quantity = double.tryParse(value.toString()); From 29948e5809eda036895f7dc41c93fdd6692d9e4f Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 28 Sep 2024 22:48:18 +1000 Subject: [PATCH 502/746] Version bump (#540) * Update ios project details * Update version number --- assets/release_notes.md | 1 + ios/Runner.xcodeproj/project.pbxproj | 3 +++ pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e195b37..43b58e3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Allow blank values to be entered into numerical fields +- Updated translations ### 0.16.4 - September 2024 --- diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3b4c00d..fbc94f1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -399,6 +399,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; @@ -490,6 +491,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -542,6 +544,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; diff --git a/pubspec.yaml b/pubspec.yaml index d2505d2..9c07d45 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.4+90 +version: 0.16.5+91 environment: sdk: ">=2.19.5 <3.13.0" From d99050823789b0b05e33a2e18c3cb6576e7bf29c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 1 Oct 2024 12:25:11 +1000 Subject: [PATCH 503/746] Update Requirements (#541) * Update package requiremenst * github workflow updates * ios build updates * Theme adjustments * Further updates * Fix typo * Deprecated imperative apply of Flutter's Gradle plugins Ref: https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply * Refactor wedge scanner * Add context checks * Adjust behaviour if testing * Further refactoring * Moar checks * Logic fix * Fix for wedge scanner test * Fix for barcode processing * Fix * Yet another fix --- .github/workflows/android.yaml | 2 +- .github/workflows/ci.yaml | 2 +- .github/workflows/ios.yaml | 2 +- android/app/build.gradle | 16 +- android/build.gradle | 14 - android/settings.gradle | 30 +- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile | 4 +- ios/Runner.xcodeproj/project.pbxproj | 7 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- lib/api.dart | 2 +- lib/app_colors.dart | 28 +- lib/barcode/barcode.dart | 51 +- lib/barcode/controller.dart | 9 +- lib/barcode/flutter_barcode_listener.dart | 175 ------ lib/barcode/stock.dart | 2 +- lib/barcode/wedge_controller.dart | 68 ++- lib/helpers.dart | 33 +- lib/inventree/sentry.dart | 21 +- lib/l10.dart | 19 +- lib/main.dart | 8 +- lib/preferences.dart | 1 - lib/widget/dialogs.dart | 14 +- lib/widget/snacks.dart | 2 +- lib/widget/stock/location_display.dart | 10 +- pubspec.lock | 549 +++++++++--------- pubspec.yaml | 26 +- test/wedge_scanner_test.dart | 2 +- 28 files changed, 519 insertions(+), 582 deletions(-) delete mode 100644 lib/barcode/flutter_barcode_listener.dart diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 0699224..16c06b7 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -23,7 +23,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.13.0' + flutter-version: '3.24.3' channel: 'stable' - run: flutter --version - name: Setup Gradle diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 889cad0..f5e5bcf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -36,7 +36,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.13.0' + flutter-version: '3.24.3' - name: Collect Translation Files run: | cd lib/l10n diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index f6bf24b..fc96cf0 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -25,7 +25,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.13.0' + flutter-version: '3.24.3' channel: 'stable' - name: Collect Translation Files run: | diff --git a/android/app/build.gradle b/android/app/build.gradle index c43c9bf..a20b12b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' @@ -21,10 +22,6 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { @@ -85,5 +82,4 @@ dependencies { androidTestImplementation 'com.android.support:multidex:2.0.1' implementation "androidx.core:core:1.9.0" implementation 'androidx.appcompat:appcompat:1.6.0' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } diff --git a/android/build.gradle b/android/build.gradle index 5ace051..346e552 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,17 +1,3 @@ -buildscript { - - ext.kotlin_version = '1.8.10' - - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} allprojects { repositories { diff --git a/android/settings.gradle b/android/settings.gradle index 5a2f14f..16ce359 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.4.1" apply false + id "org.jetbrains.kotlin.android" version "1.8.10" apply false } + +include ":app" \ No newline at end of file diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 74fd5d3..1c05085 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your projects -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -39,7 +39,7 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' end end end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index fbc94f1..3a6f42d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ 3B8B22940C363C2F0DDB698A /* Frameworks */, ); sourceTree = ""; + tabWidth = 5; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; @@ -167,7 +168,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -271,11 +272,9 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", - "${BUILT_PRODUCTS_DIR}/SentryPrivate/SentryPrivate.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/audioplayers_darwin/audioplayers_darwin.framework", "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", @@ -295,11 +294,9 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SentryPrivate.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers_darwin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826d..5e31d3d 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ barcodeFailure(String msg, dynamic extra) async { msg, success: false, onAction: () { - OneContext().showDialog( - builder: (BuildContext context) => SimpleDialog( - title: Text(L10().barcodeError), - children: [ - ListTile( - title: Text(L10().responseData), - subtitle: Text(extra.toString()) - ) - ] - ) - ); + if (hasContext()) { + OneContext().showDialog( + builder: (BuildContext context) => + SimpleDialog( + title: Text(L10().barcodeError), + children: [ + ListTile( + title: Text(L10().responseData), + subtitle: Text(extra.toString()) + ) + ] + ) + ); + } } ); } @@ -277,17 +281,20 @@ class BarcodeScanHandler extends BarcodeHandler { success: false, onAction: () { - OneContext().showDialog( - builder: (BuildContext context) => SimpleDialog( - title: Text(L10().unknownResponse), - children: [ - ListTile( - title: Text(L10().responseData), - subtitle: Text(data.toString()), - ) - ], - ) - ); + if (hasContext()) { + OneContext().showDialog( + builder: (BuildContext context) => + SimpleDialog( + title: Text(L10().unknownResponse), + children: [ + ListTile( + title: Text(L10().responseData), + subtitle: Text(data.toString()), + ) + ], + ) + ); + } } ); } diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index ad17aa6..559bac9 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import "package:inventree/helpers.dart"; import "package:one_context/one_context.dart"; import "package:inventree/preferences.dart"; @@ -43,7 +44,7 @@ class InvenTreeBarcodeControllerState extends State * Barcode data should be passed as a string */ Future handleBarcodeData(String? data) async { - + // Check that the data is valid, and this view is still mounted if (!mounted || data == null || data.isEmpty) { return; @@ -58,7 +59,11 @@ class InvenTreeBarcodeControllerState extends State processingBarcode = true; }); - BuildContext? context = OneContext.hasContext ? OneContext().context : null; + BuildContext? context; + + if (hasContext()) { + context = OneContext.hasContext ? OneContext().context : null; + } showLoadingOverlay(context); await pauseScan(); diff --git a/lib/barcode/flutter_barcode_listener.dart b/lib/barcode/flutter_barcode_listener.dart deleted file mode 100644 index c2b2845..0000000 --- a/lib/barcode/flutter_barcode_listener.dart +++ /dev/null @@ -1,175 +0,0 @@ - -/* - * Custom keyboard listener which allows the app to act as a keyboard "wedge", - * and intercept barcodes from any compatible scanner. - * - * Note: This code was copied from https://github.com/fuadreza/flutter_barcode_listener/blob/master/lib/flutter_barcode_listener.dart - * - * If that code becomes available on pub.dev, we can remove this file and reference that library - */ - -import "dart:async"; - -import "package:flutter/material.dart"; -import "package:flutter/services.dart"; - -typedef BarcodeScannedCallback = void Function(String barcode); - -/// This widget will listen for raw PHYSICAL keyboard events -/// even when other controls have primary focus. -/// It will buffer all characters coming in specifed `bufferDuration` time frame -/// that end with line feed character and call callback function with result. -/// Keep in mind this widget will listen for events even when not visible. -/// Windows seems to be using the [RawKeyDownEvent] instead of the -/// [RawKeyUpEvent], this behaviour can be managed by setting [useKeyDownEvent]. -class BarcodeKeyboardListener extends StatefulWidget { - - /// This widget will listen for raw PHYSICAL keyboard events - /// even when other controls have primary focus. - /// It will buffer all characters coming in specifed `bufferDuration` time frame - /// that end with line feed character and call callback function with result. - /// Keep in mind this widget will listen for events even when not visible. - const BarcodeKeyboardListener( - {Key? key, - - /// Child widget to be displayed. - required this.child, - - /// Callback to be called when barcode is scanned. - required Function(String) onBarcodeScanned, - - /// When experiencing issueswith empty barcodes on Windows, - /// set this value to true. Default value is `false`. - this.useKeyDownEvent = false, - - /// Maximum time between two key events. - /// If time between two key events is longer than this value - /// previous keys will be ignored. - Duration bufferDuration = hundredMs}) - : _onBarcodeScanned = onBarcodeScanned, - _bufferDuration = bufferDuration, - super(key: key); - - final Widget child; - final BarcodeScannedCallback _onBarcodeScanned; - final Duration _bufferDuration; - final bool useKeyDownEvent; - - @override - _BarcodeKeyboardListenerState createState() => _BarcodeKeyboardListenerState( - _onBarcodeScanned, _bufferDuration, useKeyDownEvent); -} - -const Duration aSecond = Duration(seconds: 1); -const Duration hundredMs = Duration(milliseconds: 100); -const String lineFeed = "\n"; - -class _BarcodeKeyboardListenerState extends State { - - _BarcodeKeyboardListenerState(this._onBarcodeScannedCallback, - this._bufferDuration, this._useKeyDownEvent) { - RawKeyboard.instance.addListener(_keyBoardCallback); - _keyboardSubscription = - _controller.stream.where((char) => char != null).listen(onKeyEvent); - } - - List _scannedChars = []; - DateTime? _lastScannedCharCodeTime; - late StreamSubscription _keyboardSubscription; - - final BarcodeScannedCallback _onBarcodeScannedCallback; - final Duration _bufferDuration; - - final _controller = StreamController(); - - final bool _useKeyDownEvent; - - bool _isShiftPressed = false; - void onKeyEvent(String? char) { - //remove any pending characters older than bufferDuration value - checkPendingCharCodesToClear(); - _lastScannedCharCodeTime = DateTime.now(); - if (char == lineFeed) { - _onBarcodeScannedCallback.call(_scannedChars.join()); - resetScannedCharCodes(); - } else { - //add character to list of scanned characters; - _scannedChars.add(char!); - } - } - - void checkPendingCharCodesToClear() { - if (_lastScannedCharCodeTime != null) { - if (_lastScannedCharCodeTime! - .isBefore(DateTime.now().subtract(_bufferDuration))) { - resetScannedCharCodes(); - } - } - } - - void resetScannedCharCodes() { - _lastScannedCharCodeTime = null; - _scannedChars = []; - } - - void addScannedCharCode(String charCode) { - _scannedChars.add(charCode); - } - - void _keyBoardCallback(RawKeyEvent keyEvent) { - if (keyEvent.logicalKey.keyId > 255 && - keyEvent.data.logicalKey != LogicalKeyboardKey.enter && - keyEvent.data.logicalKey != LogicalKeyboardKey.shiftLeft) return; - if ((!_useKeyDownEvent && keyEvent is RawKeyUpEvent) || - (_useKeyDownEvent && keyEvent is RawKeyDownEvent)) { - if (keyEvent.data is RawKeyEventDataAndroid) { - if (keyEvent.data.logicalKey == LogicalKeyboardKey.shiftLeft) { - _isShiftPressed = true; - } else { - if (_isShiftPressed) { - _isShiftPressed = false; - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataAndroid).codePoint).toUpperCase()); - } else { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataAndroid).codePoint)); - } - } - } else if (keyEvent.data is RawKeyEventDataFuchsia) { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataFuchsia).codePoint)); - } else if (keyEvent.data.logicalKey == LogicalKeyboardKey.enter) { - _controller.sink.add(lineFeed); - } else if (keyEvent.data is RawKeyEventDataWeb) { - _controller.sink.add(((keyEvent.data) as RawKeyEventDataWeb).keyLabel); - } else if (keyEvent.data is RawKeyEventDataLinux) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataLinux).keyLabel); - } else if (keyEvent.data is RawKeyEventDataWindows) { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataWindows).keyCode)); - } else if (keyEvent.data is RawKeyEventDataMacOs) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataMacOs).characters); - } else if (keyEvent.data is RawKeyEventDataIos) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataIos).characters); - } else { - _controller.sink.add(keyEvent.character); - } - } - } - - @override - Widget build(BuildContext context) { - return widget.child; - } - - @override - void dispose() { - _keyboardSubscription.cancel(); - _controller.close(); - RawKeyboard.instance.removeListener(_keyBoardCallback); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart index b084759..d230901 100644 --- a/lib/barcode/stock.dart +++ b/lib/barcode/stock.dart @@ -42,7 +42,7 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { final bool result = await onLocationScanned(_loc); - if (result && OneContext.hasContext) { + if (result && hasContext()) { OneContext().pop(); } return; diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart index b239c39..741cec1 100644 --- a/lib/barcode/wedge_controller.dart +++ b/lib/barcode/wedge_controller.dart @@ -1,11 +1,12 @@ import "package:flutter/material.dart"; +import "package:flutter/services.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/controller.dart"; import "package:inventree/barcode/handler.dart"; -import "package:inventree/barcode/flutter_barcode_listener.dart"; + import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; @@ -31,6 +32,12 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { bool get scanning => mounted && canScan; + final FocusNode _focusNode = FocusNode(); + + List _scannedCharacters = []; + + DateTime? _lastScanTime; + @override Future pauseScan() async { @@ -51,6 +58,45 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { } } + // Callback for a single key press / scan + void handleKeyEvent(KeyEvent event) { + + if (!scanning) { + return; + } + + // Look only for key-down events + if (event is! KeyDownEvent) { + return; + } + + // Ignore events without a character code + if (event.character == null) { + return; + } + + DateTime now = DateTime.now(); + + // Throw away old characters + if (_lastScanTime == null || _lastScanTime!.isBefore(now.subtract(Duration(milliseconds: 250)))) { + _scannedCharacters.clear(); + } + + _lastScanTime = now; + + if (event.character == "\n") { + if (_scannedCharacters.isNotEmpty) { + // Debug output required for unit testing + debug("scanned: ${_scannedCharacters.join()}"); + handleBarcodeData(_scannedCharacters.join()); + } + + _scannedCharacters.clear(); + } else { + _scannedCharacters.add(event.character!); + } + } + @override Widget build(BuildContext context) { @@ -66,8 +112,9 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { Spacer(flex: 5), Icon(TablerIcons.barcode, size: 64), Spacer(flex: 5), - BarcodeKeyboardListener( - useKeyDownEvent: true, + KeyboardListener( + autofocus: true, + focusNode: _focusNode, child: SizedBox( child: CircularProgressIndicator( color: scanning ? COLOR_ACTION : COLOR_PROGRESS @@ -75,13 +122,16 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { width: 64, height: 64, ), - onBarcodeScanned: (String barcode) { - debug("scanned: ${barcode}"); - if (scanning) { - // Process the barcode data - handleBarcodeData(barcode); - } + onKeyEvent: (event) { + handleKeyEvent(event); }, + // onBarcodeScanned: (String barcode) { + // debug("scanned: ${barcode}"); + // if (scanning) { + // // Process the barcode data + // handleBarcodeData(barcode); + // } + // }, ), Spacer(flex: 5), Padding( diff --git a/lib/helpers.dart b/lib/helpers.dart index 49a880d..993814f 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -39,13 +39,32 @@ bool debugContains(String msg, {bool raiseAssert = true}) { } } + if (!result) { + print("Debug does not contain expected string: '${msg}'"); + } + if (raiseAssert) { + assert(result); } return result; } + +bool isTesting() { + return Platform.environment.containsKey("FLUTTER_TEST"); +} + +bool hasContext() { + try { + return !isTesting() && OneContext.hasContext; + } catch (error) { + return false; + } +} + + /* * Display a debug message if we are in testing mode, or running in debug mode */ @@ -83,7 +102,7 @@ Future playAudioFile(String path) async { // Debug message for unit testing debug("Playing audio file: '${path}'"); - if (!OneContext.hasContext) { + if (!hasContext()) { return; } @@ -117,21 +136,13 @@ String renderCurrency(double? amount, String currency, {int decimals = 2}) { if (currency.isEmpty) return "-"; - CurrencyFormatterSettings backupSettings = CurrencyFormatterSettings( - symbol: "\$", - symbolSide: SymbolSide.left, - ); + CurrencyFormat fmt = CurrencyFormat.fromCode(currency.toLowerCase()) ?? CurrencyFormat.usd; String value = CurrencyFormatter.format( amount, - CurrencyFormatter.majors[currency.toLowerCase()] ?? backupSettings + fmt ); - // If we were not able to determine the currency - if (!CurrencyFormatter.majors.containsKey(currency.toLowerCase())) { - value += " ${currency}"; - } - return value; } diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 7484d71..34894ff 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,6 +1,7 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; +import "package:inventree/helpers.dart"; import "package:one_context/one_context.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; @@ -129,16 +130,16 @@ Future sentryReportMessage(String message, {Map? context}) } Sentry.configureScope((scope) { - scope.setExtra("server", server_info); - scope.setExtra("app", app_info); - scope.setExtra("device", device_info); + scope.setContexts("server", server_info); + scope.setContexts("app", app_info); + scope.setContexts("device", device_info); if (context != null) { - scope.setExtra("context", context); + scope.setContexts("context", context); } // Catch stacktrace data if possible - scope.setExtra("stacktrace", StackTrace.current.toString()); + scope.setContexts("stacktrace", StackTrace.current.toString()); }); try { @@ -203,7 +204,7 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr // Ensure we pass the 'source' of the error context["source"] = source; - if (OneContext.hasContext) { + if (hasContext()) { final ctx = OneContext().context; if (ctx != null) { @@ -213,10 +214,10 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr } Sentry.configureScope((scope) { - scope.setExtra("server", server_info); - scope.setExtra("app", app_info); - scope.setExtra("device", device_info); - scope.setExtra("context", context); + scope.setContexts("server", server_info); + scope.setContexts("app", app_info); + scope.setContexts("device", device_info); + scope.setContexts("context", context); }); Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { diff --git a/lib/l10.dart b/lib/l10.dart index 2b44f96..f5f6eec 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -4,18 +4,23 @@ import "package:flutter_gen/gen_l10n/app_localizations_en.dart"; import "package:one_context/one_context.dart"; import "package:flutter/material.dart"; +import "package:inventree/helpers.dart"; + // Shortcut function to reduce boilerplate! I18N L10() { - if (OneContext.hasContext) { - BuildContext? _ctx = OneContext().context; + // Testing mode - ignore context + if (!hasContext()) { + return I18NEn(); + } - if (_ctx != null) { - I18N? i18n = I18N.of(_ctx); + BuildContext? _ctx = OneContext().context; - if (i18n != null) { - return i18n; - } + if (_ctx != null) { + I18N? i18n = I18N.of(_ctx); + + if (i18n != null) { + return i18n; } } diff --git a/lib/main.dart b/lib/main.dart index 9359449..545c8cd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -162,13 +162,13 @@ class InvenTreeAppState extends State { return AdaptiveTheme( light: ThemeData( brightness: Brightness.light, - primarySwatch: Colors.lightBlue, - secondaryHeaderColor: Colors.blueGrey + colorSchemeSeed: Colors.lightBlueAccent, + useMaterial3: true, ), dark: ThemeData( brightness: Brightness.dark, - primarySwatch: Colors.lightBlue, - secondaryHeaderColor: Colors.blueGrey, + colorSchemeSeed: Colors.blue, + useMaterial3: true, ), initial: savedThemeMode ?? AdaptiveThemeMode.light, builder: (light, dark) => MaterialApp( diff --git a/lib/preferences.dart b/lib/preferences.dart index 4828a7a..2611418 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -3,7 +3,6 @@ import "dart:ui"; import "package:inventree/l10n/supported_locales.dart"; import "package:path_provider/path_provider.dart"; -import "package:sembast/sembast.dart"; import "package:sembast/sembast_io.dart"; import "package:path/path.dart"; diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index a06609d..b4cb5a2 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -31,6 +31,10 @@ Future choiceDialog(String title, List items, {Function? onSelecte ); } + if (!hasContext()) { + return; + } + OneContext().showDialog( builder: (BuildContext context) { return AlertDialog( @@ -63,6 +67,10 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; + if (!hasContext()) { + return; + } + OneContext().showDialog( builder: (BuildContext context) { return AlertDialog( @@ -176,6 +184,10 @@ Future showErrorDialog(String title, {String description = "", APIResponse } } + if (!hasContext()) { + return; + } + OneContext().showDialog( builder: (context) => SimpleDialog( title: ListTile( @@ -196,7 +208,7 @@ Future showErrorDialog(String title, {String description = "", APIResponse */ Future showServerError(String url, String title, String description) async { - if (!OneContext.hasContext) { + if (!hasContext()) { return; } diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index 66f5f15..c5a1aba 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -13,7 +13,7 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc debug("showSnackIcon: '${text}'"); // Escape quickly if we do not have context - if (!OneContext.hasContext) { + if (!hasContext()) { // Debug message for unit testing return; } diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 377325f..df29473 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -301,12 +301,16 @@ class _LocationDisplayState extends RefreshableState { // Serial number field is not required here fields.remove("serial"); + Map data = {}; + + if (location != null) { + data["location"] = location!.pk; + } + InvenTreeStockItem().createForm( context, L10().stockItemCreate, - data: { - "location": location != null ? location!.pk : null, - }, + data: data, fields: fields, onSuccess: (result) async { Map data = result as Map; diff --git a/pubspec.lock b/pubspec.lock index 66a55bd..6cd6d6f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,42 +5,47 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "52.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" adaptive_theme: dependency: "direct main" description: name: adaptive_theme - sha256: "2d9bfee4240cdfad1b169cb43ac38fb49487e7fe1cc845e2973d4cef1780c0f6" + sha256: f4ee609b464e5efc68131d9d15ba9aa1de4e3b5ede64be17781c6e19a52d637d url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.6.0" analyzer: dependency: transitive description: name: analyzer - sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.7.0" archive: dependency: transitive description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.6.1" args: dependency: transitive description: name: args - sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.0" async: dependency: transitive description: @@ -53,66 +58,66 @@ packages: dependency: "direct main" description: name: audioplayers - sha256: "61583554386721772f9309f509e17712865b38565a903c761f96b1115a979282" + sha256: c346ba5a39dc208f1bab55fc239855f573d69b0e832402114bf0b793622adc4d url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "6.1.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - sha256: dbdc9b7f2aa2440314c638aa55aadd45c7705e8340d5eddf2e3fb8da32d4ae2c + sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - sha256: "6aea96df1d12f7ad5a71d88c6d1b22a216211a9564219920124c16768e456e9d" + sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "6.0.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - sha256: "396b62ac62c92dd26c3bc5106583747f57a8b325ebd2b41e5576f840cfc61338" + sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "4.0.0" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - sha256: f7daaed4659143094151ecf6bacd927d29ab8acffba98c110c59f0b81ae51143 + sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "7.0.0" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: ec84fd46eed1577148ed4113f5998a36a18da4fce7170c37ce3e21b631393339 + sha256: "3609bdf0e05e66a3d9750ee40b1e37f2a622c4edb796cc600b53a90a30a2ace4" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "5.0.1" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: "1d3aaac98a192b8488167711ba1e67d8b96333e8d0572ede4e2912e5bbce69a3" + sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "4.0.0" back_button_interceptor: dependency: transitive description: name: back_button_interceptor - sha256: e47660f2178a4392eb72001f9594d3fdcb5efde93e59d2819d61fda499e781c8 + sha256: "8354b03320043db546e3f446af171faaa71384100486444113628f7db1e7fe9b" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "7.0.3" boolean_selector: dependency: transitive description: @@ -141,50 +146,50 @@ packages: dependency: transitive description: name: cached_network_image_web - sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" camera: dependency: "direct main" description: name: camera - sha256: e7ac55af24a890d20276821eb3c95857074d03b7de6f9892b99a205ee30bd179 + sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8 url: "https://pub.dev" source: hosted - version: "0.10.3" + version: "0.10.6" camera_android: dependency: transitive description: name: camera_android - sha256: e491c836147f60dd8a54cf3895fd2960e13b21b78a9d15b563a1b6c70894f142 + sha256: "32f04948a284b71d938fe275616faf4957d07f9b3aab8021bfc8c418301a289e" url: "https://pub.dev" source: hosted - version: "0.10.4" + version: "0.10.9+11" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "6a68c20593d4cd58974d555f74a48b244f9db28cc9156de57781122d11b8754b" + sha256: "7c28969a975a7eb2349bc2cb2dfe3ad218a33dba9968ecfb181ce08c87486655" url: "https://pub.dev" source: hosted - version: "0.9.11" + version: "0.9.17+3" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: b632be28e61d00a233f67d98ea90fd7041956f27a1c65500188ee459be60e15f + sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.8.0" camera_web: dependency: transitive description: name: camera_web - sha256: "496de93c5d462738ce991dbfe91fb19026f115ed36406700a20a380fb0018299" + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" url: "https://pub.dev" source: hosted - version: "0.3.1+1" + version: "0.3.5" characters: dependency: transitive description: @@ -197,10 +202,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" cli_util: dependency: transitive description: @@ -221,10 +226,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" convert: dependency: transitive description: @@ -237,26 +242,26 @@ packages: dependency: transitive description: name: coverage - sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5 url: "https://pub.dev" source: hosted - version: "1.6.3" + version: "1.9.2" cross_file: dependency: transitive description: name: cross_file - sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.3+4" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" cupertino_icons: dependency: "direct main" description: @@ -269,10 +274,10 @@ packages: dependency: "direct main" description: name: currency_formatter - sha256: "8fc2b612e465a4e886f5d8d3a7cec03cc3cabab617ef96bf54c70886c907f2c3" + sha256: "8d4e1762e226289e4abe902075d167029617553c913309b34a227c52c61dd063" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.2.1" datetime_picker_formfield: dependency: "direct main" description: @@ -285,18 +290,18 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: f52ab3b76b36ede4d135aab80194df8925b553686f0fa12226b4e2d658e45903 + sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 url: "https://pub.dev" source: hosted - version: "8.2.2" + version: "10.1.2" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 + sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" dropdown_search: dependency: "direct main" description: @@ -317,10 +322,10 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.3" file: dependency: transitive description: @@ -333,42 +338,42 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" + sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12" url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "8.1.2" file_selector_linux: dependency: transitive description: name: file_selector_linux - sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" url: "https://pub.dev" source: hosted - version: "0.9.2" + version: "0.9.2+1" file_selector_macos: dependency: transitive description: name: file_selector_macos - sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" + sha256: cb284e267f8e2a45a904b5c094d2ba51d0aabfc20b1538ab786d9ef7dc2bf75c url: "https://pub.dev" source: hosted - version: "0.9.3+1" + version: "0.9.4+1" file_selector_platform_interface: dependency: transitive description: name: file_selector_platform_interface - sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.6.2" file_selector_windows: dependency: transitive description: name: file_selector_windows - sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69" url: "https://pub.dev" source: hosted - version: "0.9.3" + version: "0.9.3+2" flutter: dependency: "direct main" description: flutter @@ -399,18 +404,18 @@ packages: dependency: "direct main" description: name: flutter_localized_locales - sha256: f219350dffcfd56692b4e41953710c2975888dd9c507d977ec6853d7ea140336 + sha256: "478d10535edf07292e34cb4c757882edeeaf96d5e3dbb04b42733038bd41dd3f" url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.0.5" flutter_markdown: dependency: "direct main" description: name: flutter_markdown - sha256: "21b085a1c185e46701373866144ced56cfb7a0c33f63c916bb8fe2d0c1491278" + sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504" url: "https://pub.dev" source: hosted - version: "0.6.19" + version: "0.6.23" flutter_overlay_loader: dependency: "direct main" description: @@ -423,10 +428,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8ffe990dac54a4a5492747added38571a5ab474c8e5d196809ea08849c69b1bb" + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.0.22" flutter_speed_dial: dependency: "direct main" description: @@ -447,10 +452,10 @@ packages: dependency: "direct main" description: name: flutter_tabler_icons - sha256: a1dd0221ab8c77ee15046b8da8feac5ba129b5efd2b667e199c110cf930693b3 + sha256: "657c2201e12fa9121a12ddb4edb74d69290f803868eb6526f04102e6d49ec882" url: "https://pub.dev" source: hosted - version: "1.35.0" + version: "1.43.0" flutter_test: dependency: "direct dev" description: flutter @@ -465,26 +470,26 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" http: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -513,66 +518,66 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "1f498d086203360cca099d20ffea2963f48c39ce91bdd8a3b6d4a045786b02c8" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "8179b54039b50eee561676232304f487602e2950ffb3e8995ed9034d6505ca34" + sha256: c0a6763d50b354793d0192afd0a12560b823147d3ded7c6b77daf658fa05cc85 url: "https://pub.dev" source: hosted - version: "0.8.7+4" + version: "0.8.12+13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "8b6c160cdbe572199103a091c783685b236110e4a0fd7a4947f32ff5b7da8765" + sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.5" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 + sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" url: "https://pub.dev" source: hosted - version: "0.8.9+1" + version: "0.8.12" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.2.1+1" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.2.1+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: c1134543ae2187e85299996d21c526b2f403854994026d575ae4cf30d7bb2a32 + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.2.1+1" infinite_scroll_pagination: dependency: "direct main" description: @@ -585,10 +590,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -609,98 +614,130 @@ packages: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lint: dependency: "direct dev" description: name: lint - sha256: f4bd4dbaa39f4ae8836f2d1275f2f32bc68b3a8cce0a0735dd1f7a601f06682a + sha256: d758a5211fce7fd3f5e316f804daefecdc34c7e53559716125e6da7388ae8565 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.3.0" logging: dependency: transitive description: name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" markdown: dependency: transitive description: name: markdown - sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.6" node_preamble: dependency: transitive description: name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" octo_image: dependency: transitive description: name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" one_context: dependency: "direct main" description: name: one_context - sha256: db39c05e68a0f8dabb68072eab31e21912a5f4933db24eabc2b1af8a02d221e2 + sha256: "40607e6cf85d95dc81ee037788857a943784d37dfc04a40904a140328745e0af" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "4.0.0" open_filex: dependency: "direct main" description: name: open_filex - sha256: "74e2280754cf8161e860746c3181db2c996d6c1909c7057b738ede4a469816b8" + sha256: ba425ea49affd0a98a234aa9344b9ea5d4c4f7625a1377961eae9fe194c3d523 url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.0" package_config: dependency: transitive description: @@ -713,50 +750,50 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745" + sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "8.0.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" path: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "51f0d2c554cfbc9d6a312ab35152fc77e2f0b758ce9f1a444a3a1e5b8f3c6b7f" + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.10" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -769,50 +806,42 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "6.0.2" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.4" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 - url: "https://pub.dev" - source: hosted - version: "3.6.2" + version: "2.1.8" pool: dependency: transitive description: @@ -821,22 +850,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" qr_code_scanner: dependency: "direct main" description: @@ -845,14 +866,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" - quiver: - dependency: transitive - description: - name: quiver - sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 - url: "https://pub.dev" - source: hosted - version: "3.2.1" rxdart: dependency: transitive description: @@ -865,114 +878,114 @@ packages: dependency: "direct main" description: name: sembast - sha256: "9a9f0c7aca07043fef857b8b365f41592e48832b61462292699b57978e241c11" + sha256: "934a7b99297fb4f0b6e69fb1465286737b3b47b1a5149bf8dfc85667fbbdd21d" url: "https://pub.dev" source: hosted - version: "3.6.0" + version: "3.7.4+3" sentry: dependency: transitive description: name: sentry - sha256: "39c23342fc96105da449914f7774139a17a0ca8a4e70d9ad5200171f7e47d6ba" + sha256: "033287044a6644a93498969449d57c37907e56f5cedb17b88a3ff20a882261dd" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "8.9.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: ff68ab31918690da004a42e20204242a3ad9ad57da7e2712da8487060ac9767f + sha256: "3780b5a0bb6afd476857cfbc6c7444d969c29a4d9bd1aa5b6960aa76c65b737a" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "8.9.0" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.2" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.5.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shelf: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" shelf_static: dependency: transitive description: name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -990,18 +1003,18 @@ packages: dependency: transitive description: name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" source_maps: dependency: transitive description: name: source_maps - sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" url: "https://pub.dev" source: hosted - version: "0.10.11" + version: "0.10.12" source_span: dependency: transitive description: @@ -1014,34 +1027,34 @@ packages: dependency: transitive description: name: sqflite - sha256: "78324387dc81df14f78df06019175a86a2ee0437624166c382e145d0a7fd9a4f" + sha256: ff5a2436ef8ebdfda748fbfe957f9981524cb5ff11e7bafa8c42771840e8a788 url: "https://pub.dev" source: hosted - version: "2.2.4+1" + version: "2.3.3+2" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: bfd6973aaeeb93475bc0d875ac9aefddf7965ef22ce09790eb963992ffc5183f + sha256: "2d8e607db72e9cb7748c9c6e739e2c9618320a5517de693d5a24609c4671b1a4" url: "https://pub.dev" source: hosted - version: "2.4.2+2" + version: "2.5.4+4" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1062,10 +1075,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -1078,106 +1091,98 @@ packages: dependency: "direct dev" description: name: test - sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.24.3" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.5.3" + version: "0.6.4" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" - universal_io: - dependency: transitive - description: - name: universal_io - sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" - url: "https://pub.dev" - source: hosted - version: "2.2.0" + version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.10" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4aca1e060978e19b2998ee28503f40b5ba6226819c2b5e3e4d1821e8ccd92198" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" uuid: dependency: transitive description: @@ -1198,74 +1203,90 @@ packages: dependency: transitive description: name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "14.2.5" watcher: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" web: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "3.0.1" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" win32: dependency: transitive description: name: win32 - sha256: dd8f9344bc305ae2923e3d11a2a911d9a4e2c7dd6fe0ed10626d63211a69676e + sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "5.5.4" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + url: "https://pub.dev" + source: hosted + version: "1.1.5" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.0.4" xml: dependency: transitive description: name: xml - sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.5.0" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=3.1.0 <3.13.0" - flutter: ">=3.13.0" + dart: ">=3.5.0 <3.13.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9c07d45..0d17520 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,15 +8,15 @@ environment: dependencies: adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) - audioplayers: ^4.1.0 # Play audio files + audioplayers: ^6.1.0 # Play audio files cached_network_image: ^3.3.1 # Download and cache remote images camera: ^0.10.3 # Camera cupertino_icons: ^1.0.8 - currency_formatter: ^2.0.1 + currency_formatter: ^2.2.1 # Currency formatting datetime_picker_formfield: ^2.0.1 # Date / time picker - device_info_plus: ^8.2.2 # Information about the device + device_info_plus: ^10.1.2 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields - file_picker: ^5.3.1 # Select files from the device + file_picker: ^8.1.2 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 @@ -27,19 +27,19 @@ dependencies: flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation flutter_tabler_icons: ^1.35.0 - http: ^0.13.6 - image_picker: ^1.0.8 # Select or take photos + http: ^1.2.2 + image_picker: ^1.1.2 # Select or take photos infinite_scroll_pagination: ^4.0.0 # Let the server do all the work! - intl: ^0.18.0 - one_context: ^2.1.0 # Dialogs without requiring context - open_filex: ^4.4.0 # Open local files - package_info_plus: ^3.0.2 # App information introspection - path: ^1.8.2 + intl: ^0.19.0 + one_context: ^4.0.0 # Dialogs without requiring context + open_filex: ^4.5.0 # Open local files + package_info_plus: ^8.0.2 # App information introspection + path: ^1.9.0 path_provider: ^2.1.3 # Local file storage qr_code_scanner: ^1.0.1 # Barcode scanning sembast: ^3.6.0 # NoSQL data storage - sentry_flutter: 7.9.0 # Error reporting - url_launcher: ^6.2.4 # Open link in system browser + sentry_flutter: 8.9.0 # Error reporting + url_launcher: ^6.3.0 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.11.0 diff --git a/test/wedge_scanner_test.dart b/test/wedge_scanner_test.dart index c46f127..8cdca59 100644 --- a/test/wedge_scanner_test.dart +++ b/test/wedge_scanner_test.dart @@ -21,7 +21,7 @@ void main() { await simulateKeyDownEvent(LogicalKeyboardKey.keyA); await simulateKeyDownEvent(LogicalKeyboardKey.keyB); await simulateKeyDownEvent(LogicalKeyboardKey.keyC); - await simulateKeyDownEvent(LogicalKeyboardKey.enter); + await simulateKeyDownEvent(LogicalKeyboardKey.enter, character: "\n"); // Check debug output debugContains("scanned: abc"); From c0533db1381eb1644c1b0f4ddf73910a880a1462 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 6 Oct 2024 21:54:59 +1100 Subject: [PATCH 504/746] New Crowdin updates (#543) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Chinese Traditional) --- lib/l10n/id_ID/app_id_ID.arb | 14 +- lib/l10n/zh_TW/app_zh_TW.arb | 784 +++++++++++++++++------------------ 2 files changed, 399 insertions(+), 399 deletions(-) diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 287e4c7..6c02b85 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -279,7 +279,7 @@ "@filterComponent": {}, "filterComponentDetail": "Show component parts", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Eksternal", "@filterExternal": {}, "filterExternalDetail": "Show stock in external locations", "@filterExternalDetail": {}, @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Tidak Aktif", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Perusahaan ini ditandai sebagai perusahaan non-aktif", "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, @@ -418,7 +418,7 @@ "@lastStocktake": {}, "lastUpdated": "Last Updated", "@lastUpdated": {}, - "level": "Level", + "level": "Tingkat", "@level": {}, "lineItemAdd": "Add Line Item", "@lineItemAdd": {}, @@ -582,7 +582,7 @@ "@printLabelSuccess": {}, "profile": "Profil", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "Tambah Profil Server", "@profileAdd": {}, "profileConnect": "Sambung ke Server", "@profileConnect": {}, @@ -650,7 +650,7 @@ "@refreshing": {}, "rejected": "Ditolak", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "Catatan Rilis", "@releaseNotes": {}, "remove": "Hapus", "@remove": { @@ -798,7 +798,7 @@ "@serverMissingData": {}, "serverOld": "Old Server Version", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Pengaturan Server", "@serverSettings": {}, "serverStart": "Server must start with http[s]", "@serverStart": {}, @@ -814,7 +814,7 @@ "@shipments": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Terkirim", "@shipped": {}, "sku": "SKU", "@sku": {}, diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 58207b5..2b31105 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -34,15 +34,15 @@ "@appCredits": {}, "appDetails": "應用程式詳情", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "已分配", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "分配庫存", "@allocateStock": {}, "appReleaseNotes": "顯示應用程式發布說明", "@appReleaseNotes": {}, "appSettings": "程式設定", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "InvenTree 設定", "@appSettingsDetails": {}, "attachments": "附件", "@attachments": {}, @@ -56,73 +56,73 @@ "@attachmentNoneDetail": {}, "attachmentSelect": "選取附件", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "關注", "@attention": {}, "available": "可用", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "可用庫存", "@availableStock": {}, "barcodes": "條碼", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "條碼設置", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "設定條碼", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "掃描定制條碼以設置", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "條碼已設置", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "掃碼錯誤", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "條碼已被用過", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "回應中缺少條碼的哈希數", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "無匹配條碼", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "未設置條碼", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "掃描零件條碼", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "掃描條碼以接收零件", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "條碼掃描已暫停", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "點擊或按住以暫停掃描", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "掃描以設置條碼", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "掃碼器輸入", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "選擇掃碼器輸入來源", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "掃碼延遲設定", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "兩次掃碼之間的延遲時間", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "掃描 InvenTree 條碼", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "將庫存項目掃描進這個位置", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "掃描庫存地點", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "單掃模式", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "每次掃碼後暫停一下", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "已掃描至位置", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "未掃描物品", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "掃描庫存項目", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "條碼的音調", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "條碼取消設置", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "無法辨識條碼", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "批號", "@batchCode": {}, "billOfMaterials": "材料清單", "@billOfMaterials": {}, @@ -134,9 +134,9 @@ "@build": {}, "building": "生產中", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "內置相機", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "使用內置相機讀取條碼", "@cameraInternalDetail": {}, "cancel": "取消", "@cancel": { @@ -148,26 +148,26 @@ "@category": {}, "categoryCreate": "新增類別", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "新建零件類別", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "零件類別已更新", "@categoryUpdated": {}, "company": "公司", "@company": {}, "companyEdit": "編輯公司", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "沒有符合查詢的公司", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "公司詳情已更新", "@companyUpdated": {}, "companies": "公司", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "伺服器設定", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "確認轉移", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "confirmScanDetail": "掃描條碼時確認庫存轉移詳情", + "connectionRefused": "連線被拒", "@connectionRefused": {}, "count": "數量", "@count": { @@ -179,13 +179,13 @@ }, "credits": "感謝", "@credits": {}, - "customer": "Customer", + "customer": "客戶", "@customer": {}, "customers": "客戶", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "客戶編號", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "已損壞", "@damaged": {}, "darkMode": "深色模式", "@darkMode": {}, @@ -193,17 +193,17 @@ "@darkModeEnable": {}, "delete": "刪除", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "刪除失敗", "@deleteFailed": {}, "deletePart": "刪除零件", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "從數據庫中刪除此零件", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "刪除成功", "@deleteSuccess": {}, "description": "敘述", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "已損毀", "@destroyed": {}, "details": "詳細資訊", "@details": { @@ -221,19 +221,19 @@ }, "editCategory": "編輯類別", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "編輯位置", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "編輯備註", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "編輯參數", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "編輯零件", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "編輯庫存項目", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "編輯行項目", "@editLineItem": {}, "enterPassword": "輸入密碼", "@enterPassword": {}, @@ -243,29 +243,29 @@ "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "創建數據庫條目時出錯", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "刪除數據庫條目時出錯", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "錯誤詳情", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "從服務器獲取數據時出錯", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "從服務器請求用戶角色時出錯", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "從服務器請求插件數據時出錯", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "錯誤報告", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "上傳錯誤報告", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "上傳匿名錯誤報告和崩潰日誌", "@errorReportUploadDetails": {}, "feedback": "回饋", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "提交反饋時出現了一個錯誤", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "已提交回饋", "@feedbackSuccess": {}, "filterActive": "啟用", "@filterActive": {}, @@ -275,41 +275,41 @@ "@filterAssembly": {}, "filterAssemblyDetail": "顯示已組裝的零件", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "元件", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "顯示元件零件", "@filterComponentDetail": {}, "filterExternal": "外部", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "顯示外部倉庫的庫存", "@filterExternalDetail": {}, "filterInStock": "有貨", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "顯示有庫存的零件", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "已序列化", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "顯示已序列化的庫存物品", "@filterSerializedDetail": {}, "filterTemplate": "範本", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "顯示模板零件", "@filterTemplateDetail": {}, "filterTrackable": "可追蹤", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "顯示可追踪的零件", "@filterTrackableDetail": {}, "filterVirtual": "虛擬", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "顯示虛擬零件", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "篩選選項", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "格式異常", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "JSON 數據格式異常", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "表單錯誤", "@formError": {}, "history": "歷史", "@history": { @@ -318,31 +318,31 @@ "home": "首頁", "@homeScreen": {}, "homeScreen": "主畫面", - "homeScreenSettings": "Configure home screen settings", + "homeScreenSettings": "伺服器設定", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "顯示採購訂單", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "在主屏幕上顯示訂單按鈕", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "顯示銷售訂單", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "在主屏幕上顯示銷售訂單按鈕", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "訂閱零件通知", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "在主屏幕上顯示已訂閱的零件", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "顯示供應商", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "在主屏幕上顯示供應商按鈕", "@homeShowSupplierDescription": {}, "homeShowManufacturers": "顯示生產商", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "在主屏幕上顯示製造商按鈕", "@homeShowManufacturersDescription": {}, "homeShowCustomers": "顯示客戶", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "在主屏幕上顯示客户按鈕", "@homeShowCustomersDescription": {}, "imageUploadFailure": "圖片上傳失敗", "@imageUploadFailure": {}, @@ -350,117 +350,117 @@ "@imageUploadSuccess": {}, "inactive": "未啟用", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "此公司被標記為不活躍", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "此零件已被標為未激活", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "包含子分類", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "顯示子類別中的結果", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "包括次級位置", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "顯示次級位置中的結果", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "不完整的配置文件詳細信息", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "內部零件號", "@internalPartNumber": {}, "info": "資訊", "@info": {}, - "inProduction": "In Production", + "inProduction": "生產中的", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "該庫存物品正在生產中", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "內部零件", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "無效的主機名", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "提供的主機名無效", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "無效零件", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "無效零件類別", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "無效庫存地點", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "無效庫存項", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "無效的供應商零件", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "無效的用户名密碼組合", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "發行", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "發行日期", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "發行訂單", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "物品已就位", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "項目已移除", "@itemDeleted": {}, "keywords": "關鍵字", "@keywords": {}, "labelPrinting": "標籤印製", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "啓用標籤打印功能", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "標籤模板", "@labelTemplate": {}, "language": "語言", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "系統默認語言", "@languageDefault": {}, "languageSelect": "選擇語言", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "最近庫存盤點", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "最近更新", "@lastUpdated": {}, - "level": "Level", + "level": "級", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "添加行項目", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "行項目", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "行項目", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "行項目已更新", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "定位庫存項", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "定位存貨位置", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "新建倉儲位置", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "創建新庫存地點", "@locationCreateDetail": {}, - "locationNotSet": "No location specified", + "locationNotSet": "沒有指定倉儲位置", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "庫存地點已更新", "@locationUpdated": {}, - "login": "Login", + "login": "登入", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "輸入登錄詳情", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "用户名和密碼未存儲在本地", "@loginEnterDetails": {}, - "link": "Link", + "link": "鏈接", "@link": {}, - "lost": "Lost", + "lost": "丟失", "@lost": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "製造商零件號", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "製造商", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "製造商", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "缺失數據", "@missingData": {}, - "name": "Name", + "name": "名稱", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "未連接", "@notConnected": {}, "notes": "備註", "@notes": { @@ -468,542 +468,542 @@ }, "notifications": "通知", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "沒有未讀通知", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "服務器未響應", "@noResponse": {}, - "noResults": "No Results", + "noResults": "無結果", "@noResults": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "無子類別", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "無可用子類別", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "無效的數字", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "已訂購", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "當前訂購項目", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "屏幕方向​​​​​​​​​​​​​​", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "屏幕方向(需要重啓)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "橫向", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "縱向", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "系統", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "未完成", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "顯示未完成的訂單", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "逾期", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "顯示逾期訂單", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "打包", "@packaging": {}, - "packageName": "Package Name", + "packageName": "包名", "@packageName": {}, - "parameters": "Parameters", + "parameters": "參數", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "顯示零件參數", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "上級", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "上級類別", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "上級地點", "@parentLocation": {}, - "part": "Part", + "part": "零件", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "新零件", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "在此類別中創建新的零件", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "零件已更新", "@partEdited": {}, "parts": "零件", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "零件未被標記為可銷售", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "無零件", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "沒有匹配查詢的零件", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "零件設置", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "訂閲的零件", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "沒有可用的帶星號零件", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "零件供應商", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "零件類別", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "上一級零件類別", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "零件類別", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "零件詳情", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "零件註釋", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "零件庫存", "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "密碼", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "密碼不能為空", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "您的賬户沒有執行此操作所需的權限", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "需要授權:", "@permissionRequired": {}, - "printLabel": "Print Label", + "printLabel": "打印標籤", "@printLabel": {}, - "plugin": "Plugin", + "plugin": "插件", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "打印機", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "已啓用插件支持", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "服務器支持自定義插件", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "標籤打印失敗", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "標籤已發送到打印機", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "檔案", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "添加服務器配置文件", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "連接到服務器", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "編輯服務器配置文件", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "刪除服務器配置文件", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "登出配置文件", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "配置文件名稱", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "無可用配置文件", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "未選擇配置文件", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "選擇Inventree 服務器", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "選擇服務器或創建新的配置文件", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "點擊創建或選擇一個配置文件", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "項目編碼", "@projectCode": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "採購訂單", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "新採購訂單", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "編輯採購訂單", "@purchaseOrderEdit": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "採購訂單", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "採購訂單已更新", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "採購價格", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "數量", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "可用數量", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "容量為空", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "數量無效", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "數量必須大於0", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "輸入搜索查詢", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "無查詢結果", "@queryNoResults": {}, - "received": "Received", + "received": "已接收", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "顯示已收到的條目", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "接收條目", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "收到的庫存項", "@receivedItem": {}, - "reference": "Reference", + "reference": "參考", "@reference": {}, - "refresh": "Refresh", + "refresh": "刷新", "@refresh": {}, - "refreshing": "Refreshing", + "refreshing": "正在刷新", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "已拒絕", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "更新日誌", "@releaseNotes": {}, - "remove": "Remove", + "remove": "移除", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "移除庫存", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "反饋問題", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "提交 bug 報告 (需要 GitHub 賬户)", "@reportBugDescription": {}, - "results": "Results", + "results": "結果", "@results": {}, - "request": "Request", + "request": "請求", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "請求失敗", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "請求成功", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "正在請求數據", "@requestingData": {}, - "required": "Required", + "required": "必填", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "錯誤的請求", "@response400": {}, - "response401": "Unauthorized", + "response401": "未授權", "@response401": {}, - "response403": "Permission Denied", + "response403": "權限受限", "@response403": {}, - "response404": "Resource Not Found", + "response404": "資源未找到", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "方法不允許", "@response405": {}, - "response429": "Too Many Requests", + "response429": "太多請求", "@response429": {}, - "response500": "Internal Server Error", + "response500": "內部服務器錯誤", "@response500": {}, - "response501": "Not Implemented", + "response501": "未實施", "@response501": {}, - "response502": "Bad Gateway", + "response502": "不良網關", "@response502": {}, - "response503": "Service Unavailable", + "response503": "服務暫時不可用", "@response503": {}, - "response504": "Gateway Timeout", + "response504": "網關超時", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "HTTP版本不支持", "@response505": {}, - "responseData": "Response data", + "responseData": "響應數據", "@responseData": {}, - "responseInvalid": "Invalid Response Code", + "responseInvalid": "無效響應碼", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "未知響應", "@responseUnknown": {}, - "result": "Result", + "result": "結果", "@result": { "description": "" }, - "returned": "Returned", + "returned": "已退回", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "銷售訂單", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "銷售訂單", "@salesOrders": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "新的銷售訂單", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "編輯銷售訂單", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "銷售訂單已更新", "@salesOrderUpdated": {}, - "save": "Save", + "save": "保存", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "掃描條碼", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "掃描供應商條碼", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "已掃描至位置", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "掃描此項目到此位置", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "外部掃描器", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "使用外部掃描儀讀取條碼 (分割模式)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "掃描收到的零件", "@scanReceivedParts": {}, - "search": "Search", + "search": "搜索", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "搜索", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "搜索倉儲位置", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "搜索零件", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "搜索庫存", "@searchStock": {}, - "select": "Select", + "select": "選擇", "@select": {}, - "selectFile": "Select File", + "selectFile": "選擇文件", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "選擇圖片", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "選擇一個位置", "@selectLocation": {}, - "send": "Send", + "send": "發送", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "序列號", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "序列號", "@serialNumbers": {}, - "server": "Server", + "server": "服務器", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "服務器地址", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "需要的 API 版本", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "服務器 API 版本", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "授權出錯", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "信任錯誤", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "服務器 HTTPS 證書無效", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "已連接至服務器", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "正在連接服務器……", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "無法連接到服務器", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "服務器不能為空。", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "服務器錯誤", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "服務器詳情", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "服務器響應缺少必填字段", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "過時的服務器版本", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "服務器設置", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "服務器必須以 httpp[s] 開始", "@serverStart": {}, - "settings": "Settings", + "settings": "設置", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "服務器實例", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "未連接至服務器", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "未選定服務器", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "配送", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "添加配送", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "已配送", "@shipped": {}, - "sku": "SKU", + "sku": "庫存單位 (SKU)", "@sku": {}, - "sounds": "Sounds", + "sounds": "聲音", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "播放條碼動作音效", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "服務器錯誤時播放音效", "@soundOnServerError": {}, - "status": "Status", + "status": "狀態", "@status": {}, - "statusCode": "Status Code", + "statusCode": "狀態碼", "@statusCode": {}, "stock": "庫存", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "當前可用庫存數量", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "庫存項", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "庫存項", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "新建庫存項", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "在此位置創建新的庫存項", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "刪除庫存項", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "確定要刪除此庫存項嗎?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "無法刪除庫存項", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "庫存項已刪除", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "庫存歷史記錄", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "顯示歷史庫存追蹤信息", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "已轉移的庫存項", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "庫存項已更新", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "沒有可用的庫存項", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "庫存項註釋", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "庫存項已更新", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "庫存項更新失敗", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "庫存地點", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "庫存地點", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "頂級庫存地點", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "使用嚴格的 HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "強制嚴格檢查 HTTPs 證書", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "子類別", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "子類別", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "次級位置", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "次級位置", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "無子塊", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "無可用子塊", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "提交反饋", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "供應商零件", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "供應商", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "供應商零件", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "編輯供應商零件", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "供應商零件編號", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "供應商零件已更新", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "供應商零件", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "供應商", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "供應商參考", "@supplierReference": {}, - "takePicture": "Take Picture", + "takePicture": "拍照", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "預計日期", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "上級模板零件", "@templatePart": {}, - "testName": "Test Name", + "testName": "測試名", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "測試通過或失敗", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "所需測試", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "測試結果", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "顯示庫存項測試結果", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "添加測試結果", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "無測試結果", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "無可用測試結果", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "上傳測試結果出錯", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "測試結果上傳", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "超時", "@timeout": { "description": "" }, - "tokenError": "Token Error", + "tokenError": "令牌錯誤", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "缺少令牌", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "響應中缺少訪問令牌", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "總價", "@totalPrice": {}, - "transfer": "Transfer", + "transfer": "轉移", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "轉移庫存", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "將物品轉移到另一個位置", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "轉移庫存地點", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "將此庫存地點轉移到另一個", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "轉移", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "協助翻譯 InvenTree 應用", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "單價", "@unitPrice": {}, - "units": "Units", + "units": "單位", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "未知響應", "@unknownResponse": {}, - "upload": "Upload", + "upload": "上傳", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "文件上傳失敗", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "文件已上傳", "@uploadSuccess": {}, - "usedIn": "Used In", + "usedIn": "用途", "@usedIn": {}, - "usedInDetails": "Assemblies which require this part", + "usedInDetails": "需要此零件的裝配體", "@usedInDetails": {}, - "username": "Username", + "username": "用户名", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "用户名不能為空", "@usernameEmpty": {}, - "value": "Value", + "value": "值", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "數值不能為空", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "值為必填項", "@valueRequired": {}, - "variants": "Variants", + "variants": "變體", "@variants": {}, - "version": "Version", + "version": "版本", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "查看供應商零件", "@viewSupplierPart": {}, - "website": "Website", + "website": "網站", "@website": {} } \ No newline at end of file From 4a2e91a3712178d55d99da5089bbe9d24b066ec8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 16 Oct 2024 20:00:14 +1100 Subject: [PATCH 505/746] New translations app_en.arb (Vietnamese) (#545) --- lib/l10n/vi_VN/app_vi_VN.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 087f2b8..11926e6 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -350,7 +350,7 @@ "@imageUploadSuccess": {}, "inactive": "Không hoạt động", "@inactive": {}, - "inactiveCompany": "Đánh dáu không hoạt động cho công ty này", + "inactiveCompany": "Đánh dấu không hoạt động cho công ty này", "@inactiveCompany": {}, "inactiveDetail": "Phần này được đánh dấu là không hoạt động", "@inactiveDetail": {}, From 1a1521efe39314be2feebf0057236ecec2a07f45 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 20 Nov 2024 12:11:56 +1100 Subject: [PATCH 506/746] New Crowdin updates (#546) * New translations app_en.arb (Polish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Estonian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Italian) * New translations app_en.arb (Persian) * New translations app_en.arb (Danish) --- lib/l10n/da_DK/app_da_DK.arb | 156 +++++++------- lib/l10n/et_EE/app_et_EE.arb | 214 +++++++++---------- lib/l10n/fa_IR/app_fa_IR.arb | 6 +- lib/l10n/id_ID/app_id_ID.arb | 398 +++++++++++++++++------------------ lib/l10n/it_IT/app_it_IT.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 4 +- lib/l10n/uk_UA/app_uk_UA.arb | 2 +- lib/l10n/zh_TW/app_zh_TW.arb | 4 +- 8 files changed, 393 insertions(+), 393 deletions(-) diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index a0afda8..4d809d5 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -8,95 +8,95 @@ "@ok": { "description": "OK" }, - "about": "About", + "about": "Om", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "Kontodetaljer", "@accountDetails": {}, - "actions": "Actions", + "actions": "Handlinger", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "Ingen handlinger tilgængelige", "@actionsNone": {}, - "add": "Add", + "add": "Tilføj ", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "Tilføj Lagerbeholdning", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "Adresse", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "Om InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "Yderligere app kredit", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "Oplysninger om appen", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Tildelt", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Tildel lager", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": "Vis app-udgivelsesnoter", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "Appindstillinger", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "Konfigurer InvenTree app-indstillinger", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "Vedhæftede filer", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "Vedhæft billede", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "Ingen vedhæftning fundet", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "Ingen vedhæftning fundet", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "Vælg vedhæftede filer", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "Bemærk", "@attention": {}, - "available": "Available", + "available": "Tilgængelig", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "Tilgængelig Lager", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Stregkoder", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Stregkode Indstillinger", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "Tildel Stregkode", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Scan brugerdefineret stregkode, der skal tildeles", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "Stregkode tildelt", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "Fejl i stregkodeskanning", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "Stregkode allerede tildelt", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "Barcode hash data mangler fra respons", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "Intet match for stregkode", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "Stregkode ikke tildelt", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Skan del stregkode", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Scan stregkode for at modtage en del", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Stregkode skanning på pause", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tryk eller hold nede for at pause i skanningen", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "Scan for at tildele stregkode", "@barcodeScanAssign": {}, "barcodeScanController": "Scanner Input", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Vælg stregkodeskanners indgangskilde", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Forsinkelse Af Stregkode", "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Delay between barcode scans", "@barcodeScanDelayDetail": {}, @@ -199,45 +199,45 @@ "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Sletning lykkedes", "@deleteSuccess": {}, - "description": "Description", + "description": "Beskrivelse", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "Destrueret", "@destroyed": {}, - "details": "Details", + "details": "Detaljer", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "Dokumentation", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "Overfører fil", "@downloading": {}, - "downloadError": "Download Error", + "downloadError": "Fejl under download", "@downloadError": {}, - "edit": "Edit", + "edit": "Rediger", "@edit": { "description": "edit" }, - "editCategory": "Edit Category", + "editCategory": "Rediger kategori", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "Redigér placering", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "Redigér noter", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Redigér parameter", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "Rediger Del", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "Rediger Lagervare", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Rediger Linjeelement", "@editLineItem": {}, - "enterPassword": "Enter password", + "enterPassword": "Indtast adgangskode", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "Indtast brugernavn", "@enterUsername": {}, "error": "Error", "@error": { @@ -267,7 +267,7 @@ "@feedbackError": {}, "feedbackSuccess": "Feedback submitted", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Aktiv", "@filterActive": {}, "filterActiveDetail": "Show active parts", "@filterActiveDetail": {}, @@ -283,7 +283,7 @@ "@filterExternal": {}, "filterExternalDetail": "Show stock in external locations", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "På Lager", "@filterInStock": {}, "filterInStockDetail": "Show parts which have stock", "@filterInStockDetail": {}, @@ -299,7 +299,7 @@ "@filterTrackable": {}, "filterTrackableDetail": "Show trackable parts", "@filterTrackableDetail": {}, - "filterVirtual": "Virtual", + "filterVirtual": "Virtuel", "@filterVirtual": {}, "filterVirtualDetail": "Show virtual parts", "@filterVirtualDetail": {}, @@ -309,20 +309,20 @@ "@formatException": {}, "formatExceptionJson": "JSON data format exception", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Formular Fejl", "@formError": {}, - "history": "History", + "history": "Historik", "@history": { "description": "history" }, - "home": "Home", + "home": "Hjem", "@homeScreen": {}, - "homeScreen": "Home Screen", - "homeScreenSettings": "Configure home screen settings", + "homeScreen": "Startskærm", + "homeScreenSettings": "Konfigurér indstillinger for startskærmen", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Vis Indkøbsordrer", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Vis indkøbsordreknap på startskærmen", "@homeShowPoDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, @@ -332,7 +332,7 @@ "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Vis Leverandører", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, @@ -348,7 +348,7 @@ "@imageUploadFailure": {}, "imageUploadSuccess": "Image uploaded", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Inaktiv", "@inactive": {}, "inactiveCompany": "This company is marked as inactive", "@inactiveCompany": {}, @@ -368,27 +368,27 @@ "@internalPartNumber": {}, "info": "Info", "@info": {}, - "inProduction": "In Production", + "inProduction": "I Produktion", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "Denne lagervare er i produktion", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Intern Del", "@internalPart": {}, "invalidHost": "Invalid hostname", "@invalidHost": {}, "invalidHostDetails": "Provided hostname is not valid", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "Ugyldig Del", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "Ugyldig Del Kategori", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "Ugyldig Lagerplacering", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "Ugyldig Lagervare", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Ugyldig Leverandørdel", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "Ugyldigt brugernavn/adgangskode-kombination", "@invalidUsernamePassword": {}, "issue": "Issue", "@issue": {}, diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index c5b340b..e59caad 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -52,7 +52,7 @@ }, "attachmentNone": "Manust pole", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "Manuseid ei leitud", "@attachmentNoneDetail": {}, "attachmentSelect": "Valige manus", "@attachmentSelect": {}, @@ -62,7 +62,7 @@ "@available": {}, "availableStock": "Available Stock", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "Vöötkoodid", "@barcodes": {}, "barcodeSettings": "Barcode Settings", "@barcodeSettings": {}, @@ -92,7 +92,7 @@ "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Skänneri sisend", "@barcodeScanController": {}, "barcodeScanControllerDetail": "Select barcode scanner input source", "@barcodeScanControllerDetail": {}, @@ -169,7 +169,7 @@ "confirmScanDetail": "Kinnitage laoseisu ülekande üksikasjad vöötkoodide skaneerimisel", "connectionRefused": "Connection Refused", "@connectionRefused": {}, - "count": "Count", + "count": "Kogus", "@count": { "description": "Count" }, @@ -179,13 +179,13 @@ }, "credits": "Credits", "@credits": {}, - "customer": "Customer", + "customer": "Klient", "@customer": {}, - "customers": "Customers", + "customers": "Kliendid", "@customers": {}, "customerReference": "Customer Reference", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Kahjustatud", "@damaged": {}, "darkMode": "Tume režiim", "@darkMode": {}, @@ -195,23 +195,23 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, - "deletePart": "Delete Part", + "deletePart": "Kustuta osa", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, - "description": "Description", + "description": "Kirjeldus", "@description": {}, "destroyed": "Destroyed", "@destroyed": {}, - "details": "Details", + "details": "Üksikasjad", "@details": { "description": "details" }, "documentation": "Dokumendid", "@documentation": {}, - "downloading": "Downloading File", + "downloading": "Faili allalaadimine", "@downloading": {}, "downloadError": "Allalaadimise viga", "@downloadError": {}, @@ -219,15 +219,15 @@ "@edit": { "description": "edit" }, - "editCategory": "Edit Category", + "editCategory": "Muuda kategooriat", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "Muuda asukohta", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "Muuda märkmeid", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Muuda parameetrit", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "Muuda osa", "@editPart": { "description": "edit part" }, @@ -235,9 +235,9 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, - "enterPassword": "Enter password", + "enterPassword": "Sisesta parool", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "Sisesta kasutajanimi", "@enterUsername": {}, "error": "Viga", "@error": { @@ -261,7 +261,7 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, - "feedback": "Feedback", + "feedback": "Tagasiside", "@feedback": {}, "feedbackError": "Error submitting feedback", "@feedbackError": {}, @@ -275,11 +275,11 @@ "@filterAssembly": {}, "filterAssemblyDetail": "Show assembled parts", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Komponent", "@filterComponent": {}, "filterComponentDetail": "Show component parts", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Väline", "@filterExternal": {}, "filterExternalDetail": "Show stock in external locations", "@filterExternalDetail": {}, @@ -311,13 +311,13 @@ "@formatExceptionJson": {}, "formError": "Form Error", "@formError": {}, - "history": "History", + "history": "Ajalugu", "@history": { "description": "history" }, "home": "Avaleht", "@homeScreen": {}, - "homeScreen": "Home Screen", + "homeScreen": "Koduekraan", "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -332,25 +332,25 @@ "@homeShowSubscribed": {}, "homeShowSubscribedDescription": "Show subscribed parts on home screen", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Näita tarnijaid", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Näita avalehel tarnijate nuppu", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "Näita tootjaid", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Näita avalehel tootjate nuppu", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Näita kliente", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Näita avalehel klientide nuppu", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Pildi üleslaadimine ebaõnnestus", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Pilt on üles laaditud", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Mitteaktiivne", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "See ettevõte on märgitud mitteaktiivseks", "@inactiveCompany": {}, "inactiveDetail": "This part is marked as inactive", "@inactiveDetail": {}, @@ -400,7 +400,7 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, - "keywords": "Keywords", + "keywords": "Märksõnad", "@keywords": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, @@ -408,17 +408,17 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, - "language": "Language", + "language": "Keel", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Süsteemi vaikimisi keel", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Vali keel", "@languageSelect": {}, "lastStocktake": "Last Stocktake", "@lastStocktake": {}, "lastUpdated": "Last Updated", "@lastUpdated": {}, - "level": "Level", + "level": "Tase", "@level": {}, "lineItemAdd": "Add Line Item", "@lineItemAdd": {}, @@ -432,7 +432,7 @@ "@locateItem": {}, "locateLocation": "Locate stock location", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Uus asukoht", "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, @@ -448,7 +448,7 @@ "@loginEnterDetails": {}, "link": "Link", "@link": {}, - "lost": "Lost", + "lost": "Kadunud", "@lost": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, @@ -462,23 +462,23 @@ "@name": {}, "notConnected": "Not Connected", "@notConnected": {}, - "notes": "Notes", + "notes": "Märkmed", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Teavitused", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Lugemata teavitusi pole", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Server ei vasta", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Tulemusi pole", "@noResults": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Alamkategooriaid pole", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Ühtegi alamkategooriat pole saadaval", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Vigane number", "@numberInvalid": {}, "onOrder": "On Order", "@onOrder": {}, @@ -502,7 +502,7 @@ "@overdue": {}, "overdueDetail": "Show overdue orders", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Pakkimine", "@packaging": {}, "packageName": "Package Name", "@packageName": {}, @@ -520,13 +520,13 @@ "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Uus osa", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Loo selles kategoorias uus osa", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Osa on uuendatud", "@partEdited": {}, - "parts": "Parts", + "parts": "Osad", "@parts": { "description": "Part (multiple)" }, @@ -558,7 +558,7 @@ "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "Parool", "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, @@ -604,7 +604,7 @@ "@profileSelectOrCreate": {}, "profileTapToCreate": "Tap to create or select a profile", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Projekti kood", "@projectCode": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, @@ -624,11 +624,11 @@ }, "quantityAvailable": "Quantity Available", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Kogus on tühi", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Kogus on vigane", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Kogus peab olema positiivne", "@quantityPositive": {}, "queryEmpty": "Enter search query", "@queryEmpty": {}, @@ -642,7 +642,7 @@ "@receiveItem": {}, "receivedItem": "Received Stock Item", "@receivedItem": {}, - "reference": "Reference", + "reference": "Viide", "@reference": {}, "refresh": "Värskenda", "@refresh": {}, @@ -664,7 +664,7 @@ "@reportBug": {}, "reportBugDescription": "Submit bug report (requires GitHub account)", "@reportBugDescription": {}, - "results": "Results", + "results": "Tulemused", "@results": {}, "request": "Request", "@request": {}, @@ -708,11 +708,11 @@ "@responseInvalid": {}, "responseUnknown": "Unknown Response", "@responseUnknown": {}, - "result": "Result", + "result": "Tulemus", "@result": { "description": "" }, - "returned": "Returned", + "returned": "Tagastatud", "@returned": {}, "salesOrder": "Sales Order", "@salesOrder": {}, @@ -736,17 +736,17 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scan this item into location", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Väline skänner", "@scannerExternal": {}, "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", "@scannerExternalDetail": {}, "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, - "search": "Search", + "search": "Otsi", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Otsimine", "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, @@ -756,51 +756,51 @@ "@searchStock": {}, "select": "Vali", "@select": {}, - "selectFile": "Select File", + "selectFile": "Vali fail", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Vali pilt", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Vali asukoht", "@selectLocation": {}, "send": "Saada", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Seerianumber", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Seerianumbrid", "@serialNumbers": {}, "server": "Server", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Serveri aadress", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Nõutud API versioon", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Serveri API versioon", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Autentimise viga", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Sertifikaadi viga", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Serveri HTTPS sertifikaat on vigane", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Ühendatud serveriga", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Serveriga ühendamine", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Ühenduse loomine serveriga ebaõnnestus", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Serveri lahter ei saa olla tühi", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Serveri tõrge", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Serveri üksikasjad", "@serverDetails": {}, "serverMissingData": "Server response missing required fields", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Vana serveri versioon", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Serveri seaded", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Server peab algama eesliitega http[s]", "@serverStart": {}, "settings": "Seaded", "@settings": {}, @@ -808,15 +808,15 @@ "@serverInstance": {}, "serverNotConnected": "Server not connected", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Serverite pole valitud", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Saadetised", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Lisa saadetis", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Saadetud", "@shipped": {}, - "sku": "SKU", + "sku": "Tootekood", "@sku": {}, "sounds": "Sounds", "@sounds": {}, @@ -824,9 +824,9 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Play audible tone on server error", "@soundOnServerError": {}, - "status": "Status", + "status": "Staatus", "@status": {}, - "statusCode": "Status Code", + "statusCode": "Olekukood", "@statusCode": {}, "stock": "Ladu", "@stock": { @@ -880,9 +880,9 @@ "@strictHttps": {}, "strictHttpsDetails": "Kohusta ranget HTTPS-sertifikaatide kontrollimist", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "Alamkategooria", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "Alamkategooriad", "@subcategories": {}, "sublocation": "Sublocation", "@sublocation": {}, @@ -940,7 +940,7 @@ "@testResultUploadFail": {}, "testResultUploadPass": "Test result uploaded", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "Aegumine", "@timeout": { "description": "" }, @@ -968,19 +968,19 @@ "@transferStockLocationDetail": {}, "translate": "Tõlgi", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "Aita InvenTree rakendust tõlkida", "@translateHelp": {}, - "unitPrice": "Unit Price", + "unitPrice": "Ühiku hind", "@unitPrice": {}, - "units": "Units", + "units": "Ühikud", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "Tundmatu vastus", "@unknownResponse": {}, - "upload": "Upload", + "upload": "Laadi üles", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "Faili laadimine ebaõnnestus", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "Fail on üles laaditud", "@uploadSuccess": {}, "usedIn": "Used In", "@usedIn": {}, @@ -994,16 +994,16 @@ "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "Väärtus ei saa olla tühi", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "Väärtus on nõutud", "@valueRequired": {}, - "variants": "Variants", + "variants": "Variandid", "@variants": {}, - "version": "Version", + "version": "Versioon", "@version": {}, "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, - "website": "Website", + "website": "Koduleht", "@website": {} } \ No newline at end of file diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index ab5c064..724cdef 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -213,7 +213,7 @@ "@documentation": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", + "downloadError": "خطای بارگیری", "@downloadError": {}, "edit": "Edit", "@edit": { @@ -223,9 +223,9 @@ "@editCategory": {}, "editLocation": "Edit Location", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "ویرایش یادداشت‌ها", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "ویرایش پارامتر", "@editParameter": {}, "editPart": "Edit Part", "@editPart": { diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 6c02b85..7e014bb 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -30,31 +30,31 @@ "@address": {}, "appAbout": "Tentang InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "App kredit tambahan", "@appCredits": {}, "appDetails": "Rincian Aplikasi", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Dialokasikan", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Alokasikan Stok", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": "Tampilkan catatan rilis aplikasi", "@appReleaseNotes": {}, "appSettings": "Pengaturan Aplikasi", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "Konfigurasikan pengaturan aplikasi InvenTree", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "Lampiran", "@attachments": {}, "attachImage": "Melampirkan Gambar", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "Tidak ada lampiran yang ditemukan", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "Tidak ada lampiran yang ditemukan", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "Pilih lampiran", "@attachmentSelect": {}, "attention": "Perhatian", "@attention": {}, @@ -64,79 +64,79 @@ "@availableStock": {}, "barcodes": "Barcodes", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Pengaturan barcode", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "Tetapkan barcode", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Pindai barcode khusus untuk menetapkan", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "Barcode ditetapkan", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "Kesalahan Pemindaian barcode", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "Barcode telah ditetapkan", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "Data hash barcode hilang dari respons", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "Tidak ada kecocokan untuk barcode", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "Barcode tidak ditetapkan", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Pindai barcode Part", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Pindai barcode untuk menerima Part", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Pemindaian barcode dijeda", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Ketuk atau tahan untuk menjeda pemindaian", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "Pindai untuk menetapkan barcode", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Input pemindai", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Pilih sumber input pemindai barcode", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Penundaan Pemindaian barcode", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Penundaan antara pemindaian barcode", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "Pindai barcode InvenTree", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Pindai item stok ke lokasi ini", "@barcodeScanInItems": {}, "barcodeScanLocation": "", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Mode Pemindaian Tunggal", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Jeda pemindai barcode setelah setiap pemindaian", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "Dipindai ke lokasi", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "Item tidak dipindai di", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "Pindai item stok", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Nada barcode", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "Batalkan Penetapan barcode", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "barcode tidak dikenali", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "barcode batch", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "Daftar bahan", "@billOfMaterials": {}, - "bom": "BOM", + "bom": "Bill Of Materials", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Tampilkan Daftar Bahan Baku", "@bomEnable": {}, - "build": "Build", + "build": "Membangun", "@build": {}, - "building": "Building", + "building": "Bangunan", "@building": {}, "cameraInternal": "Kamera Internal", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Gunakan internal kamera untuk membaca barcode", "@cameraInternalDetail": {}, "cancel": "Batalkan", "@cancel": { @@ -148,62 +148,62 @@ "@category": {}, "categoryCreate": "Kategori Baru", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "Buat kategori Part baru", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Kategori Part diperbarui", "@categoryUpdated": {}, "company": "Perusahaan", "@company": {}, "companyEdit": "Rubah Perusahaan", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "Tidak ada perusahaan yang cocok dengan query", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "Detail perusahaan diperbarui", "@companyUpdated": {}, "companies": "Perusahaan", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "Konfigurasikan pengaturan server", "@configureServer": {}, "confirmScan": "Konfirmasi Transfer", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "confirmScanDetail": "Konfirmasikan detail transfer stok saat memindai barcode", + "connectionRefused": "Koneksi ditolak", "@connectionRefused": {}, - "count": "Count", + "count": "Hitung", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "Hitung stok", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "Kredit", "@credits": {}, "customer": "Pelanggan", "@customer": {}, "customers": "Pelanggan", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Refensi Pelanggan", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Rusak", "@damaged": {}, "darkMode": "Mode Gelap", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Aktifkan mode gelap", "@darkModeEnable": {}, "delete": "Hapus", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Operasi penghapusan gagal", "@deleteFailed": {}, - "deletePart": "Delete Part", + "deletePart": "Hapus Part", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "Hapus Part ini dari database", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Operasi penghapusan berhasil", "@deleteSuccess": {}, "description": "Deskripsi", "@description": {}, - "destroyed": "Destroyed", + "destroyed": "Hancur", "@destroyed": {}, "details": "Detail", "@details": { @@ -225,15 +225,15 @@ "@editLocation": {}, "editNotes": "Ubah Catatan", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Edit parameter", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "Edit part", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "Edit stok item", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Edit item baris", "@editLineItem": {}, "enterPassword": "Masukkan Kata Sandi", "@enterPassword": {}, @@ -243,73 +243,73 @@ "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "Kesalahan saat membuat entri database", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "Kesalahan saat menghapus entri database", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "Detail kesalahan", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "Kesalahan saat mengambil data dari server", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Kesalahan saat meminta peran pengguna dari server", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Kesalahan saat meminta data plugin dari server", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "Pelaporan kesalahan", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "Unggahan Laporan Kesalahan", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Unggah laporan kesalahan anonim dan log kerusakan", "@errorReportUploadDetails": {}, "feedback": "Umpan Balik", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Kesalahan saat mengirimkan umpan balik", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Umpan balik dikirimkan", "@feedbackSuccess": {}, "filterActive": "Aktif", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Tampilkan komponen aktif", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Dirakit", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Tampilkan Part yang dirakit", "@filterAssemblyDetail": {}, "filterComponent": "Komponen", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Tampilkan komponen Part", "@filterComponentDetail": {}, "filterExternal": "Eksternal", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Tampilkan stok di lokasi eksternal", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "Tersedia", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Tampilkan part yang memiliki stok", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serial", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Tampilkan item stok yang diserialisasikan", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Templat", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Tampilkan Part templat", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Dapat dilacak", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Tampilkan Part yang dapat dilacak", "@filterTrackableDetail": {}, "filterVirtual": "Virtual", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Tampilkan part virtual", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Opsi Pemfilteran", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Pengecualian format", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "Pengecualian format data JSON", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Kesalahan Formulir", "@formError": {}, "history": "Riwayat", "@history": { @@ -318,21 +318,21 @@ "home": "Beranda", "@homeScreen": {}, "homeScreen": "Tampilan Beranda", - "homeScreenSettings": "Configure home screen settings", + "homeScreenSettings": "Konfigurasikan pengaturan layar beranda", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Tampilkan Pembelian Pesanan", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Tampilkan tombol pesanan pembelian di layar beranda", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Tampilkan Pesanan Penjualan", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Tampilkan tombol pesanan penjualan di layar beranda", "@homeShowSoDescription": {}, "homeShowSubscribed": "Penjelasan Suku Cadang", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Tampilkan suku cadang yang dilanggan di layar beranda", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Tampilkan Pemasok", "@homeShowSuppliers": {}, "homeShowSuppliersDescription": "Show suppliers button on home screen", "@homeShowSupplierDescription": {}, @@ -456,7 +456,7 @@ "@manufacturer": {}, "manufacturers": "Manufacturers", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Data Hilang", "@missingData": {}, "name": "Nama", "@name": {}, @@ -468,51 +468,51 @@ }, "notifications": "Notifikasi", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Tidak ada notifikasi yang belum dibaca", "@notificationsEmpty": {}, "noResponse": "Tidak ada respon dari server", "@noResponse": {}, "noResults": "Tidak ada hasil", "@noResults": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Tidak ada subkategori", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Tidak ada subkategori tersedia", "@noSubcategoriesAvailable": {}, "numberInvalid": "Nomor tidak valid", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "Pada Pesanan", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Item yang saat ini sedang dipesan", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Orientasi Layar", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Orientasi layar (perlu memulai ulang)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Lanskap", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Tegak", "@orientationPortrait": {}, "orientationSystem": "Sistem", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Belum Selesai", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Tampilkan pesanan yang belum selesai", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Terlambat", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Tampilkan pesanan yang terlambat", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Kemasan", "@packaging": {}, - "packageName": "Package Name", + "packageName": "Nama Paket", "@packageName": {}, - "parameters": "Parameters", + "parameters": "Parameter", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Tampilkan parameter komponen", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "Induk", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Kategori Induk", "@parentCategory": {}, "parentLocation": "Lokasi Orang Tua", "@parentLocation": {}, @@ -520,65 +520,65 @@ "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Part baru", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Buat kategori Part baru", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Part diperbarui", "@partEdited": {}, "parts": "Parts", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Part tidak ditandai sebagai dapat dijual", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "Tanpa Part", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "Tidak ada Part yang cocok dengan kueri", "@partNoResults": {}, - "partSettings": "Part Settings", + "partSettings": "Pengaturan Part", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "Part yang disubcribe", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "Tidak ada part yang diberi bintang yang tersedia", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "Pemasok Part", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "Kategori Part", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "Kategori Part tingkat atas", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "kategori Part", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Detail Part", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Catatan Part", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Stok Part", "@partStock": { "description": "part stock" }, "password": "Kata Sandi", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "Kata sandi tidak boleh kosong", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Akun Anda tidak memiliki izin yang diperlukan untuk melakukan tindakan ini", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Izin Diperlukan", "@permissionRequired": {}, - "printLabel": "Print Label", + "printLabel": "Cetak Label", "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, "pluginPrinter": "Mesin Cetak", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "Dukungan Plugin Diaktifkan", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Server mendukung plugin khusus", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "Pencetakan label gagal", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "Label dikirim ke printer", "@printLabelSuccess": {}, "profile": "Profil", "@profile": {}, @@ -586,15 +586,15 @@ "@profileAdd": {}, "profileConnect": "Sambung ke Server", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "Edit Profil Server", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "Hapus Profil Server", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Keluar dari Profil", "@profileLogout": {}, "profileName": "Profil Nama", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "Tidak ada profil yang tersedia", "@profileNone": {}, "profileNotSelected": "No Profile Selected", "@profileNotSelected": {}, @@ -732,15 +732,15 @@ "@scanBarcode": {}, "scanSupplierPart": "Scan supplier part barcode", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "Pindai Ke Lokasi", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Pindai item ini ke lokasi", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Pemindai Eksternal", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Gunakan pemindai eksternal untuk membaca barcode (mode baji)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Pindai Komponen yang Diterima", "@scanReceivedParts": {}, "search": "Cari", "@search": { @@ -748,9 +748,9 @@ }, "searching": "Mencari", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "Caro Lokasi", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "Cari Part", "@searchParts": {}, "searchStock": "Cari Persediaan", "@searchStock": {}, @@ -760,59 +760,59 @@ "@selectFile": {}, "selectImage": "Pilih Gambar", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Pilih Lokasi", "@selectLocation": {}, "send": "Kirim", "@send": {}, "serialNumber": "Nomor Seri", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Nomor Seri", "@serialNumbers": {}, "server": "Server", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Alamat Server", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Versi API yang diperlukan", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Versi API Server", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Kesalahan Autentikasi", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Kesalahan Sertifikat", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Sertifikat HTTPS server tidak valid", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Sambung ke Server", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Menghubungkan ke server", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Tidak dapat terhubung ke server", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Server tidak boleh kosong", "@serverEmpty": {}, "serverError": "Galat Server", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Detail Server", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "Respons server tidak memiliki kolom yang diperlukan", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Versi Server Lama", "@serverOld": {}, "serverSettings": "Pengaturan Server", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Server harus dimulai dengan http[s]", "@serverStart": {}, "settings": "Pengaturan", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Instans Server", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Server tidak terhubung", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Server tidak dipilih", "@serverNotSelected": {}, - "shipments": "Shipments", + "shipments": "Pengiriman", "@shipments": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Tambahkan Pengiriman", "@shipmentAdd": {}, "shipped": "Terkirim", "@shipped": {}, @@ -820,9 +820,9 @@ "@sku": {}, "sounds": "Suara", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Putar nada suara pada tindakan Barcode", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Putar nada suara pada kesalahan server", "@soundOnServerError": {}, "status": "Status", "@status": {}, @@ -832,51 +832,51 @@ "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Jumlah stok yang tersedia saat ini", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "Stok Item", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "Item Stok", "@stockItems": {}, "stockItemCreate": "Unit Persediaan Baru", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "Buat item stok baru di lokasi ini", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "Hapus item stok", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Apakah Anda yakin ingin menghapus item stok ini?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "Tidak dapat menghapus item stok", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "item stok dihapus", "@stockItemDeleteSuccess": {}, "stockItemHistory": "Riwayat Stok", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Tampilkan informasi pelacakan stok historis", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "Item stok ditransfer", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "Item stok diperbarui", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "Tidak ada item stok yang tersedia", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "Catatan Item Stok", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "Item stok diperbarui", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "Pembaruan item stok gagal", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "lokasi stok", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "Lokasi Stok", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "Lokasi stok tingkat atas", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Gunakan HTTPS Ketat", "@strictHttps": {}, "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", "@strictHttpsDetails": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 9b85ec7..5d24fbf 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -84,7 +84,7 @@ "@barcodeNotAssigned": {}, "barcodeScanPart": "Scansiona codice a barre del prodotto", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scansione codice a barre per ricevere la parte", + "barcodeReceivePart": "Scansiona codice a barre per ricevere la parte", "@barcodeReceivePart": {}, "barcodeScanPaused": "Scansione codice a barre in pausa", "@barodeScanPaused": {}, diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index b679add..c85a644 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -233,7 +233,7 @@ }, "editItem": "Edytuj Pozycję Magazynową", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Edytuj element", "@editLineItem": {}, "enterPassword": "Wprowadź hasło", "@enterPassword": {}, @@ -420,7 +420,7 @@ "@lastUpdated": {}, "level": "Poziom", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Dodaj element pozycji", "@lineItemAdd": {}, "lineItem": "Pozycja", "@lineItem": {}, diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 2aaefd0..374f5dd 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -150,7 +150,7 @@ "@categoryCreate": {}, "categoryCreateDetail": "Create new part category", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Категорію частини оновлено", "@categoryUpdated": {}, "company": "Company", "@company": {}, diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 2b31105..dffb1bb 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -42,7 +42,7 @@ "@appReleaseNotes": {}, "appSettings": "程式設定", "@appSettings": {}, - "appSettingsDetails": "InvenTree 設定", + "appSettingsDetails": "配置 InvenTree 應用程式設定", "@appSettingsDetails": {}, "attachments": "附件", "@attachments": {}, @@ -64,7 +64,7 @@ "@availableStock": {}, "barcodes": "條碼", "@barcodes": {}, - "barcodeSettings": "條碼設置", + "barcodeSettings": "條形碼設置", "@barcodeSettings": {}, "barcodeAssign": "設定條碼", "@barcodeAssign": {}, From 20e454d28741b93f44bbcbb9175b1adbdc3b5b1a Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 20 Nov 2024 16:47:04 +1100 Subject: [PATCH 507/746] StockItem Updates (#550) * bump version * Add new helpers for StockItem * Navigate to sales order from stock item * Navigate to customer (if specified) * linting fix --- assets/release_notes.md | 5 ++ lib/inventree/stock.dart | 46 +++++++---- lib/l10n/app_en.arb | 6 ++ lib/widget/stock/stock_detail.dart | 128 ++++++++++++++++++++++++++--- pubspec.yaml | 2 +- 5 files changed, 157 insertions(+), 30 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 43b58e3..09e86ee 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.17.0 - November 2024 +--- + +- Clearly indicate if a StockItem is unavailable + ### 0.16.5 - September 2024 --- diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 4d12553..bd7a6cf 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -291,7 +291,9 @@ class InvenTreeStockItem extends InvenTreeModel { } int get status => getInt("status"); - + + bool get isInStock => getBool("in_stock", backup: true); + String get packaging => getString("packaging"); String get batch => getString("batch"); @@ -321,26 +323,34 @@ class InvenTreeStockItem extends InvenTreeModel { bool get isBuilding => getBool("is_building"); - // Date of last update - DateTime? get updatedDate { - if (jsondata.containsKey("updated")) { - return DateTime.tryParse((jsondata["updated"] ?? "") as String); - } else { - return null; - } + int get salesOrderId => getInt("sales_order"); + + bool get hasSalesOrder => salesOrderId > 0; + + int get customerId => getInt("customer"); + + bool get hasCustomer => customerId > 0; + + // Date of last update + DateTime? get updatedDate { + if (jsondata.containsKey("updated")) { + return DateTime.tryParse((jsondata["updated"] ?? "") as String); + } else { + return null; + } + } + + String get updatedDateString { + var _updated = updatedDate; + + if (_updated == null) { + return ""; } - String get updatedDateString { - var _updated = updatedDate; + final DateFormat _format = DateFormat("yyyy-MM-dd"); - if (_updated == null) { - return ""; - } - - final DateFormat _format = DateFormat("yyyy-MM-dd"); - - return _format.format(_updated); - } + return _format.format(_updated); + } DateTime? get stocktakeDate { if (jsondata.containsKey("stocktake_date")) { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2f622ff..cbe1f14 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1430,6 +1430,12 @@ "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", "@unitPrice": {}, diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 93b02b1..bf874b2 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -7,6 +7,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/stock.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; @@ -16,10 +17,12 @@ import "package:inventree/preferences.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/company/supplier_part_detail.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/order/sales_order_detail.dart"; import "package:inventree/widget/stock/location_display.dart"; import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/progress.dart"; @@ -51,6 +54,11 @@ class _StockItemDisplayState extends RefreshableState { bool stockShowHistory = false; bool stockShowTests = true; + // Linked data fields + InvenTreePart? part; + InvenTreeSalesOrder? salesOrder; + InvenTreeCompany? customer; + @override List appBarActions(BuildContext context) { List actions = []; @@ -199,9 +207,6 @@ class _StockItemDisplayState extends RefreshableState { // This will be determined when the widget is loaded List> labels = []; - // Part object - InvenTreePart? part; - int attachmentCount = 0; @override @@ -252,6 +257,40 @@ class _StockItemDisplayState extends RefreshableState { } }); + // Request SalesOrder information + if (widget.item.hasSalesOrder) { + InvenTreeSalesOrder().get(widget.item.salesOrderId).then((instance) => { + if (mounted) { + setState(() { + salesOrder = instance as InvenTreeSalesOrder?; + }) + } + }); + } else { + if (mounted) { + setState(() { + salesOrder = null; + }); + } + } + + // Request Customer information + if (widget.item.hasCustomer) { + InvenTreeCompany().get(widget.item.customerId).then((instance) => { + if (mounted) { + setState(() { + customer = instance as InvenTreeCompany?; + }) + } + }); + } else { + if (mounted) { + setState(() { + customer = null; + }); + } + } + List> _labels = []; bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); allowLabelPrinting &= api.supportsMixin("labels"); @@ -455,18 +494,32 @@ class _StockItemDisplayState extends RefreshableState { } Widget headerTile() { - return Card( - child: ListTile( - title: Text("${widget.item.partName}"), - subtitle: Text("${widget.item.partDescription}"), - leading: InvenTreeAPI().getThumbnail(widget.item.partImage), - trailing: widget.item.isSerialized() ? null : Text( + + Widget? trailing; + + if (!widget.item.isInStock) { + trailing = Text( + L10().unavailable, + style: TextStyle( + color: COLOR_DANGER + ) + ); + } else if (!widget.item.isSerialized()) { + trailing = Text( widget.item.quantityString(), style: TextStyle( fontSize: 20, color: api.StockStatus.color(widget.item.status), ) - ), + ); + } + + return Card( + child: ListTile( + title: Text("${widget.item.partName}"), + subtitle: Text("${widget.item.partDescription}"), + leading: InvenTreeAPI().getThumbnail(widget.item.partImage), + trailing: trailing, onTap: () async { if (widget.item.partId > 0) { @@ -544,7 +597,7 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text("${widget.item.serialNumber}"), ) ); - } else { + } else if (widget.item.isInStock) { tiles.add( ListTile( title: widget.item.allocated > 0 ? Text(L10().quantityAvailable) : Text(L10().quantity), @@ -554,6 +607,27 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (!widget.item.isInStock) { + tiles.add( + ListTile( + leading: Icon(TablerIcons.box_off), + title: Text( + L10().unavailable, + style: TextStyle( + color: COLOR_DANGER, + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text( + L10().unavailableDetail, + style: TextStyle( + color: COLOR_DANGER + ) + ) + ) + ); + } + // Stock item status information tiles.add( ListTile( @@ -605,6 +679,38 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (widget.item.hasSalesOrder && salesOrder != null) { + tiles.add( + ListTile( + title: Text(L10().salesOrder), + subtitle: Text(salesOrder?.description ?? ""), + leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), + trailing: Text(salesOrder?.reference ?? ""), + onTap: () { + Navigator.push(context, MaterialPageRoute( + builder: (context) => SalesOrderDetailWidget(salesOrder!) + )); + } + ) + ); + } + + if (widget.item.hasCustomer && customer != null) { + tiles.add( + ListTile( + title: Text(L10().customer), + subtitle: Text(customer?.description ?? ""), + leading: Icon(TablerIcons.building_store, color: COLOR_ACTION), + trailing: Text(customer?.name ?? ""), + onTap: () { + Navigator.push(context, MaterialPageRoute( + builder: (context) => CompanyDetailWidget(customer!) + )); + }, + ) + ); + } + if (widget.item.batch.isNotEmpty) { tiles.add( ListTile( diff --git a/pubspec.yaml b/pubspec.yaml index 0d17520..5cbee61 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.16.5+91 +version: 0.17.0+92 environment: sdk: ">=2.19.5 <3.13.0" From a06ad4e804d8a080b50c17e49f19a3444091e0fb Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Nov 2024 11:27:19 +1100 Subject: [PATCH 508/746] New Crowdin updates (#551) * New translations app_en.arb (Italian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) * New translations app_en.arb (Persian) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++ lib/l10n/da_DK/app_da_DK.arb | 4 ++ lib/l10n/de_DE/app_de_DE.arb | 4 ++ lib/l10n/el_GR/app_el_GR.arb | 4 ++ lib/l10n/es_ES/app_es_ES.arb | 4 ++ lib/l10n/es_MX/app_es_MX.arb | 4 ++ lib/l10n/et_EE/app_et_EE.arb | 4 ++ lib/l10n/fa_IR/app_fa_IR.arb | 72 +++++++++++++++++++----------------- lib/l10n/fi_FI/app_fi_FI.arb | 4 ++ lib/l10n/fr_FR/app_fr_FR.arb | 4 ++ lib/l10n/he_IL/app_he_IL.arb | 4 ++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++ lib/l10n/id_ID/app_id_ID.arb | 4 ++ lib/l10n/it_IT/app_it_IT.arb | 4 ++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++ lib/l10n/nl_NL/app_nl_NL.arb | 4 ++ lib/l10n/no_NO/app_no_NO.arb | 4 ++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++ lib/l10n/pt_PT/app_pt_PT.arb | 4 ++ lib/l10n/ro_RO/app_ro_RO.arb | 4 ++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++ lib/l10n/th_TH/app_th_TH.arb | 4 ++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++ lib/l10n/zh_CN/app_zh_CN.arb | 4 ++ lib/l10n/zh_TW/app_zh_TW.arb | 4 ++ 38 files changed, 186 insertions(+), 34 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 67193c5..c68226f 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 4a73da4..11dc8c9 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index a4c1bb2..05a48c2 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Pomozte přeložit aplikaci InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Jednotková cena", "@unitPrice": {}, "units": "Jednotky", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 4d809d5..34354b1 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index cdada25..6250c7b 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Preis pro Einheit", "@unitPrice": {}, "units": "Einheiten", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 4af1818..4fb78fb 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 8658316..5238e9b 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Precio Unitario", "@unitPrice": {}, "units": "Unidades", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index ea4924e..3820eee 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Precio unitario", "@unitPrice": {}, "units": "Unidades", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index e59caad..a5f1d4e 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Aita InvenTree rakendust tõlkida", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Ühiku hind", "@unitPrice": {}, "units": "Ühikud", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 724cdef..42d077a 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -1,88 +1,88 @@ { "@@locale": "fa", - "appTitle": "InvenTree", + "appTitle": "اینونتری", "@appTitle": { "description": "InvenTree application title string" }, - "ok": "OK", + "ok": "تأیید", "@ok": { "description": "OK" }, - "about": "About", + "about": "درباره", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "جزئیات حساب", "@accountDetails": {}, - "actions": "Actions", + "actions": "اقدامات", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "اقدامی وجود ندارد", "@actionsNone": {}, - "add": "Add", + "add": "افزودن", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "افزودن موجودی", "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "نشانی", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "درباره اینونتری", "@appAbout": {}, "appCredits": "Additional app credits", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "جزئیات برنامه", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "اختصاص داده شده", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "موجودی اختصاص داده شده", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, - "appSettings": "App Settings", + "appSettings": "تنظیمات برنامه", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "پیکربندی تنظیمات برنامه ", "@appSettingsDetails": {}, - "attachments": "Attachments", + "attachments": "پیوست ها", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "پیوست تصویر", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "پیوستی یافت نشد", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "پیوستی یافت نشد", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "انتخاب پیوست", "@attachmentSelect": {}, - "attention": "Attention", + "attention": "توجه", "@attention": {}, - "available": "Available", + "available": "موجود", "@available": {}, - "availableStock": "Available Stock", + "availableStock": "ذخیره موجود", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "بارکدها", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "تنضیمات بارکد", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "اضافه بارکد", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "ایجاد بارکد سفارشی", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "بارکد اضافه شد", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "خطای اسکن بارکد", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "بارکد قبلا اضافه شده است", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "اطلاعات هش بارکد در پاسخ موجود نیست", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "عدم وجود بارکد در سسیستم", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "بارکد اضافه نشده است", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "اسکن بارکد قطعه", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index e250099..e2cc4bb 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Auta kääntämään InvenTree-sovellusta", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index b1ad192..d34b9c5 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Aidez à traduire l'application InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Prix unitaire", "@unitPrice": {}, "units": "Unités", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index abb4092..d0945fb 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "עזרו לתרגם את אפליקציית InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "מחיר ליחידה", "@unitPrice": {}, "units": "יחידות", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 249569a..4f33ac4 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 9b538b2..033cb8b 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Egységár", "@unitPrice": {}, "units": "Mértékegységek", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 7e014bb..4438639 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Harga Unit", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 5d24fbf..27ebee4 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Aiuta a tradurre l'app InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Prezzo Unitario", "@unitPrice": {}, "units": "Unità", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index b72b8b2..1aa53bd 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "InvenTree アプリの翻訳に協力する", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "単位", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index a8cdc6f..3bca621 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "InvenTree 앱의 번역을 도와주세요", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 3b3fda3..7e02439 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 43443fe..e1c9c5c 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index d077b62..d04ec4f 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help de InvenTree app te vertalen", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Stukprijs", "@unitPrice": {}, "units": "Eenheden", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index ed03f1e..ca65f8a 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Hjelp til med å oversette InvenTree-appen", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Enhetspris", "@unitPrice": {}, "units": "Enheter", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index c85a644..ec1790a 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Cena jednostkowa", "@unitPrice": {}, "units": "Jednostki", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index e7c2b79..28371bf 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Ajude a traduzir", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Preço unitário", "@unitPrice": {}, "units": "Unidades", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 2c77cb4..ee5ba84 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 6e73fd8..8b88604 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 3a8dd6b..965c491 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Помочь перевести приложение InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Цена за ед.", "@unitPrice": {}, "units": "Единицы измерения", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index fb30c75..6620869 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index f9c5e5f..f6b184d 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 9b1af03..20557b6 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 2c39b3b..1294a0e 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Hjälp till att översätta appen InvenTree", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Enhetspris", "@unitPrice": {}, "units": "Enheter", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index a7d91d5..40e55b6 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index f3e1904..c544342 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Çeviriye yardım et", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Birim Fiyat", "@unitPrice": {}, "units": "Birim", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 374f5dd..93c5ee1 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Help translate the InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Unit Price", "@unitPrice": {}, "units": "Units", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 11926e6..05c7bc3 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "Hỗ trợ dịch InvenTree app", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "Đơn giá", "@unitPrice": {}, "units": "Đơn vị", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 27595ab..38c7af2 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "协助翻译 InvenTree 应用", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "单价", "@unitPrice": {}, "units": "单位", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index dffb1bb..32a19f8 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -970,6 +970,10 @@ "@translate": {}, "translateHelp": "協助翻譯 InvenTree 應用", "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, "unitPrice": "單價", "@unitPrice": {}, "units": "單位", From 06bdd2d7f3982f5d7520817b2031f34bbd88bd0e Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 24 Nov 2024 14:37:28 +1100 Subject: [PATCH 509/746] Update README.md (#553) Add information on how to download / install --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index b3f1336..636f100 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,22 @@ The InvenTree mobile / tablet application is a companion app for the [InvenTree Written in the [Flutter](https://flutter.dev/) environment, the app provides native support for Android and iOS devices. +## Installation + +You can install the app via the following channels: + +### Google Play Store (Android) + +Download and install from the [Google Play Store](https://play.google.com/store/apps/details?id=inventree.inventree_app&hl=en_AU) + +### Apple Store (iOS) + +Download and install from the [Apple App Store](https://apps.apple.com/au/app/inventree/id1581731101) + +### Direct Download (Android) + +We provide direct downloads for Android users - view our [download page via polar.sh](https://polar.sh/inventree/products/299bf0d5-af88-4e0f-becf-c007ad37ecf2) + ## User Documentation User documentation for the InvenTree mobile app can be found [within the InvenTree documentation](https://inventree.readthedocs.io/en/latest/app/app/). From 07a3f759816f5ead95f8fc273b6e46f72c891ebc Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 29 Nov 2024 10:18:19 +1100 Subject: [PATCH 510/746] New Crowdin updates (#554) * New translations app_en.arb (Greek) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish) --- lib/l10n/el_GR/app_el_GR.arb | 60 ++++++++++++++++++------------------ lib/l10n/es_ES/app_es_ES.arb | 4 +-- lib/l10n/fa_IR/app_fa_IR.arb | 60 ++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 4fb78fb..13b06ec 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -4,11 +4,11 @@ "@appTitle": { "description": "InvenTree application title string" }, - "ok": "OK", + "ok": "ΟΚ", "@ok": { "description": "OK" }, - "about": "About", + "about": "Σχετικά με", "@about": {}, "accountDetails": "Λεπτομέρειες Λογαριασμού", "@accountDetails": {}, @@ -16,33 +16,33 @@ "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "Καμία διαθέσιμη ενέργεια", "@actionsNone": {}, - "add": "Add", + "add": "Προσθήκη", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "Προσθήκη Αποθέματος", "@addStock": { "description": "add stock" }, "address": "Διεύθυνση", "@address": {}, - "appAbout": "About InvenTree", + "appAbout": "Σχετικά με το InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "Πρόσθετες μονάδες εφαρμογής", "@appCredits": {}, - "appDetails": "App Details", + "appDetails": "Λεπτομέρειες εφαρμογής", "@appDetails": {}, - "allocated": "Allocated", + "allocated": "Κατανεμημένο", "@allocated": {}, - "allocateStock": "Allocate Stock", + "allocateStock": "Κατανομή Αποθέματος", "@allocateStock": {}, - "appReleaseNotes": "Display app release notes", + "appReleaseNotes": "Προβολή πληροφοριών έκδοσης εφαρμογής", "@appReleaseNotes": {}, "appSettings": "Ρυθμίσεις Εφαρμογής", "@appSettings": {}, - "appSettingsDetails": "Configure InvenTree app settings", + "appSettingsDetails": "Διαμόρφωση ρυθμίσεων της εφαρμογής InvenTree", "@appSettingsDetails": {}, "attachments": "Συνημμένα", "@attachments": {}, @@ -50,51 +50,51 @@ "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "Δε βρέθηκαν συνημμένα", "@attachmentNone": {}, "attachmentNoneDetail": "Δεν βρέθηκαν συνημμένα", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "Επιλογή επισύναψης", "@attachmentSelect": {}, "attention": "Προσοχή", "@attention": {}, - "available": "Available", + "available": "Διαθέσιμο", "@available": {}, "availableStock": "Διαθέσιμο Απόθεμα", "@availableStock": {}, "barcodes": "Barcodes", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "Ρυθμίσεις Barcode", "@barcodeSettings": {}, "barcodeAssign": "Αντιστοίχιση Barcode", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "Σαρώστε προσαρμοσμένο barcode για ανάθεση", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "Το Βarcode καταχωρήθηκε", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "Σφάλμα σάρωσης Barcode", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "Το Barcode έχει ήδη ανατεθεί", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "Λείπουν δεδομένα κατακερματισμού Barcode από την απόκριση", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "Δεν υπάρχει αντιστοιχία με το barcode", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "Το Βarcode δεν καταχωρήθηκε", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "Σάρωση barcode εξαρτήματος", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Σάρωση barcode για λήψη εξαρτήματος", "@barcodeReceivePart": {}, - "barcodeScanPaused": "Barcode scanning paused", + "barcodeScanPaused": "Παύση σάρωσης barcode", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Πατήστε ή κρατήστε πατημένο για να κάνετε παύση σάρωσης", "@barcodeScanPause": {}, - "barcodeScanAssign": "Scan to assign barcode", + "barcodeScanAssign": "Σάρωση για εκχώρηση barcode", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Είσοδος Σαρωτή", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Επιλέξτε πηγή εισόδου για σαρωτή barcode", "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Barcode Scan Delay", "@barcodeScanDelay": {}, diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 5238e9b..5f27323 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -970,9 +970,9 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "No disponible", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Artículo no disponible", "@unavailableDetail": {}, "unitPrice": "Precio Unitario", "@unitPrice": {}, diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 42d077a..7618378 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -92,7 +92,7 @@ "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "", "@barcodeScanController": {}, "barcodeScanControllerDetail": "Select barcode scanner input source", "@barcodeScanControllerDetail": {}, @@ -130,60 +130,60 @@ "@bom": {}, "bomEnable": "Display Bill of Materials", "@bomEnable": {}, - "build": "Build", + "build": "ایجاد", "@build": {}, - "building": "Building", + "building": "ساختمان", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "دوربین داخلی", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "دسترسی دوبین برای خواندن بارکد", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "لغو", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "لغو سفارش", "@cancelOrder": {}, - "category": "Category", + "category": "دسته بندی", "@category": {}, - "categoryCreate": "New Category", + "categoryCreate": "دسته بندی جدید", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "دسته بندی کالای جدید", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "دسته بندی کالا آپدیت شد", "@categoryUpdated": {}, - "company": "Company", + "company": "شرکت", "@company": {}, - "companyEdit": "Edit Company", + "companyEdit": "ویرایش شرکت", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "شرکت پیدا نشد", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "مشخصات شرکت آپدیت شد", "@companyUpdated": {}, - "companies": "Companies", + "companies": "شرکت‌ها", "@companies": {}, - "configureServer": "Configure server settings", + "configureServer": "تنظیم شمخصات سرور", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "تأیید انتقال", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "connectionRefused": "Connection Refused", + "connectionRefused": "اتصال رد شد", "@connectionRefused": {}, - "count": "Count", + "count": "تعداد", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "موجودی انبار", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "اعتبارات", "@credits": {}, - "customer": "Customer", + "customer": "مشتری", "@customer": {}, - "customers": "Customers", + "customers": "مشتریان", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "مرجع مشتری", "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, @@ -558,19 +558,19 @@ "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "رمز عبور", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "رمز عبور نمی تواند خالی باشد", "@passwordEmpty": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "نیازمند مجوز", "@permissionRequired": {}, "printLabel": "Print Label", "@printLabel": {}, - "plugin": "Plugin", + "plugin": "افزونه", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "پرینتر", "@pluginPrinter": {}, "pluginSupport": "Plugin Support Enabled", "@pluginSupport": {}, From 4698e7e82cb843635125123d749417763d2fe5cb Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 4 Dec 2024 16:15:06 +1100 Subject: [PATCH 511/746] New translations app_en.arb (Polish) (#555) --- lib/l10n/pl_PL/app_pl_PL.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index ec1790a..13b42f5 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -253,7 +253,7 @@ "@errorFetch": {}, "errorUserRoles": "Błąd podczas wczytywania ról użytkownika z serwera", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Błąd podczas żądania danych wtyczki z serwera", "@errorPluginInfo": {}, "errorReporting": "Raportowanie błędów", "@errorReporting": {}, @@ -426,7 +426,7 @@ "@lineItem": {}, "lineItems": "Pozycje", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Pozycja zaktualizowana", "@lineItemUpdated": {}, "locateItem": "Zlokalizuj element magazynowy", "@locateItem": {}, @@ -970,9 +970,9 @@ "@translate": {}, "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Niedostępny", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Produkt nie jest dostępny", "@unavailableDetail": {}, "unitPrice": "Cena jednostkowa", "@unitPrice": {}, From 2e798b1bd1143dade02f9db5a6062af0030110de Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Dec 2024 14:38:53 +1100 Subject: [PATCH 512/746] Order picture action (#557) * Add "take picture" to purchase order detail * Rename uploaded images * Provide prefix when uploading images * Add similar functionality for "sales order" detail * Add new settings screens * Control camera shortcut * Bump release notes --- assets/release_notes.md | 3 + lib/inventree/model.dart | 46 ++++++++++-- lib/l10n/app_en.arb | 30 ++++++++ lib/preferences.dart | 8 +++ lib/settings/part_settings.dart | 10 +-- lib/settings/purchase_order_settings.dart | 79 +++++++++++++++++++++ lib/settings/sales_order_settings.dart | 79 +++++++++++++++++++++ lib/settings/settings.dart | 19 ++++- lib/widget/attachment_widget.dart | 8 ++- lib/widget/company/company_detail.dart | 1 + lib/widget/order/purchase_order_detail.dart | 25 +++++++ lib/widget/order/sales_order_detail.dart | 24 +++++++ lib/widget/part/part_detail.dart | 5 +- lib/widget/stock/stock_detail.dart | 1 + 14 files changed, 321 insertions(+), 17 deletions(-) create mode 100644 lib/settings/purchase_order_settings.dart create mode 100644 lib/settings/sales_order_settings.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 09e86ee..1841054 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,9 @@ ### 0.17.0 - November 2024 --- +- Improvements for image uploading +- Provide "upload image" shortcut on Purchase Order detail view +- Provide "upload image" shortcut on Sales Order detail view - Clearly indicate if a StockItem is unavailable ### 0.16.5 - September 2024 diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 2ee6256..852454d 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -12,7 +12,9 @@ import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; + import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/fields.dart"; // Paginated response object @@ -993,7 +995,7 @@ class InvenTreeAttachment extends InvenTreeModel { return count(filters: filters); } - Future uploadAttachment(File attachment, String modelType, int modelId, {String comment = "", Map fields = const {}}) async { + Future uploadAttachment(File attachment, int modelId, {String comment = "", Map fields = const {}}) async { // Ensure that the correct reference field is set Map data = Map.from(fields); @@ -1002,14 +1004,9 @@ class InvenTreeAttachment extends InvenTreeModel { if (InvenTreeAPI().supportsModernAttachments) { - if (modelType.isEmpty) { - sentryReportMessage("uploadAttachment called with empty 'modelType'"); - return false; - } - url = "attachment/"; data["model_id"] = modelId.toString(); - data["model_type"] = modelType; + data["model_type"] = REF_MODEL_TYPE; } else { @@ -1032,6 +1029,41 @@ class InvenTreeAttachment extends InvenTreeModel { return response.successful(); } + + Future uploadImage(int modelId, {String prefix = "InvenTree"}) async { + + bool result = false; + + await FilePickerDialog.pickImageFromCamera().then((File? file) { + if (file != null) { + + String dir = path.dirname(file.path); + String ext = path.extension(file.path); + String now = DateTime.now().toIso8601String().replaceAll(":", "-"); + + // Rename the file with a unique name + String filename = "${dir}/${prefix}_image_${now}${ext}"; + + try { + file.rename(filename).then((File renamed) { + uploadAttachment(renamed, modelId).then((success) { + result = success; + showSnackIcon( + result ? L10().imageUploadSuccess : L10().imageUploadFailure, + success: result); + }); + }); + } catch (error, stackTrace) { + sentryReportError("uploadImage", error, stackTrace); + showSnackIcon(L10().imageUploadFailure, success: false); + } + } + }); + + return result; + } + + /* * Download this attachment file */ diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cbe1f14..3db78e6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -897,6 +897,18 @@ "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, @@ -906,6 +918,9 @@ "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, @@ -1060,6 +1075,21 @@ "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, + "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 2611418..5700487 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -36,6 +36,14 @@ const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; const String INV_STOCK_SHOW_TESTS = "stockShowTests"; const String INV_STOCK_CONFIRM_SCAN = "stockConfirmScan"; +// Purchase order settings +const String INV_PO_ENABLE = "poEnable"; +const String INV_PO_SHOW_CAMERA = "poShowCamera"; + +// Sales order settings +const String INV_SO_ENABLE = "soEnable"; +const String INV_SO_SHOW_CAMERA = "soShowCamera"; + const String INV_REPORT_ERRORS = "reportErrors"; const String INV_STRICT_HTTPS = "strictHttps"; diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index bae7095..11cba4b 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -30,11 +30,11 @@ class _InvenTreePartSettingsState extends State { } Future loadSettings() async { - partShowParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; - partShowBom = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_BOM, true) as bool; - stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; - stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; - stockConfirmScan = await InvenTreeSettingsManager().getValue(INV_STOCK_CONFIRM_SCAN, false) as bool; + partShowParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); + partShowBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); + stockShowHistory = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_HISTORY, false); + stockShowTests = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_TESTS, true); + stockConfirmScan = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); if (mounted) { setState(() { diff --git a/lib/settings/purchase_order_settings.dart b/lib/settings/purchase_order_settings.dart new file mode 100644 index 0000000..d4211c2 --- /dev/null +++ b/lib/settings/purchase_order_settings.dart @@ -0,0 +1,79 @@ + +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; + +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; + + +class InvenTreePurchaseOrderSettingsWidget extends StatefulWidget { + @override + _InvenTreePurchaseOrderSettingsState createState() => _InvenTreePurchaseOrderSettingsState(); +} + + +class _InvenTreePurchaseOrderSettingsState extends State { + + _InvenTreePurchaseOrderSettingsState(); + + bool poEnable = true; + bool poShowCamera = true; + + @override + void initState() { + super.initState(); + + loadSettings(); + } + + Future loadSettings() async { + poEnable = await InvenTreeSettingsManager().getBool(INV_PO_ENABLE, true); + poShowCamera = await InvenTreeSettingsManager().getBool(INV_PO_SHOW_CAMERA, true); + + if (mounted) { + setState(() { + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(L10().purchaseOrderSettings)), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().purchaseOrderEnable), + subtitle: Text(L10().purchaseOrderEnableDetail), + leading: Icon(TablerIcons.shopping_cart), + trailing: Switch( + value: poEnable, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_PO_ENABLE, value); + setState(() { + poEnable = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().purchaseOrderShowCamera), + subtitle: Text(L10().purchaseOrderShowCameraDetail), + leading: Icon(TablerIcons.camera), + trailing: Switch( + value: poShowCamera, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_PO_SHOW_CAMERA, value); + setState(() { + poShowCamera = value; + }); + }, + ), + ), + ] + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/settings/sales_order_settings.dart b/lib/settings/sales_order_settings.dart new file mode 100644 index 0000000..62219b9 --- /dev/null +++ b/lib/settings/sales_order_settings.dart @@ -0,0 +1,79 @@ + +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; + +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; + + +class InvenTreeSalesOrderSettingsWidget extends StatefulWidget { + @override + _InvenTreeSalesOrderSettingsState createState() => _InvenTreeSalesOrderSettingsState(); +} + + +class _InvenTreeSalesOrderSettingsState extends State { + + _InvenTreeSalesOrderSettingsState(); + + bool soEnable = true; + bool soShowCamera = true; + + @override + void initState() { + super.initState(); + + loadSettings(); + } + + Future loadSettings() async { + soEnable = await InvenTreeSettingsManager().getBool(INV_SO_ENABLE, true); + soShowCamera = await InvenTreeSettingsManager().getBool(INV_SO_SHOW_CAMERA, true); + + if (mounted) { + setState(() { + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(L10().salesOrderSettings)), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().salesOrderEnable), + subtitle: Text(L10().salesOrderEnableDetail), + leading: Icon(TablerIcons.shopping_cart), + trailing: Switch( + value: soEnable, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_SO_ENABLE, value); + setState(() { + soEnable = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().salesOrderShowCamera), + subtitle: Text(L10().salesOrderShowCameraDetail), + leading: Icon(TablerIcons.camera), + trailing: Switch( + value: soShowCamera, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_SO_SHOW_CAMERA, value); + setState(() { + soShowCamera = value; + }); + }, + ), + ), + ] + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 595a15b..82267ce 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -11,7 +11,8 @@ import "package:inventree/settings/barcode_settings.dart"; import "package:inventree/settings/home_settings.dart"; import "package:inventree/settings/select_server.dart"; import "package:inventree/settings/part_settings.dart"; - +import "package:inventree/settings/purchase_order_settings.dart"; +import "package:inventree/settings/sales_order_settings.dart"; // InvenTree settings view class InvenTreeSettingsWidget extends StatefulWidget { @@ -86,6 +87,22 @@ class _InvenTreeSettingsState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePartSettingsWidget())); } ), + ListTile( + title: Text(L10().purchaseOrder), + subtitle: Text(L10().purchaseOrderSettings), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePurchaseOrderSettingsWidget())); + }, + ), + ListTile( + title: Text(L10().salesOrder), + subtitle: Text(L10().salesOrderSettings), + leading: Icon(TablerIcons.truck, color: COLOR_ACTION), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSalesOrderSettingsWidget())); + }, + ), Divider(), ListTile( title: Text(L10().about), diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index bc700f4..e6cfcd7 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -26,11 +26,12 @@ import "package:inventree/widget/refreshable_state.dart"; */ class AttachmentWidget extends StatefulWidget { - const AttachmentWidget(this.attachmentClass, this.modelId, this.hasUploadPermission) : super(); + const AttachmentWidget(this.attachmentClass, this.modelId, this.imagePrefix, this.hasUploadPermission) : super(); final InvenTreeAttachment attachmentClass; final int modelId; final bool hasUploadPermission; + final String imagePrefix; @override _AttachmentWidgetState createState() => _AttachmentWidgetState(); @@ -54,6 +55,10 @@ class _AttachmentWidgetState extends RefreshableState { IconButton( icon: Icon(TablerIcons.camera), onPressed: () async { + widget.attachmentClass.uploadImage( + widget.modelId, + prefix: widget.imagePrefix, + ); FilePickerDialog.pickImageFromCamera().then((File? file) { upload(context, file); }); @@ -78,7 +83,6 @@ class _AttachmentWidgetState extends RefreshableState { final bool result = await widget.attachmentClass.uploadAttachment( file, - widget.attachmentClass.REF_MODEL_TYPE, widget.modelId ); diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index f79992b..65f65d1 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -404,6 +404,7 @@ class _CompanyDetailState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreeCompanyAttachment(), widget.company.pk, + widget.company.name, InvenTreeCompany().canEdit ) ) diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 6f413f5..29dc68b 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -19,6 +19,7 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock/stock_list.dart"; +import "package:inventree/preferences.dart"; /* @@ -45,6 +46,7 @@ class _PurchaseOrderDetailState extends RefreshableState actionButtons(BuildContext context) { List actions = []; + if (showCameraShortcut && widget.order.canEdit) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.camera, color: Colors.blue), + label: L10().takePicture, + onTap: () async { + _uploadImage(context); + } + ) + ); + } + if (widget.order.canCreate) { if (widget.order.isPending) { @@ -137,6 +151,15 @@ class _PurchaseOrderDetailState extends RefreshableState _uploadImage(BuildContext context) async { + + InvenTreePurchaseOrderAttachment().uploadImage( + widget.order.pk, + prefix: widget.order.reference, + ).then((result) => refresh(context)); + } + /// Issue this order Future _issueOrder(BuildContext context) async { @@ -217,6 +240,7 @@ class _PurchaseOrderDetailState extends RefreshableState AttachmentWidget( InvenTreePurchaseOrderAttachment(), widget.order.pk, + widget.order.reference, widget.order.canEdit ) ) diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 36b8214..243a77f 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -6,6 +6,7 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/widget/order/so_line_list.dart"; import "package:inventree/widget/order/so_shipment_list.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -40,6 +41,7 @@ class _SalesOrderDetailState extends RefreshableState { List lines = []; + bool showCameraShortcut = true; bool supportsProjectCodes = false; int attachmentCount = 0; @@ -100,6 +102,14 @@ class _SalesOrderDetailState extends RefreshableState { ); } + /// Upload an image for this order + Future _uploadImage(BuildContext context) async { + InvenTreeSalesOrderAttachment().uploadImage( + widget.order.pk, + prefix: widget.order.reference, + ).then((result) => refresh(context)); + } + /// Issue this order Future _issueOrder(BuildContext context) async { @@ -136,6 +146,18 @@ class _SalesOrderDetailState extends RefreshableState { List actionButtons(BuildContext context) { List actions = []; + if (showCameraShortcut && widget.order.canEdit) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.camera, color: Colors.blue), + label: L10().takePicture, + onTap: () async { + _uploadImage(context); + } + ) + ); + } + if (widget.order.isPending) { actions.add( SpeedDialChild( @@ -231,6 +253,7 @@ class _SalesOrderDetailState extends RefreshableState { await api.SalesOrderStatus.load(); supportsProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED"); + showCameraShortcut = await InvenTreeSettingsManager().getBool(INV_SO_SHOW_CAMERA, true); InvenTreeSalesOrderAttachment().countAttachments(widget.order.pk).then((int value) { if (mounted) { @@ -378,6 +401,7 @@ class _SalesOrderDetailState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreeSalesOrderAttachment(), widget.order.pk, + widget.order.reference, widget.order.canEdit ) ) diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index c2d7470..4718e6e 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -181,7 +181,7 @@ class _PartDisplayState extends RefreshableState { }); // Request the number of parameters for this part - showParameters = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_PARAMETERS, true) as bool; + showParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); // Request the number of attachments InvenTreePartAttachment().countAttachments(part.pk).then((int value) { @@ -192,7 +192,7 @@ class _PartDisplayState extends RefreshableState { } }); - showBom = await InvenTreeSettingsManager().getValue(INV_PART_SHOW_BOM, true) as bool; + showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); // Request the number of BOM items InvenTreePart().count( @@ -588,6 +588,7 @@ class _PartDisplayState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreePartAttachment(), part.pk, + L10().part, part.canEdit ) ) diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index bf874b2..106d050 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -844,6 +844,7 @@ class _StockItemDisplayState extends RefreshableState { builder: (context) => AttachmentWidget( InvenTreeStockItemAttachment(), widget.item.pk, + L10().stockItem, widget.item.canEdit, ) ) From 9c12a831764ff4b686e025803bae6506c3418e08 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Dec 2024 14:55:10 +1100 Subject: [PATCH 513/746] Specify app bar color (#558) --- lib/api_form.dart | 1 + lib/app_colors.dart | 5 +++++ lib/barcode/camera_controller.dart | 1 + lib/barcode/wedge_controller.dart | 1 + lib/settings/about.dart | 1 + lib/settings/app_settings.dart | 1 + lib/settings/barcode_settings.dart | 7 ++++++- lib/settings/home_settings.dart | 2 ++ lib/settings/login.dart | 1 + lib/settings/part_settings.dart | 6 +++++- lib/settings/release.dart | 5 ++++- lib/settings/settings.dart | 1 + lib/widget/home.dart | 1 + lib/widget/refreshable_state.dart | 1 + 14 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 9522280..c22877d 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1498,6 +1498,7 @@ class _APIFormWidgetState extends State { return Scaffold( appBar: AppBar( title: Text(widget.title), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( icon: Icon(widget.icon), diff --git a/lib/app_colors.dart b/lib/app_colors.dart index b5d5eac..d9b0da9 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -27,6 +27,11 @@ Color get COLOR_ACTION { } } +// Return an "app bar" color based on the current theme +Color get COLOR_APP_BAR { + return Colors.blueGrey; +} + const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); const Color COLOR_DANGER = Color.fromRGBO(200, 50, 75, 1); const Color COLOR_SUCCESS = Color.fromRGBO(100, 200, 75, 1); diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 0e644d4..460aecb 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -135,6 +135,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { return Scaffold( appBar: AppBar( + backgroundColor: COLOR_APP_BAR, title: Text(L10().scanBarcode), actions: [ IconButton( diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart index 741cec1..1c553e1 100644 --- a/lib/barcode/wedge_controller.dart +++ b/lib/barcode/wedge_controller.dart @@ -102,6 +102,7 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { return Scaffold( appBar: AppBar( + backgroundColor: COLOR_APP_BAR, title: Text(L10().scanBarcode), ), backgroundColor: Colors.black.withOpacity(0.9), diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 7928eb2..6bbd68e 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -225,6 +225,7 @@ class InvenTreeAboutWidget extends StatelessWidget { return Scaffold( appBar: AppBar( title: Text(L10().appAbout), + backgroundColor: COLOR_APP_BAR, ), body: ListView( children: ListTile.divideTiles( diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index f623f8f..a2e82aa 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -157,6 +157,7 @@ class _InvenTreeAppSettingsState extends State { key: _settingsKey, appBar: AppBar( title: Text(L10().appSettings), + backgroundColor: COLOR_APP_BAR ), body: Container( child: ListView( diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index d881124..08a7bf6 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -3,6 +3,8 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/app_colors.dart"; + import "package:inventree/widget/dialogs.dart"; @@ -110,7 +112,10 @@ class _InvenTreeBarcodeSettingsState extends State { key: _settingsKey, appBar: AppBar( title: Text(L10().homeScreen), + backgroundColor: COLOR_APP_BAR, ), body: Container( child: ListView( diff --git a/lib/settings/login.dart b/lib/settings/login.dart index b895a38..d580b1d 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -108,6 +108,7 @@ class _InvenTreeLoginState extends State { return Scaffold( appBar: AppBar( title: Text(L10().login), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( icon: Icon(TablerIcons.transition_right, color: COLOR_SUCCESS), diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 11cba4b..02952b6 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -3,6 +3,7 @@ import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; @@ -45,7 +46,10 @@ class _InvenTreePartSettingsState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(L10().partSettings)), + appBar: AppBar( + title: Text(L10().partSettings), + backgroundColor: COLOR_APP_BAR + ), body: Container( child: ListView( children: [ diff --git a/lib/settings/release.dart b/lib/settings/release.dart index 4358a47..20e10b2 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -1,5 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_markdown/flutter_markdown.dart"; +import "package:inventree/app_colors.dart"; import "package:url_launcher/url_launcher.dart"; import "package:inventree/l10.dart"; @@ -16,7 +17,8 @@ class ReleaseNotesWidget extends StatelessWidget { Widget build (BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(L10().releaseNotes) + title: Text(L10().releaseNotes), + backgroundColor: COLOR_APP_BAR, ), body: Markdown( selectable: false, @@ -54,6 +56,7 @@ class CreditsWidget extends StatelessWidget { return Scaffold( appBar: AppBar( title: Text(L10().credits), + backgroundColor: COLOR_APP_BAR, ), body: Markdown( selectable: false, diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 82267ce..715d963 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -43,6 +43,7 @@ class _InvenTreeSettingsState extends State { key: _scaffoldKey, appBar: AppBar( title: Text(L10().settings), + backgroundColor: COLOR_APP_BAR, ), body: Center( child: ListView( diff --git a/lib/widget/home.dart b/lib/widget/home.dart index e68c35c..ac1f44c 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -397,6 +397,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr key: homeKey, appBar: AppBar( title: Text(L10().appTitle), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( icon: Icon( diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 8296b7e..d18d07c 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -60,6 +60,7 @@ mixin BaseWidgetProperties { centerTitle: false, bottom: tabs.isEmpty ? null : TabBar(tabs: tabs), title: Text(getAppBarTitle()), + backgroundColor: COLOR_APP_BAR, actions: appBarActions(context), leading: backButton(context, key), ); From d4b2204baf290c8e98acca2eb1f09dc019070b16 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Dec 2024 17:09:57 +1100 Subject: [PATCH 514/746] Sales order shipment progress (#560) - Display progress bar for sales order page --- lib/inventree/orders.dart | 4 ++++ lib/widget/order/sales_order_detail.dart | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart index 25b97d7..8d63f34 100644 --- a/lib/inventree/orders.dart +++ b/lib/inventree/orders.dart @@ -28,6 +28,10 @@ class InvenTreeOrder extends InvenTreeModel { int get completedLineItemCount => getInt("completed_lines", backup: 0); + int get shipmentCount => getInt("shipments_count", backup: 0); + + int get completedShipmentCount => getInt("completed_shipments_count", backup: 0); + bool get complete => completedLineItemCount >= lineItemCount; bool get overdue => getBool("overdue"); diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 243a77f..30c218e 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -362,6 +362,19 @@ class _SalesOrderDetailState extends RefreshableState { trailing: Text("${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), )); + // Shipment progress + if (widget.order.shipmentCount > 0) { + tiles.add(ListTile( + title: Text(L10().shipments), + subtitle: ProgressBar( + widget.order.completedShipmentCount.toDouble(), + maximum: widget.order.shipmentCount.toDouble() + ), + leading: Icon(TablerIcons.truck_delivery), + trailing: Text("${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", style: TextStyle(color: lineColor)), + )); + } + // TODO: total price if (widget.order.targetDate.isNotEmpty) { From 2964950b26390d140ef9825d000b4f62c82b6e5e Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Dec 2024 17:10:56 +1100 Subject: [PATCH 515/746] Home screen (#559) * Use grid view for home screen * Update release notes * Prune dead code --- assets/release_notes.md | 1 + lib/settings/settings.dart | 1 + lib/widget/home.dart | 54 +++++++++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 1841054..9329ce1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.17.0 - November 2024 --- +- Enhanced home-screen display using grid-view - Improvements for image uploading - Provide "upload image" shortcut on Purchase Order detail view - Provide "upload image" shortcut on Sales Order detail view diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 715d963..30f4f2b 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -56,6 +56,7 @@ class _InvenTreeSettingsState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget())); }, ), + Divider(), ListTile( title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), diff --git a/lib/widget/home.dart b/lib/widget/home.dart index ac1f44c..748a424 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -1,4 +1,5 @@ import "dart:async"; +import "dart:math"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -187,15 +188,24 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr return GestureDetector( child: Card( - margin: EdgeInsets.symmetric( - vertical: 5, - horizontal: 12 - ), - child: ListTile( - leading: Icon(icon, color: connected && allowed ? COLOR_ACTION : Colors.grey), - title: Text(label), - trailing: trailing, - ), + margin: EdgeInsets.all(5), + child: Align( + child: ListTile( + leading: Icon( + icon, + size: 32, + color: connected && allowed ? COLOR_ACTION : Colors.grey + ), + title: Text( + label, + style: TextStyle( + fontSize: 20 + ), + ), + trailing: trailing, + ), + alignment: Alignment.center, + ) ), onTap: () { if (!allowed) { @@ -219,9 +229,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr */ List getListTiles(BuildContext context) { - List tiles = [ - Divider(height: 5) - ]; + List tiles = []; // Parts if (InvenTreePart().canView) { @@ -381,10 +389,26 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr return _connectionStatusWidget(context); } - return ListView( - scrollDirection: Axis.vertical, - children: getListTiles(context), + double w = MediaQuery.of(context).size.width; + double h = MediaQuery.of(context).size.height; + + bool smallScreen = max(w, h) < 1000; + + int vTiles = smallScreen ? 2 : 3; + int hTiles = smallScreen ? 1 : 2; + double aspect = smallScreen ? 5 : 3; + double padding = smallScreen ? 2 : 10; + + return GridView.count( + crossAxisCount: w > h ? vTiles : hTiles, + children: getListTiles(context), + childAspectRatio: aspect, + primary: false, + crossAxisSpacing: padding, + mainAxisSpacing: padding, + padding: EdgeInsets.all(padding), ); + } @override From 4151aeb8e188326349773773cc0fab5a2ee12a0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 5 Dec 2024 19:54:30 +1100 Subject: [PATCH 516/746] New Crowdin updates (#561) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 20 ++++++++++++++++++++ lib/l10n/bg_BG/app_bg_BG.arb | 20 ++++++++++++++++++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 20 ++++++++++++++++++++ lib/l10n/da_DK/app_da_DK.arb | 20 ++++++++++++++++++++ lib/l10n/de_DE/app_de_DE.arb | 20 ++++++++++++++++++++ lib/l10n/el_GR/app_el_GR.arb | 20 ++++++++++++++++++++ lib/l10n/es_ES/app_es_ES.arb | 20 ++++++++++++++++++++ lib/l10n/es_MX/app_es_MX.arb | 20 ++++++++++++++++++++ lib/l10n/et_EE/app_et_EE.arb | 20 ++++++++++++++++++++ lib/l10n/fa_IR/app_fa_IR.arb | 20 ++++++++++++++++++++ lib/l10n/fi_FI/app_fi_FI.arb | 20 ++++++++++++++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 20 ++++++++++++++++++++ lib/l10n/he_IL/app_he_IL.arb | 20 ++++++++++++++++++++ lib/l10n/hi_IN/app_hi_IN.arb | 20 ++++++++++++++++++++ lib/l10n/hu_HU/app_hu_HU.arb | 20 ++++++++++++++++++++ lib/l10n/id_ID/app_id_ID.arb | 20 ++++++++++++++++++++ lib/l10n/it_IT/app_it_IT.arb | 20 ++++++++++++++++++++ lib/l10n/ja_JP/app_ja_JP.arb | 20 ++++++++++++++++++++ lib/l10n/ko_KR/app_ko_KR.arb | 20 ++++++++++++++++++++ lib/l10n/lt_LT/app_lt_LT.arb | 20 ++++++++++++++++++++ lib/l10n/lv_LV/app_lv_LV.arb | 20 ++++++++++++++++++++ lib/l10n/nl_NL/app_nl_NL.arb | 20 ++++++++++++++++++++ lib/l10n/no_NO/app_no_NO.arb | 20 ++++++++++++++++++++ lib/l10n/pl_PL/app_pl_PL.arb | 22 +++++++++++++++++++++- lib/l10n/pt_BR/app_pt_BR.arb | 20 ++++++++++++++++++++ lib/l10n/pt_PT/app_pt_PT.arb | 20 ++++++++++++++++++++ lib/l10n/ro_RO/app_ro_RO.arb | 20 ++++++++++++++++++++ lib/l10n/ru_RU/app_ru_RU.arb | 20 ++++++++++++++++++++ lib/l10n/sk_SK/app_sk_SK.arb | 20 ++++++++++++++++++++ lib/l10n/sl_SI/app_sl_SI.arb | 20 ++++++++++++++++++++ lib/l10n/sr_CS/app_sr_CS.arb | 20 ++++++++++++++++++++ lib/l10n/sv_SE/app_sv_SE.arb | 20 ++++++++++++++++++++ lib/l10n/th_TH/app_th_TH.arb | 20 ++++++++++++++++++++ lib/l10n/tr_TR/app_tr_TR.arb | 20 ++++++++++++++++++++ lib/l10n/uk_UA/app_uk_UA.arb | 20 ++++++++++++++++++++ lib/l10n/vi_VN/app_vi_VN.arb | 20 ++++++++++++++++++++ lib/l10n/zh_CN/app_zh_CN.arb | 20 ++++++++++++++++++++ lib/l10n/zh_TW/app_zh_TW.arb | 20 ++++++++++++++++++++ 38 files changed, 761 insertions(+), 1 deletion(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index c68226f..321e957 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 11dc8c9..298fb6c 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 05a48c2..065d0fe 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Kód projektu", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Objednávka", "@purchaseOrder": {}, "purchaseOrderCreate": "Nová objednávka", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Upravit objednávku", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Objednávky", "@purchaseOrders": {}, "purchaseOrderUpdated": "Objednávka byla aktualizována", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Prodejní objednávky", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Nová prodejní objednávka", "@saleOrderCreate": {}, "salesOrderEdit": "Upravit prodejní objednávku", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 34354b1..d633a12 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 6250c7b..8176417 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Projektcode", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Bestellung", "@purchaseOrder": {}, "purchaseOrderCreate": "Neue Bestellung", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Bestellung bearbeiten", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Bestellungen", "@purchaseOrders": {}, "purchaseOrderUpdated": "Bestellung aktualisiert", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Kundenauftrag", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Neuer Auftrag", "@saleOrderCreate": {}, "salesOrderEdit": "Auftrag bearbeiten", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 13b06ec..4e84375 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 5f27323..10d98af 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, "purchaseOrderCreate": "Nueva orden de compra", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Ordenes de compra", "@purchaseOrders": {}, "purchaseOrderUpdated": "Orden de compra actualizada", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Nueva orden de venta", "@saleOrderCreate": {}, "salesOrderEdit": "Editar orden de venta", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 3820eee..cc8f5b2 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, "purchaseOrderCreate": "Nueva orden de compra", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Órdenes de compra", "@purchaseOrders": {}, "purchaseOrderUpdated": "Orden de compra actualizada", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index a5f1d4e..d0cb525 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Projekti kood", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 7618378..b0be0ca 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index e2cc4bb..d128df1 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index d34b9c5..510fd3e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Code Projet", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Commande d’achat", "@purchaseOrder": {}, "purchaseOrderCreate": "Nouveau Bon de Commande", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifier la commande d'achat", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Commandes d'achat", "@purchaseOrders": {}, "purchaseOrderUpdated": "Bon de commande mis à jour", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Ventes", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Nouvelle commande", "@saleOrderCreate": {}, "salesOrderEdit": "Modifier la commande", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index d0945fb..0d9cd18 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "קוד פרויקט ", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "הזמנת רכש", "@purchaseOrder": {}, "purchaseOrderCreate": "הזמנת רכש חדשה", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "ערוך הזמנת רכש", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "הזמנות רכש", "@purchaseOrders": {}, "purchaseOrderUpdated": "הזמנות רכש עודכנו", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "הזמנת מכירות", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "הזמנת מכירה חדשה", "@saleOrderCreate": {}, "salesOrderEdit": "ערוך הזמנת מכירות", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 4f33ac4..208e41e 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 033cb8b..4d10207 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Projektszám", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Beszerzési rendelés", "@purchaseOrder": {}, "purchaseOrderCreate": "Új beszerzési rendelés", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Beszerzési rendelések", "@purchaseOrders": {}, "purchaseOrderUpdated": "Beszerzési rendelés frissítve", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Vevői rendelések", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Új vevői rendelés", "@saleOrderCreate": {}, "salesOrderEdit": "Vevői rendelés szerkesztése", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 4438639..d3a5448 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 27ebee4..b84bae5 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Codice del progetto", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Ordine d'acquisto", "@purchaseOrder": {}, "purchaseOrderCreate": "Nuovo Ordine di Acquisto", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifica ordine d'acquisto", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Ordini d'acquisto", "@purchaseOrders": {}, "purchaseOrderUpdated": "Ordine d'acquisto aggiornato", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Ordini di vendita", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Nuovo Ordine di Vendita", "@saleOrderCreate": {}, "salesOrderEdit": "Modifica Ordine di Vendita", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 1aa53bd..a37b74c 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "発注書", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "発注書の更新", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "発注書", "@purchaseOrders": {}, "purchaseOrderUpdated": "発注書が更新されました", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 3bca621..c24ff05 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 7e02439..9f781d9 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index e1c9c5c..fe11a8b 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index d04ec4f..131301b 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Inkooporder", "@purchaseOrder": {}, "purchaseOrderCreate": "Nieuwe Inkooporder", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Bewerk Inkooporder", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Inkooporders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Inkooporder bijgewerkt", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Verkooporders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Nieuwe verkooporder", "@saleOrderCreate": {}, "salesOrderEdit": "Verkooporder bewerken", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index ca65f8a..52f5f5b 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Prosjektkode", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Innkjøpsordre", "@purchaseOrder": {}, "purchaseOrderCreate": "Ny innkjøpsordre", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Rediger innkjøpsordre", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Innkjøpsordrer", "@purchaseOrders": {}, "purchaseOrderUpdated": "Innkjøpsordre oppdatert", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Salgsordre", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Ny salgsordre", "@saleOrderCreate": {}, "salesOrderEdit": "Rediger salgsordre", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 13b42f5..5804963 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -128,7 +128,7 @@ "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Wyświetl Bill of Materials", + "bomEnable": "Wyświetl listę materiałów", "@bomEnable": {}, "build": "Budowa", "@build": {}, @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Kod projektu", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Zlecenie Zakupu", "@purchaseOrder": {}, "purchaseOrderCreate": "Nowe zlecenie zakupu", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edytuj Zlecenie Zakupu", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Zlecenia zakupu", "@purchaseOrders": {}, "purchaseOrderUpdated": "Zamówienie zakupu zaktualizowane", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Zlecenia Sprzedaży", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Zlecenie sprzedaży", "@saleOrderCreate": {}, "salesOrderEdit": "Edytuj zlecenie sprzedaży", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 28371bf..8d455c4 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Código do projeto", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Ordem de Compra", "@purchaseOrder": {}, "purchaseOrderCreate": "Novo Pedido de Compra", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Editar ordem de compra", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Ordens de compras", "@purchaseOrders": {}, "purchaseOrderUpdated": "Ordem de compra atualizada", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Pedido de vendas", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Novo Pedido de Venda", "@saleOrderCreate": {}, "salesOrderEdit": "Editar Pedidos de Venda", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index ee5ba84..f62dd62 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 8b88604..7bd3d34 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 965c491..c7d86e1 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Код проекта", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Заказ на поставку", "@purchaseOrder": {}, "purchaseOrderCreate": "Новый заказ на поставку", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Редактировать заказ на поставку", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Заказы на поставку", "@purchaseOrders": {}, "purchaseOrderUpdated": "Заказ на поставку обновлен", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Заказы на продажу", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Новый заказ на продажу", "@saleOrderCreate": {}, "salesOrderEdit": "Редактировать заказ на продажу", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 6620869..c4ca84f 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index f6b184d..071d394 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 20557b6..fdd552a 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 1294a0e..d14242a 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Projektkod", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Inköpsorder", "@purchaseOrder": {}, "purchaseOrderCreate": "Ny inköpsorder", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Redigera inköpsorder", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Inköpsorder", "@purchaseOrders": {}, "purchaseOrderUpdated": "Inköpsorder uppdaterad", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Försäljningsordrar", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Ny försäljningsorder", "@saleOrderCreate": {}, "salesOrderEdit": "Redigera försäljningsorder", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 40e55b6..d4c917d 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index c544342..ef698b2 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Proje Kodu", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Satınalma Siparişi", "@purchaseOrder": {}, "purchaseOrderCreate": "Yeni Satınalma Emri", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Satın Alma siparişini düzenle", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Satınalma Siparişleri", "@purchaseOrders": {}, "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Yeni Satış Siparişi", "@saleOrderCreate": {}, "salesOrderEdit": "Satış Siparişini Düzenle", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 93c5ee1..d6a2784 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, "purchaseOrderCreate": "New Purchase Order", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Edit Purchase Order", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Purchase Orders", "@purchaseOrders": {}, "purchaseOrderUpdated": "Purchase order updated", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Sales Orders", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, "salesOrderEdit": "Edit Sales Order", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 05c7bc3..0288bae 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "Mã dự án", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Đơn hàng", "@purchaseOrder": {}, "purchaseOrderCreate": "Thêm mới đơn đặt hàng", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Chỉnh sửa đơn đặt hàng", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "Đơn hàng", "@purchaseOrders": {}, "purchaseOrderUpdated": "Cập nhật đơn đặt hàng", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "Đơn đặt hàng", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "Đơn hàng bán mới", "@saleOrderCreate": {}, "salesOrderEdit": "Sửa đơn hàng bán", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 38c7af2..e31464a 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "项目编码", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "采购订单", "@purchaseOrder": {}, "purchaseOrderCreate": "新采购订单", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "编辑采购订单", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "采购订单", "@purchaseOrders": {}, "purchaseOrderUpdated": "采购订单已更新", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "销售订单", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "新的销售订单", "@saleOrderCreate": {}, "salesOrderEdit": "编辑销售订单", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 32a19f8..258ac86 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -606,12 +606,22 @@ "@profileTapToCreate": {}, "projectCode": "項目編碼", "@projectCode": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "採購訂單", "@purchaseOrder": {}, "purchaseOrderCreate": "新採購訂單", "@purchaseOrderCreate": {}, "purchaseOrderEdit": "編輯採購訂單", "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Purchase order settings", + "@purchaseOrderSettings": {}, "purchaseOrders": "採購訂單", "@purchaseOrders": {}, "purchaseOrderUpdated": "採購訂單已更新", @@ -718,6 +728,16 @@ "@salesOrder": {}, "salesOrders": "銷售訂單", "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, "salesOrderCreate": "新的銷售訂單", "@saleOrderCreate": {}, "salesOrderEdit": "編輯銷售訂單", From d4cff1a5b9363d54c36eb123767eb81c40b82ca0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 6 Dec 2024 00:08:04 +1100 Subject: [PATCH 517/746] Barcode scanner updates (#562) * Add BUILDING.md * Replace scaning library - Out with qr_code_scanner - In with flutter_zxing * Update specs for jdk / kotlin / gradle - NFI what this all means? * Refactor barcode scanning widget * Refactor barcode overlay * Add handlers * Update release notes * Fix AppBar color * Enhance attachment widget * remove unused import * Improved icon * Select theme from main drawer --- .github/workflows/android.yaml | 4 +- BUILDING.md | 64 ++++ README.md | 39 +- android/app/build.gradle | 10 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- assets/release_notes.md | 3 +- lib/barcode/camera_controller.dart | 355 ++++++++++-------- lib/barcode/handler.dart | 1 + lib/l10n/app_en.arb | 6 + lib/settings/app_settings.dart | 2 +- lib/settings/purchase_order_settings.dart | 6 +- lib/settings/sales_order_settings.dart | 6 +- lib/settings/select_server.dart | 1 + lib/widget/attachment_widget.dart | 5 +- lib/widget/drawer.dart | 23 ++ lib/widget/refreshable_state.dart | 2 +- pubspec.lock | 32 +- pubspec.yaml | 6 +- 18 files changed, 339 insertions(+), 228 deletions(-) create mode 100644 BUILDING.md diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 16c06b7..2298bad 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - name: Setup Flutter uses: subosito/flutter-action@v2 with: @@ -29,7 +29,7 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2.4.2 with: - gradle-version: 7.6 + gradle-version: 8.5 - name: Collect Translation Files run: | cd lib/l10n diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..9e1d3fe --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,64 @@ +## InvenTree App Development + +For developers looking to contribute to the project, we use Flutter for app development. The project has been tested in Android Studio (on both Windows and Mac) and also VSCode. + +## Prerequisites + +To build the app from source, you will need the following tools installed on your system: + +- Android Studio (with Flutter and Dart plugins) + +### iOS Development + +For iOS development, you will need a Mac system with XCode installed. + +### Java Version + +Some versions of Android Studio ship with a built-in version of the Java JDK. However, the InvenTree app requires [JDK 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) to be installed. + +If you see any errors related to JDK version mismatch, download and install the correct version of the JDK (from the link above) and update your Android Studio settings to point to the correct JDK location: + +```bash +flutter config --jdk-dir /path/to/jdk +``` + +## Invoke Tasks + +We use the [invoke](https://www.pyinvoke.org) to run some core tasks - you will need python and invoke installed on your local system. + +## Getting Started + +Initial project setup (after you have installed all required dev tools) is as follows: + +Generate initial translation files: + +``` +invoke translate +``` + +Install required flutter packages: +``` +flutter pub get +``` + +You should now be ready to debug on a connected or emulated device! + +## Building Release Versions + +Building release versions for target platforms (either android or iOS) is simplified using invoke: + +### Android + +Build Android release: + +``` +invoke android +``` + +### iOS + +Build iOS release: + +``` +invoke ios +``` diff --git a/README.md b/README.md index 636f100..c422c6c 100644 --- a/README.md +++ b/README.md @@ -31,41 +31,4 @@ User documentation for the InvenTree mobile app can be found [within the InvenTr ## Developer Documentation -For developers looking to contribute to the project, we use Flutter for app development. The project has been tested in Android Studio (on both Windows and Mac) and also VSCode. - -### Invoke Tasks - -We use the [invoke](https://www.pyinvoke.org) to run some core tasks - you will need python and invoke installed on your local system. - -### Getting Started - -Initial project setup (after you have installed all required dev tools) is as follows: - -Generate initial translation files: - -``` -invoke translate -``` - -Install required flutter packages: -``` -flutter pub get -``` - -You should now be ready to debug on a connected or emulated device! - -### Building Release Versions - -Building release versions for target platforms (either android or iOS) is simplified using invoke: - -Build Android release: - -``` -invoke android -``` - -Build iOS release: - -``` -invoke ios -``` +Refer to the [build instructions](BUILDING.md) for information on how to build the app from source. diff --git a/android/app/build.gradle b/android/app/build.gradle index a20b12b..bdee7d8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,6 +31,16 @@ if (keystorePropertiesFile.exists()) { android { compileSdkVersion 34 + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + // If using Kotlin + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17 + } + sourceSets { main.java.srcDirs += 'src/main/kotlin' } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 2b22d05..829e1a5 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/assets/release_notes.md b/assets/release_notes.md index 9329ce1..8d3947b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ -### 0.17.0 - November 2024 +### 0.17.0 - December 2024 --- +- Improved barcode scanning with new scanning library - Enhanced home-screen display using grid-view - Improvements for image uploading - Provide "upload image" shortcut on Purchase Order detail view diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 460aecb..ea4cf63 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,10 +1,10 @@ -import "dart:io"; +import "dart:math"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; -import "package:qr_code_scanner/qr_code_scanner.dart"; +import "package:flutter_zxing/flutter_zxing.dart"; import "package:inventree/l10.dart"; @@ -26,197 +26,234 @@ class CameraBarcodeController extends InvenTreeBarcodeController { class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { _CameraBarcodeControllerState() : super(); - QRViewController? _controller; - bool flash_status = false; + int scan_delay = 500; bool single_scanning = false; bool scanning_paused = false; + String scanned_code = ""; + + @override + void initState() { + super.initState(); + _loadSettings(); + } + + /* + * Load the barcode scanning settings + */ Future _loadSettings() async { bool _single = await InvenTreeSettingsManager() .getBool(INV_BARCODE_SCAN_SINGLE, false); + int _delay = await InvenTreeSettingsManager() + .getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + if (mounted) { setState(() { + scan_delay = _delay; single_scanning = _single; scanning_paused = false; }); } } - /* Callback function when the Barcode scanner view is initially created */ - void _onViewCreated(BuildContext context, QRViewController controller) { - _controller = controller; - - controller.scannedDataStream.listen((barcode) { - if (!scanning_paused) { - handleBarcodeData(barcode.code).then((value) => { - // If in single-scanning mode, pause after successful scan - if (single_scanning && mounted) - { - setState(() { - scanning_paused = true; - }) - } - }); - } - }); - - _loadSettings(); - } - - // In order to get hot reload to work we need to pause the camera if the platform - // is android, or resume the camera if the platform is iOS. - @override - void reassemble() { - super.reassemble(); - - if (mounted) { - if (Platform.isAndroid) { - _controller!.pauseCamera(); - } - - _controller!.resumeCamera(); - } - } - - @override - void dispose() { - _controller?.dispose(); - super.dispose(); - } - @override Future pauseScan() async { - try { - await _controller?.pauseCamera(); - } on CameraException { - // do nothing - } - } - - @override - Future resumeScan() async { - // Do not attempt to resume if the widget is not mounted - if (!mounted) { - return; - } - - try { - await _controller?.resumeCamera(); - } on CameraException { - // do nothing - } - } - - // Toggle the status of the camera flash - Future updateFlashStatus() async { - final bool? status = await _controller?.getFlashStatus(); - if (mounted) { setState(() { - flash_status = status != null && status; + scanning_paused = true; }); } } @override - Widget build(BuildContext context) { - Widget actionIcon = - Icon(TablerIcons.player_pause, color: COLOR_WARNING, size: 64); + Future resumeScan() async { + if (mounted) { + setState(() { + scanning_paused = false; + }); + } + } + + /* + * Callback function when a barcode is scanned + */ + void _onScanSuccess(Code? code) { if (scanning_paused) { - actionIcon = - Icon(TablerIcons.player_play, color: COLOR_ACTION, size: 64); + return; } + String barcode_data = code?.text ?? ""; + + if (mounted) { + setState(() { + scanned_code = barcode_data; + scanning_paused = barcode_data.isNotEmpty; + }); + } + + if (barcode_data.isNotEmpty) { + handleBarcodeData(barcode_data).then((_) { + if (!single_scanning && mounted) { + // Resume next scan + setState(() { + scanning_paused = false; + }); + } + }); + } + + } + + /* + * Build the barcode scanner overlay + */ + FixedScannerOverlay BarcodeOverlay(BuildContext context) { + + // Note: Copied from reader_widget.dart:ReaderWidget.build + final Size size = MediaQuery.of(context).size; + final double cropSize = min(size.width, size.height) * 0.5; + + return FixedScannerOverlay( + borderColor: scanning_paused ? COLOR_WARNING : COLOR_ACTION, + overlayColor: Colors.black45, + borderRadius: 1, + borderLength: 15, + borderWidth: 8, + cutOutSize: cropSize, + ); + } + + /* + * Build the barcode reader widget + */ + Widget BarcodeReader(BuildContext context) { + + return ReaderWidget( + onScan: _onScanSuccess, + isMultiScan: false, + tryHarder: true, + tryInverted: true, + tryRotate: true, + showGallery: false, + scanDelay: Duration(milliseconds: scan_delay), + resolution: ResolutionPreset.high, + lensDirection: CameraLensDirection.back, + flashOnIcon: const Icon(Icons.flash_on), + flashOffIcon: const Icon(Icons.flash_off), + toggleCameraIcon: const Icon(TablerIcons.camera_rotate), + actionButtonsBackgroundBorderRadius: + BorderRadius.circular(40), + scannerOverlay: BarcodeOverlay(context), + actionButtonsBackgroundColor: Colors.black.withOpacity(0.7), + ); + } + + Widget topCenterOverlay() { + return SafeArea( + child: Align( + alignment: Alignment.topCenter, + child: Padding( + padding: EdgeInsets.all(10), + child: Text( + widget.handler.getOverlayText(context), + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold + ) + ) + ) + ) + ); + } + + Widget bottomCenterOverlay() { + String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; - return Scaffold( - appBar: AppBar( - backgroundColor: COLOR_APP_BAR, - title: Text(L10().scanBarcode), - actions: [ - IconButton( - icon: Icon(Icons.flip_camera_android), - onPressed: () { - _controller?.flipCamera(); - }), - IconButton( - icon: flash_status ? Icon(Icons.flash_off) : Icon(Icons.flash_on), - onPressed: () { - _controller?.toggleFlash(); - updateFlashStatus(); - }, + return SafeArea( + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: EdgeInsets.all(10), + child: Text( + scanned_code.isNotEmpty ? scanned_code : info_text, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold + ) + ), + ) + ) + ); + } + + + /* + * Display an overlay at the bottom right of the screen + */ + Widget bottomRightOverlay() { + return SafeArea( + child: Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: EdgeInsets.all(10), + child: ClipRRect( + borderRadius: BorderRadius.circular(40), + child: ColoredBox( + color: Colors.black45, + child: Row( + mainAxisSize: MainAxisSize.min, + children: scanning_paused ? [] : [ + CircularProgressIndicator( + value: null + ) + // actionIcon, + ] + ) + ) + ) ) + ) + ); + } + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: AppBar( + backgroundColor: COLOR_APP_BAR, + title: Text(L10().scanBarcode), + ), + body: GestureDetector( + onTap: () async { + setState(() { + scanning_paused = !scanning_paused; + }); + }, + child: Stack( + children: [ + Column( + children: [ + Expanded( + child: BarcodeReader(context) + ), + ], + ), + topCenterOverlay(), + bottomCenterOverlay(), + bottomRightOverlay(), ], ), - body: GestureDetector( - onTapDown: (details) async { - setState(() { - scanning_paused = !scanning_paused; - }); - }, - onLongPressEnd: (details) async { - if (mounted) { - setState(() { - scanning_paused = false; - }); - } - }, - child: Stack( - children: [ - Column(children: [ - Expanded( - child: QRView( - key: barcodeControllerKey, - onQRViewCreated: (QRViewController controller) { - _onViewCreated(context, controller); - }, - overlay: QrScannerOverlayShape( - borderColor: - scanning_paused ? COLOR_WARNING : COLOR_ACTION, - borderRadius: 10, - borderLength: 30, - borderWidth: 10, - cutOutSize: 300, - ), - )) - ]), - Center( - child: Column(children: [ - Padding( - child: Text( - widget.handler.getOverlayText(context), - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, color: Colors.white), - ), - padding: EdgeInsets.all(25)), - Padding( - child: CircularProgressIndicator( - value: scanning_paused ? 0 : null), - padding: EdgeInsets.all(40), - ), - Spacer(), - SizedBox( - child: Center( - child: actionIcon, - ), - width: 100, - height: 150, - ), - Padding( - child: Text(info_text, - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - )), - padding: EdgeInsets.all(25), - ), - ])) - ], - ))); + ), + ); } + } diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index a5e1b8a..20dc9e9 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -60,6 +60,7 @@ class BarcodeHandler { Future processBarcode(String barcode, {String url = "barcode/", Map extra_data = const {}}) async { + debug("Scanned barcode data: '${barcode}'"); barcode = barcode.trim(); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3db78e6..cbaeb35 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -274,6 +274,12 @@ "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", "@darkMode": {}, diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index a2e82aa..7b6b08d 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -174,7 +174,7 @@ class _InvenTreeAppSettingsState extends State { ListTile( title: Text(L10().darkMode), subtitle: Text(L10().darkModeEnable), - leading: Icon(TablerIcons.moon), + leading: Icon(TablerIcons.sun_moon), trailing: Switch( value: darkMode, onChanged: (bool value) { diff --git a/lib/settings/purchase_order_settings.dart b/lib/settings/purchase_order_settings.dart index d4211c2..5a3b430 100644 --- a/lib/settings/purchase_order_settings.dart +++ b/lib/settings/purchase_order_settings.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; @@ -39,7 +40,10 @@ class _InvenTreePurchaseOrderSettingsState extends State { key: _loginKey, appBar: AppBar( title: Text(L10().profileSelect), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( icon: Icon(TablerIcons.circle_plus), diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index e6cfcd7..ab9c61c 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -208,11 +208,8 @@ class _AttachmentWidgetState extends RefreshableState { if (tiles.isEmpty) { tiles.add(ListTile( + leading: Icon(TablerIcons.file_x, color: COLOR_WARNING), title: Text(L10().attachmentNone), - subtitle: Text( - L10().attachmentNoneDetail, - style: TextStyle(fontStyle: FontStyle.italic), - ), )); } diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 1fbbbe4..2288e34 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -1,3 +1,4 @@ +import "package:adaptive_theme/adaptive_theme.dart"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -185,6 +186,28 @@ class InvenTreeDrawer extends StatelessWidget { ) ); + tiles.add(Divider()); + + bool darkMode = AdaptiveTheme.of(context).mode.isDark; + + tiles.add( + ListTile( + onTap: () { + AdaptiveTheme.of(context).toggleThemeMode(); + _closeDrawer(); + }, + title: Text(L10().colorScheme), + subtitle: Text(L10().colorSchemeDetail), + leading: Icon( + TablerIcons.sun_moon, + color: COLOR_ACTION + ), + trailing: Icon( + darkMode ? TablerIcons.moon : TablerIcons.sun, + ) + ) + ); + tiles.add( ListTile( title: Text(L10().settings), diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index d18d07c..f20462c 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -101,7 +101,7 @@ mixin BaseWidgetProperties { }, ), IconButton( - icon: Icon(Icons.barcode_reader, color: COLOR_ACTION), + icon: Icon(TablerIcons.barcode, color: COLOR_ACTION), iconSize: iconSize, onPressed: () { if (InvenTreeAPI().checkConnection()) { diff --git a/pubspec.lock b/pubspec.lock index 6cd6d6f..afda72c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -210,10 +210,10 @@ packages: dependency: transitive description: name: cli_util - sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.3.5" + version: "0.4.2" clock: dependency: transitive description: @@ -391,10 +391,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c + sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" url: "https://pub.dev" source: hosted - version: "0.11.0" + version: "0.14.1" flutter_localizations: dependency: "direct main" description: flutter @@ -466,6 +466,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_zxing: + dependency: "direct main" + description: + name: flutter_zxing + sha256: "5b2670f151a6d96643204ff3a781e073739c23a91ef5fc39742bf13fb8287b4c" + url: "https://pub.dev" + source: hosted + version: "1.8.2" frontend_server_client: dependency: transitive description: @@ -510,10 +518,10 @@ packages: dependency: transitive description: name: image - sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "4.3.0" image_picker: dependency: "direct main" description: @@ -750,10 +758,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 + sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "8.1.1" package_info_plus_platform_interface: dependency: transitive description: @@ -858,14 +866,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - qr_code_scanner: - dependency: "direct main" - description: - name: qr_code_scanner - sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd - url: "https://pub.dev" - source: hosted - version: "1.0.1" rxdart: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5cbee61..496fd1c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,22 +27,22 @@ dependencies: flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation flutter_tabler_icons: ^1.35.0 + flutter_zxing: ^1.8.2 # Barcode scanning http: ^1.2.2 image_picker: ^1.1.2 # Select or take photos infinite_scroll_pagination: ^4.0.0 # Let the server do all the work! intl: ^0.19.0 one_context: ^4.0.0 # Dialogs without requiring context open_filex: ^4.5.0 # Open local files - package_info_plus: ^8.0.2 # App information introspection + package_info_plus: ^8.1.1 # App information introspection path: ^1.9.0 path_provider: ^2.1.3 # Local file storage - qr_code_scanner: ^1.0.1 # Barcode scanning sembast: ^3.6.0 # NoSQL data storage sentry_flutter: 8.9.0 # Error reporting url_launcher: ^6.3.0 # Open link in system browser dev_dependencies: - flutter_launcher_icons: ^0.11.0 + flutter_launcher_icons: ^0.14.1 flutter_test: sdk: flutter lint: ^2.1.2 From b849bfc7181d885a6cca6b351ffe961b74e22292 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 6 Dec 2024 10:31:57 +1100 Subject: [PATCH 518/746] New Crowdin updates (#563) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++ lib/l10n/da_DK/app_da_DK.arb | 4 ++ lib/l10n/de_DE/app_de_DE.arb | 4 ++ lib/l10n/el_GR/app_el_GR.arb | 4 ++ lib/l10n/es_ES/app_es_ES.arb | 4 ++ lib/l10n/es_MX/app_es_MX.arb | 88 +++++++++++++++++++----------------- lib/l10n/et_EE/app_et_EE.arb | 4 ++ lib/l10n/fa_IR/app_fa_IR.arb | 4 ++ lib/l10n/fi_FI/app_fi_FI.arb | 4 ++ lib/l10n/fr_FR/app_fr_FR.arb | 4 ++ lib/l10n/he_IL/app_he_IL.arb | 4 ++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++ lib/l10n/id_ID/app_id_ID.arb | 4 ++ lib/l10n/it_IT/app_it_IT.arb | 4 ++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++ lib/l10n/nl_NL/app_nl_NL.arb | 4 ++ lib/l10n/no_NO/app_no_NO.arb | 4 ++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++ lib/l10n/pt_PT/app_pt_PT.arb | 4 ++ lib/l10n/ro_RO/app_ro_RO.arb | 4 ++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++ lib/l10n/th_TH/app_th_TH.arb | 4 ++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++ lib/l10n/zh_CN/app_zh_CN.arb | 4 ++ lib/l10n/zh_TW/app_zh_TW.arb | 4 ++ 38 files changed, 194 insertions(+), 42 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 321e957..778fe56 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 298fb6c..2b963a5 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 065d0fe..a508181 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Poškozeno", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Tmavý motiv", "@darkMode": {}, "darkModeEnable": "Nastaví tmavý motiv aplikace", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index d633a12..a85929f 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 8176417..b7fda18 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Beschädigt", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dunkles Design", "@darkMode": {}, "darkModeEnable": "Dunkles Design aktivieren", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 4e84375..c342e68 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 10d98af..c95f617 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Modo oscuro", "@darkMode": {}, "darkModeEnable": "Activar modo oscuro", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index cc8f5b2..1bf9683 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -84,17 +84,17 @@ "@barcodeNotAssigned": {}, "barcodeScanPart": "Escanear código de barras de parte", "@barcodeScanPart": {}, - "barcodeReceivePart": "Scan barcode to receive part", + "barcodeReceivePart": "Escanear código de barras para recibir parte", "@barcodeReceivePart": {}, "barcodeScanPaused": "Escaneo de código de barras en pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Toque o mantenga pulsado para pausar el escaneo", "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, - "barcodeScanController": "Scanner Input", + "barcodeScanController": "Entrada de escáner", "@barcodeScanController": {}, - "barcodeScanControllerDetail": "Select barcode scanner input source", + "barcodeScanControllerDetail": "Seleccionar fuente de entrada del escáner de código de barras", "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Retraso de escaneo de código de barras", "@barcodeScanDelay": {}, @@ -106,9 +106,9 @@ "@barcodeScanInItems": {}, "barcodeScanLocation": "Escanear ubicación de Inventario", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Modo de escaneo único", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Pausar el escáner de código de barras después de cada escaneado", "@barcodeScanSingleDetail": {}, "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", "@barcodeScanIntoLocationSuccess": {}, @@ -134,9 +134,9 @@ "@build": {}, "building": "Construyendo", "@building": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Cámara interna", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", "@cameraInternalDetail": {}, "cancel": "Cancelar", "@cancel": { @@ -164,9 +164,9 @@ "@companies": {}, "configureServer": "Configurar ajustes del servidor", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Confirmar transferencia", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Confirmar detalles de transferencia de stock al escanear códigos de barras", "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Número", @@ -179,14 +179,18 @@ }, "credits": "Créditos", "@credits": {}, - "customer": "Customer", + "customer": "Cliente", "@customer": {}, "customers": "Clientes", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Referencia del Cliente", "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, + "colorScheme": "Esquema de colores", + "@colorScheme": {}, + "colorSchemeDetail": "Seleccionar esquema de color", + "@colorSchemeDetail": {}, "darkMode": "Modo Oscuro", "@darkMode": {}, "darkModeEnable": "Habilitar modo oscuro", @@ -324,9 +328,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Mostrar Órdenes de Venta", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Mostrar botón de órdenes de ventas en la pantalla de inicio", "@homeShowSoDescription": {}, "homeShowSubscribed": "Partes Suscritas", "@homeShowSubscribed": {}, @@ -350,7 +354,7 @@ "@imageUploadSuccess": {}, "inactive": "Inactivo", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Esta empresa está marcada como inactiva", "@inactiveCompany": {}, "inactiveDetail": "Esta parte está marcada como inactiva", "@inactiveDetail": {}, @@ -398,7 +402,7 @@ "@issueOrder": {}, "itemInLocation": "El artículo ya está en la ubicación", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "El artículo ha sido eliminado", "@itemDeleted": {}, "keywords": "Palabras claves", "@keywords": {}, @@ -444,7 +448,7 @@ "@login": {}, "loginEnter": "Ingresar datos de acceso", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Nombre de usuario y contraseña no se almacenan localmente", "@loginEnterDetails": {}, "link": "Vincular", "@link": {}, @@ -496,11 +500,11 @@ "@orientationSystem": {}, "outstanding": "Pendiente", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Mostrar pedidos destacados", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Vencido", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Mostrar pedidos vencidos", "@overdueDetail": {}, "packaging": "Embalaje", "@packaging": {}, @@ -530,7 +534,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Parte no marcada como vendible", "@partNotSalable": {}, "partsNone": "Sin Partes", "@partsNone": {}, @@ -590,7 +594,7 @@ "@profileEdit": {}, "profileDelete": "Eliminar perfil del servidor", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Cerrar sesión", "@profileLogout": {}, "profileName": "Nombre de perfil", "@profileName": {}, @@ -606,13 +610,13 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Habilitar órdenes de compra", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Habilitar funcionalidad de orden de compra", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Acceso directo a la cámara", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, @@ -620,7 +624,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Ajustes de la orden de compra", "@purchaseOrderSettings": {}, "purchaseOrders": "Órdenes de compra", "@purchaseOrders": {}, @@ -724,25 +728,25 @@ }, "returned": "Devuelto", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Orden de venta", "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Activar pedidos de venta", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Habilitar funcionalidad de orden de ventas", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Acceso directo a la cámara", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Ajustes del pedido de ventas", "@salesOrderSettings": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Nueva orden de venta", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Editar orden de venta", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Orden de venta actualizada", "@salesOrderUpdated": {}, "save": "Guardar", "@save": { @@ -750,17 +754,17 @@ }, "scanBarcode": "Escanear código de barras", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Escanear código de barras del proveedor", "@scanSupplierPart": {}, "scanIntoLocation": "Escanear a la ubicación", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Escanear este artículo en su ubicación", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Escáner externo", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Usar escáner externo para leer códigos de barras (modo cuña)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Escanear partes recibidas", "@scanReceivedParts": {}, "search": "Buscar", "@search": { @@ -990,9 +994,9 @@ "@translate": {}, "translateHelp": "Ayuda a traducir la aplicación InvenTree", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "No disponible", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Artículo no disponible", "@unavailableDetail": {}, "unitPrice": "Precio unitario", "@unitPrice": {}, diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index d0cb525..f037a5a 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Kahjustatud", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Tume režiim", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index b0be0ca..b47c875 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index d128df1..81802e4 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Vahingoittunut", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Tumma tila", "@darkMode": {}, "darkModeEnable": "Käytä tummaa tilaa", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 510fd3e..d2eb80d 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Endommagé", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Mode Sombre", "@darkMode": {}, "darkModeEnable": "Activer le mode sombre", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 0d9cd18..eb421ec 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "מלאי פגום", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "מצב כהה", "@darkMode": {}, "darkModeEnable": "הפעל מצב כהה", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 208e41e..b781904 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 4d10207..bc91ab4 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Sérült", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Sötét mód", "@darkMode": {}, "darkModeEnable": "Sötét mód engedélyezése", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index d3a5448..adc5a99 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Rusak", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Mode Gelap", "@darkMode": {}, "darkModeEnable": "Aktifkan mode gelap", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index b84bae5..1a40d74 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Danneggiato", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Modalità Scura", "@darkMode": {}, "darkModeEnable": "Abilita modalità scura", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index a37b74c..7def1cb 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "破損", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index c24ff05..6a5c2ed 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 9f781d9..de5d6ef 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index fe11a8b..4891991 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 131301b..f631bf8 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Beschadigd", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Donkere Modus", "@darkMode": {}, "darkModeEnable": "Donkere modus inschakelen", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 52f5f5b..bc305ef 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Skadet", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Mørk Modus", "@darkMode": {}, "darkModeEnable": "Aktiver mørk modus", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 5804963..9ca04e7 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Uszkodzone", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Tryb ciemny", "@darkMode": {}, "darkModeEnable": "Włącz tryb ciemny", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 8d455c4..292f78f 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Modo Escuro", "@darkMode": {}, "darkModeEnable": "Habilitar o modo escuro", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index f62dd62..4589f6d 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Modo Noturno", "@darkMode": {}, "darkModeEnable": "Ativar modo noturno", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 7bd3d34..42346e0 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Deteriorat", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Mod Întunecat", "@darkMode": {}, "darkModeEnable": "Activează modul întunecat", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index c7d86e1..e1c931c 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Поврежденный", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Тёмная тема", "@darkMode": {}, "darkModeEnable": "Включить тёмную тему", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index c4ca84f..86cb7ab 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 071d394..1577fda 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index fdd552a..268a9ea 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index d14242a..e076b2f 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Skadad", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Mörkt läge", "@darkMode": {}, "darkModeEnable": "Aktivera mörkt läge", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index d4c917d..2ec3059 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index ef698b2..bcdc96f 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Hasarlı", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Koyu Tema", "@darkMode": {}, "darkModeEnable": "Koyu temayı etkinleştir", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index d6a2784..24aca40 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Damaged", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Dark Mode", "@darkMode": {}, "darkModeEnable": "Enable dark mode", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 0288bae..b79f447 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "Bị hỏng", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "Chế độ tối", "@darkMode": {}, "darkModeEnable": "Bật Chế độ nền tối", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index e31464a..6a2e6e0 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "破损", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "暗黑模式", "@darkMode": {}, "darkModeEnable": "启用暗黑模式", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 258ac86..b5bde62 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -187,6 +187,10 @@ "@customerReference": {}, "damaged": "已損壞", "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, "darkMode": "深色模式", "@darkMode": {}, "darkModeEnable": "啟用深色模式", From 6f5fc1d8a97aaa626a8b4bd78b88e5de73b508f7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 6 Dec 2024 10:59:49 +1100 Subject: [PATCH 519/746] Test result fixes (#564) * Fix association of test results to templates * Fixes * Remove unused vars --- lib/api.dart | 4 ++ lib/api_form.dart | 6 +++ lib/inventree/model.dart | 9 ++-- lib/inventree/stock.dart | 33 +++++++++++-- lib/widget/stock/stock_item_test_results.dart | 46 ++++++++++++------- 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 0a1e706..704b7df 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -316,6 +316,10 @@ class InvenTreeAPI { // Does the server support allocating stock to sales order using barcodes? bool get supportsBarcodeSOAllocateEndpoint => isConnected() && apiVersion >= 160; + // Does the server support the "modern" test results API + // Ref: https://github.com/inventree/InvenTree/pull/6430/ + bool get supportsModernTestResults => isConnected() && apiVersion >= 169; + // Does the server support "null" top-level filtering for PartCategory and StockLocation endpoints? bool get supportsNullTopLevelFiltering => isConnected() && apiVersion < 174; diff --git a/lib/api_form.dart b/lib/api_form.dart index c22877d..432e49c 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -657,7 +657,13 @@ class APIFormField { ) : null, leading: extended ? InvenTreeAPI().getThumbnail(part.thumbnail) : null, ); + case "parttesttemplate": + var template = InvenTreePartTestTemplate.fromJson(data); + return ListTile( + title: Text(template.testName), + subtitle: Text(template.description), + ); case "supplierpart": var part = InvenTreeSupplierPart.fromJson(data); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 852454d..6d0e890 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -97,7 +97,6 @@ class InvenTreeModel { if (data.containsKey(key)) { return data[key]; } else { - debug("JSON data does not contain key '$key' (subKey '${subKey}')"); return backup; } } @@ -427,13 +426,17 @@ class InvenTreeModel { } } - Map defaultListFilters() { + Map defaultFilters() { return {}; } + Map defaultListFilters() { + return defaultFilters(); + } + // A map of "default" headers to use when performing a GET request Map defaultGetFilters() { - return {}; + return defaultFilters(); } /* diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index bd7a6cf..df15803 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -27,19 +27,43 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { List get rolesRequired => ["stock"]; @override - Map> formFields() { + Map defaultFilters() { return { + "user_detail": "true", + "template_detail": "true", + }; + } + + @override + Map> formFields() { + + Map> fields = { "stock_item": {"hidden": true}, "test": {}, + "template": { + "filters": { + "enabled": "true", + } + }, "result": {}, "value": {}, "notes": {}, "attachment": {}, }; + + if (InvenTreeAPI().supportsModernTestResults) { + fields.remove("test"); + } else { + fields.remove("template"); + } + + return fields; } String get key => getString("key"); - + + int get templateId => getInt("template"); + String get testName => getString("test"); bool get result => getBool("result"); @@ -47,7 +71,9 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { String get value => getString("value"); String get attachment => getString("attachment"); - + + String get username => getString("username", subKey: "user_detail"); + String get date => getString("date"); @override @@ -256,6 +282,7 @@ class InvenTreeStockItem extends InvenTreeModel { await InvenTreePartTestTemplate().list( filters: { "part": "${partId}", + "enabled": "true", }, ).then((var templates) { testTemplates.clear(); diff --git a/lib/widget/stock/stock_item_test_results.dart b/lib/widget/stock/stock_item_test_results.dart index c65422d..d1671e5 100644 --- a/lib/widget/stock/stock_item_test_results.dart +++ b/lib/widget/stock/stock_item_test_results.dart @@ -62,12 +62,19 @@ class _StockItemTestResultDisplayState extends RefreshableState addTestResult(BuildContext context, {String name = "", bool nameIsEditable = true, bool result = false, String value = "", bool valueRequired = false, bool attachmentRequired = false}) async { + Future addTestResult(BuildContext context, {int templateId = 0, String name = "", bool nameIsEditable = true, bool result = false, String value = "", bool valueRequired = false, bool attachmentRequired = false}) async { + + Map> fields = InvenTreeStockItemTestResult().formFields(); + + // Add additional filters + fields["template"]?["filters"]?["part"] = "${item.partId}"; InvenTreeStockItemTestResult().createForm( context, L10().testResultAdd, + fields: fields, data: { + "template": "${templateId}", "stock_item": "${item.pk}", "test": "${name}", }, @@ -98,10 +105,11 @@ class _StockItemTestResultDisplayState extends RefreshableState Date: Fri, 6 Dec 2024 11:11:47 +1100 Subject: [PATCH 520/746] Screen wake (#565) * Prevent screen turning off when scanning barcodes - Close https://github.com/inventree/inventree-app/issues/492 * Update release notes --- assets/release_notes.md | 2 ++ lib/barcode/camera_controller.dart | 9 ++++++++- pubspec.lock | 24 ++++++++++++++++++++++++ pubspec.yaml | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 8d3947b..93c8ad8 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,8 @@ --- - Improved barcode scanning with new scanning library +- Prevent screen turning off when scanning barcodes +- Improved support for Stock Item test results - Enhanced home-screen display using grid-view - Improvements for image uploading - Provide "upload image" shortcut on Purchase Order detail view diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index ea4cf63..2e40ef4 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -3,7 +3,7 @@ import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; - +import "package:wakelock_plus/wakelock_plus.dart"; import "package:flutter_zxing/flutter_zxing.dart"; import "package:inventree/l10.dart"; @@ -38,6 +38,13 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { void initState() { super.initState(); _loadSettings(); + WakelockPlus.enable(); + } + + @override + void dispose() { + super.dispose(); + WakelockPlus.disable(); } /* diff --git a/pubspec.lock b/pubspec.lock index afda72c..2a5876e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -286,6 +286,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" device_info_plus: dependency: "direct main" description: @@ -1207,6 +1215,22 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.5" + wakelock_plus: + dependency: "direct main" + description: + name: wakelock_plus + sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + url: "https://pub.dev" + source: hosted + version: "1.2.8" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + url: "https://pub.dev" + source: hosted + version: "1.2.1" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 496fd1c..2bcb6ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: sembast: ^3.6.0 # NoSQL data storage sentry_flutter: 8.9.0 # Error reporting url_launcher: ^6.3.0 # Open link in system browser + wakelock_plus: ^1.2.8 # Prevent device from sleeping dev_dependencies: flutter_launcher_icons: ^0.14.1 From 5dab11ee0cb077e96c1df2930941a26823a75a8c Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 6 Dec 2024 12:51:02 +1100 Subject: [PATCH 521/746] Bug fix for list filtering (#566) - Observe "tristate" values --- assets/release_notes.md | 2 ++ lib/widget/paginator.dart | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 93c8ad8..d1f0195 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -9,6 +9,8 @@ - Provide "upload image" shortcut on Purchase Order detail view - Provide "upload image" shortcut on Sales Order detail view - Clearly indicate if a StockItem is unavailable +- Improved list filtering management +- Updated translations ### 0.16.5 - September 2024 --- diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 44d3064..bc3df6d 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -50,7 +50,9 @@ abstract class PaginatedSearchState extends Sta key = "${prefix}filter_${key}"; Map opts = filterOptions[key] ?? {}; - dynamic backup = opts["default"]; + + bool tristate = (opts["tristate"] ?? true) as bool; + dynamic backup = tristate ? null : opts["default"]; final result = await InvenTreeSettingsManager().getValue(key, backup); return result; @@ -59,7 +61,12 @@ abstract class PaginatedSearchState extends Sta // Set the boolean value of a particular boolean filter Future setFilterValue(String key, dynamic value) async { key = "${prefix}filter_${key}"; - await InvenTreeSettingsManager().setValue(key, value); + + if (value == null) { + await InvenTreeSettingsManager().removeValue(key); + } else { + await InvenTreeSettingsManager().setValue(key, value); + } } // Construct the boolean filter options for this list From 3f7c2feeb7cd085c8c2004dbf4a025f169ecc79e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 9 Dec 2024 23:06:04 +1100 Subject: [PATCH 522/746] New Crowdin updates (#567) * New translations app_en.arb (Spanish) * New translations app_en.arb (Polish) * New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_ES/app_es_ES.arb | 24 ++++++++++++------------ lib/l10n/es_MX/app_es_MX.arb | 4 ++-- lib/l10n/pl_PL/app_pl_PL.arb | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index c95f617..8ec6959 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -187,9 +187,9 @@ "@customerReference": {}, "damaged": "Dañado", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Combinación de colores", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Seleccionar combinación de colores", "@colorSchemeDetail": {}, "darkMode": "Modo oscuro", "@darkMode": {}, @@ -610,13 +610,13 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Habilitar órdenes de compra", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Activar funcionalidad de orden de compra", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Acceso directo a la cámara", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Orden de compra", "@purchaseOrder": {}, @@ -624,7 +624,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modificar orden de compra", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Ajustes de orden de compra", "@purchaseOrderSettings": {}, "purchaseOrders": "Ordenes de compra", "@purchaseOrders": {}, @@ -732,15 +732,15 @@ "@salesOrder": {}, "salesOrders": "Órdenes de venta", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Activar órdenes de venta", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Activar funcionalidad de orden de ventas", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Acceso directo a la cámara", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de ventas", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Ajustes de órdenes de ventas", "@salesOrderSettings": {}, "salesOrderCreate": "Nueva orden de venta", "@saleOrderCreate": {}, diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 1bf9683..3a7c49d 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -197,13 +197,13 @@ "@darkModeEnable": {}, "delete": "Eliminar", "@delete": {}, - "deleteFailed": "Operación de borrado fallida", + "deleteFailed": "Operación de eliminación fallida", "@deleteFailed": {}, "deletePart": "Eliminar parte", "@deletePart": {}, "deletePartDetail": "Eliminar esta parte de la base de datos", "@deletePartDetail": {}, - "deleteSuccess": "Operación de borrado exitosa", + "deleteSuccess": "Operación de eliminación exitosa", "@deleteSuccess": {}, "description": "Descripción", "@description": {}, diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 9ca04e7..4e8a1b4 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -187,9 +187,9 @@ "@customerReference": {}, "damaged": "Uszkodzone", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Schemat kolorów", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Wybierz schemat kolorów", "@colorSchemeDetail": {}, "darkMode": "Tryb ciemny", "@darkMode": {}, @@ -301,7 +301,7 @@ "@filterTemplateDetail": {}, "filterTrackable": "Możliwość śledzenia", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Pokaż aktywne części", "@filterTrackableDetail": {}, "filterVirtual": "Wirtualny", "@filterVirtual": {}, @@ -498,7 +498,7 @@ "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Zaległe", "@outstanding": {}, "outstandingOrderDetail": "Pokaż oczekujące zamówienia", "@outstandingOrderDetail": {}, From f7d179e0411e28fbca2ba02dd6009e9006b7b8ca Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:30:02 +1100 Subject: [PATCH 523/746] Assigned to me filter (#568) * Add "assigned to me" order filter * Update version and release notes --- assets/release_notes.md | 6 ++++++ lib/l10n/app_en.arb | 6 ++++++ lib/widget/order/purchase_order_list.dart | 5 +++++ lib/widget/order/sales_order_list.dart | 5 +++++ pubspec.yaml | 2 +- 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index d1f0195..4f75c9c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.17.1 - January 2025 +--- + +- Adds "assigned to me" filter for Purchase Order list +- Adds "assigned to me" filter for Sales Order list + ### 0.17.0 - December 2024 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cbaeb35..3ce9866 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -62,6 +62,12 @@ "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "Attachments", "@attachments": {}, diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart index f19306c..2f15004 100644 --- a/lib/widget/order/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -149,6 +149,11 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState=2.19.5 <3.13.0" From d072c7721881ad655277d58c8a57a8ffb59ed411 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:02 +1100 Subject: [PATCH 524/746] New translations app_en.arb (Italian) --- lib/l10n/it_IT/app_it_IT.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 1a40d74..b7a0a9c 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Allegati", "@attachments": {}, "attachImage": "Allega Immagine", From fc2675064125b5dece464e9d84dfefd2204b70b2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:03 +1100 Subject: [PATCH 525/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index d2eb80d..a1e9613 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Pieces jointes", "@attachments": {}, "attachImage": "Ajouter une image", From b25e76318868ac3a220da67e49cdbd3d5d765cfe Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:04 +1100 Subject: [PATCH 526/746] New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 8ec6959..6fee832 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Adjuntos", "@attachments": {}, "attachImage": "Adjuntar Imagen", From 31dc193fa1dce8e365f95898a91fa6ba93ed355c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:05 +1100 Subject: [PATCH 527/746] New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index a508181..6ec0b77 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurovat nastavení aplikace InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Přílohy", "@attachments": {}, "attachImage": "Připojit obrázek", From d008011fcca7aedbb117f924946ffd2c30be7d0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:07 +1100 Subject: [PATCH 528/746] New translations app_en.arb (Greek) --- lib/l10n/el_GR/app_el_GR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index c342e68..7e22db9 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Διαμόρφωση ρυθμίσεων της εφαρμογής InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Συνημμένα", "@attachments": {}, "attachImage": "Επισύναψη Εικόνας", From 2658734a89c4d1cf6c55d2bb22dc6a9a01ea365f Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:08 +1100 Subject: [PATCH 529/746] New translations app_en.arb (Hebrew) --- lib/l10n/he_IL/app_he_IL.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index eb421ec..793206b 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "הגדר את הגדרות אפליקציית Inventree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "קבצים מצורפים", "@attachments": {}, "attachImage": "צירוף תמונה", From 6af819de0cba7fbba944b0c0c962d5a1a1924189 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:09 +1100 Subject: [PATCH 530/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index f631bf8..2884aa0 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configureer InvenTree app instellingen", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Bijlagen", "@attachments": {}, "attachImage": "Voeg afbeelding toe", From 66587e71ef211630c443a5c9b2638fc91eef2d20 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:11 +1100 Subject: [PATCH 531/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 4e8a1b4..0198c9b 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Załączniki", "@attachments": {}, "attachImage": "Dodaj zdjęcie", From ac567974985d5fe16b6504323554edf23bc9f984 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:12 +1100 Subject: [PATCH 532/746] New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index e1c931c..1c9a9bb 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Изменить настройки приложения InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Вложения", "@attachments": {}, "attachImage": "Прикрепить изображение", From 0c2957ae70bf5bb62f44669d4c6e35a0fdefb926 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:13 +1100 Subject: [PATCH 533/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index bcdc96f..f3927cc 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Uygulama ayarlarından yapılandır", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Ekler", "@attachments": {}, "attachImage": "Resim ekle", From 048c25267f851cb796829a77c186e1d571e8f8fc Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:14 +1100 Subject: [PATCH 534/746] New translations app_en.arb (Chinese Traditional) --- lib/l10n/zh_TW/app_zh_TW.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index b5bde62..6e06908 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "配置 InvenTree 應用程式設定", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "附件", "@attachments": {}, "attachImage": "附加影像", From 9d8668745c606111ff818f29b38246f0d8a961f1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:15 +1100 Subject: [PATCH 535/746] New translations app_en.arb (Indonesian) --- lib/l10n/id_ID/app_id_ID.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index adc5a99..4fe0cf8 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurasikan pengaturan aplikasi InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Lampiran", "@attachments": {}, "attachImage": "Melampirkan Gambar", From ff40777d942a212c58d5cc95cc607ffb9f1664de Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:16 +1100 Subject: [PATCH 536/746] New translations app_en.arb (Persian) --- lib/l10n/fa_IR/app_fa_IR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index b47c875..e00406b 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "پیکربندی تنظیمات برنامه ", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "پیوست ها", "@attachments": {}, "attachImage": "پیوست تصویر", From 8b5548f926ec1db6e883a950b7b684f226174ba6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:18 +1100 Subject: [PATCH 537/746] New translations app_en.arb (Estonian) --- lib/l10n/et_EE/app_et_EE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index f037a5a..5d8a0c6 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Manused", "@attachments": {}, "attachImage": "Lisa pilte", From 79618ba298be794baf0db099d73f5d685fbeb14b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:19 +1100 Subject: [PATCH 538/746] New translations app_en.arb (Romanian) --- lib/l10n/ro_RO/app_ro_RO.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 42346e0..8f496dd 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurare setări aplicație InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Atașamente", "@attachments": {}, "attachImage": "Atașare imagine", From c9e0f90be9a14e3f6d59962818f97aaafffbd1da Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:20 +1100 Subject: [PATCH 539/746] New translations app_en.arb (Arabic) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 778fe56..90b9d45 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From 8348c55f63166fae8f42e036b24245c389ceeaed Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:21 +1100 Subject: [PATCH 540/746] New translations app_en.arb (Bulgarian) --- lib/l10n/bg_BG/app_bg_BG.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 2b963a5..4322e66 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From 5589afaebf1e3663e8a3f3c71750e9d31dd663b5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:22 +1100 Subject: [PATCH 541/746] New translations app_en.arb (Danish) --- lib/l10n/da_DK/app_da_DK.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index a85929f..e732c3b 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurer InvenTree app-indstillinger", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Vedhæftede filer", "@attachments": {}, "attachImage": "Vedhæft billede", From 73c4ef270e62da7e33b938603a9ee99aa09926d2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:24 +1100 Subject: [PATCH 542/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index b7fda18..6875ea0 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Anhänge", "@attachments": {}, "attachImage": "Bild hinzufügen", From 9420bf450ac039baaf9795434147340914c04060 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:25 +1100 Subject: [PATCH 543/746] New translations app_en.arb (Finnish) --- lib/l10n/fi_FI/app_fi_FI.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 81802e4..c105037 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Määritä InvenTree sovelluksen asetukset", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Liitteet", "@attachments": {}, "attachImage": "Liitä kuva", From 237d812e51e58982a61aafd2a318fb8f8e2fc5f0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:26 +1100 Subject: [PATCH 544/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index bc91ab4..20b2558 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Inventree alkalmazás beállításai", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Mellékletek", "@attachments": {}, "attachImage": "Kép csatolása", From 776f0e0ea512eb7fc24e937d26a0f6eebf9b545b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:27 +1100 Subject: [PATCH 545/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 7def1cb..601f684 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "アプリ設定を構成します", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "添付ファイル", "@attachments": {}, "attachImage": "画像を添付", From 6f9995ed3a2eb4458058ab85360c09025acffc7e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:29 +1100 Subject: [PATCH 546/746] New translations app_en.arb (Korean) --- lib/l10n/ko_KR/app_ko_KR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 6a5c2ed..c5f5cf4 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From 6e0e099de8964a107b4850738893f19adb2de511 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:30 +1100 Subject: [PATCH 547/746] New translations app_en.arb (Lithuanian) --- lib/l10n/lt_LT/app_lt_LT.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index de5d6ef..60d6c92 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From b83ee998f0dea90766cbcf8054088c002519ee25 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:31 +1100 Subject: [PATCH 548/746] New translations app_en.arb (Norwegian) --- lib/l10n/no_NO/app_no_NO.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index bc305ef..0a021b2 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurer InvenTree appinnstillinger", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Vedlegg", "@attachments": {}, "attachImage": "Legg ved bilde", From 58585cb213486f53af1cda724f6c3eee747b1ef7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:32 +1100 Subject: [PATCH 549/746] New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 4589f6d..48307d9 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurar os parâmetros do InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Anexos", "@attachments": {}, "attachImage": "Anexar Imagem", From 0f49298401d4fb856f294e7ef265f10dbe3db74e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:33 +1100 Subject: [PATCH 550/746] New translations app_en.arb (Slovak) --- lib/l10n/sk_SK/app_sk_SK.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 86cb7ab..ab51751 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From dd9f326dcb61053687e8cc65d8c524fa812ca815 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:35 +1100 Subject: [PATCH 551/746] New translations app_en.arb (Slovenian) --- lib/l10n/sl_SI/app_sl_SI.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 1577fda..7b78afc 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From de4546995420a1c5d62a2804a6a608018d295eba Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:36 +1100 Subject: [PATCH 552/746] New translations app_en.arb (Swedish) --- lib/l10n/sv_SE/app_sv_SE.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index e076b2f..96e85a5 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurera inställningar för InvenTree app", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Bilagor", "@attachments": {}, "attachImage": "Bifoga bild", From ac3841a102ee4d5f4697424a56b2524d9a1a47b7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:37 +1100 Subject: [PATCH 553/746] New translations app_en.arb (Ukrainian) --- lib/l10n/uk_UA/app_uk_UA.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 24aca40..16c6520 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From 9f392aaff758f3f1c991b38b70800b84802c06be Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:38 +1100 Subject: [PATCH 554/746] New translations app_en.arb (Chinese Simplified) --- lib/l10n/zh_CN/app_zh_CN.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 6a2e6e0..47169bd 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "配置 InvenTree app 设置项", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "附件", "@attachments": {}, "attachImage": "附加图片", From d9f08b3128def9ea82ef4fc3f6b4248f59c173cc Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:39 +1100 Subject: [PATCH 555/746] New translations app_en.arb (Vietnamese) --- lib/l10n/vi_VN/app_vi_VN.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index b79f447..bdc1bb4 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Cấu hình cài đặt ứng dụng", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Tập tin đính kèm", "@attachments": {}, "attachImage": "Hình ảnh đính kèm", From 493f83ef9a2d597947bbb1aeab421b92c1a539ea Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:40 +1100 Subject: [PATCH 556/746] New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/pt_BR/app_pt_BR.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 292f78f..de96e14 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurar os parâmetros do App do InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Anexos", "@attachments": {}, "attachImage": "Anexar imagem", From 42fc7960199a4c5d4c6eeb6832fe737f68bf1054 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:42 +1100 Subject: [PATCH 557/746] New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_MX/app_es_MX.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 3a7c49d..6aae33f 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Adjuntos", "@attachments": {}, "attachImage": "Adjuntar Imagen", From 1e7232a6884ebb7ca9bf4f727e4a52e0851ee566 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:43 +1100 Subject: [PATCH 558/746] New translations app_en.arb (Thai) --- lib/l10n/th_TH/app_th_TH.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 2ec3059..a6c4481 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "การตั้งค่าแอพ Inventree", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "ไฟล์แนบ", "@attachments": {}, "attachImage": "แนบรูปภาพ", From a08f64a2a23cccdf0d2c6e124e38ff93d4d9d280 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:44 +1100 Subject: [PATCH 559/746] New translations app_en.arb (Latvian) --- lib/l10n/lv_LV/app_lv_LV.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 4891991..2ae70cc 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From 3e1018c6ade3818252136697e95268ac31e9be7d Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:45 +1100 Subject: [PATCH 560/746] New translations app_en.arb (Hindi) --- lib/l10n/hi_IN/app_hi_IN.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index b781904..36edfe5 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From d5d1573eb3384432e5591c418558e5957f4db5b2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Dec 2024 19:33:46 +1100 Subject: [PATCH 561/746] New translations app_en.arb (Serbian (Latin)) --- lib/l10n/sr_CS/app_sr_CS.arb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 268a9ea..b4bc2b6 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -44,6 +44,10 @@ "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, "attachments": "Attachments", "@attachments": {}, "attachImage": "Attach Image", From e70aa9c4fcc5649899d4aee61aeea97398ae474d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 07:28:19 +1100 Subject: [PATCH 562/746] New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 6fee832..a3b12a0 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -44,9 +44,9 @@ "@appSettings": {}, "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Asignado a mí", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Mostrar pedidos asignados a mí", "@assignedToMeDetail": {}, "attachments": "Adjuntos", "@attachments": {}, From ff82ed105d37dc05203b74ab505880fbb27dad62 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 13:12:30 +1100 Subject: [PATCH 563/746] Fix recreation of scanned data - Ensure RS and GS characters are correctly observed --- lib/barcode/camera_controller.dart | 31 +++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 2e40ef4..fb88a62 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,4 +1,6 @@ import "dart:math"; +import "dart:typed_data"; + import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; @@ -93,17 +95,36 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { return; } - String barcode_data = code?.text ?? ""; + Uint8List raw_data = code?.rawBytes ?? Uint8List(0); + + // Reconstruct barcode from raw data + String barcode; + + if (raw_data.isNotEmpty) { + barcode = ""; + + final buffer = StringBuffer(); + + for (int i = 0; i < raw_data.length; i++) { + buffer.writeCharCode(raw_data[i]); + } + + barcode = buffer.toString(); + + } else { + barcode = code?.text ?? ""; + } if (mounted) { setState(() { - scanned_code = barcode_data; - scanning_paused = barcode_data.isNotEmpty; + scanned_code = barcode; + scanning_paused = barcode.isNotEmpty; }); } - if (barcode_data.isNotEmpty) { - handleBarcodeData(barcode_data).then((_) { + if (barcode.isNotEmpty) { + + handleBarcodeData(barcode).then((_) { if (!single_scanning && mounted) { // Resume next scan setState(() { From a893d51e3cd1f50c57822b7300c82c3dc9ada0a8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 13:40:39 +1100 Subject: [PATCH 564/746] Cleanup --- lib/barcode/camera_controller.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index fb88a62..0932995 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -203,13 +203,19 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; + String text = scanned_code.isNotEmpty ? scanned_code : info_text; + + if (text.length > 50) { + text = text.substring(0, 50) + "..."; + } + return SafeArea( child: Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.all(10), child: Text( - scanned_code.isNotEmpty ? scanned_code : info_text, + text, textAlign: TextAlign.center, style: TextStyle( color: Colors.white, From 8f802209a7a14a26f59f373251e32f3739da7901 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 13:41:12 +1100 Subject: [PATCH 565/746] Update release notes --- assets/release_notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 4f75c9c..e4367d5 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ -### 0.17.1 - January 2025 +### 0.17.1 - December 2024 --- +- Fixes barcode scanning bug which prevents scanning of DataMatrix codes - Adds "assigned to me" filter for Purchase Order list - Adds "assigned to me" filter for Sales Order list From 08e01a729bc5c08b45d3cdd2fae3867a5dac409e Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 15:48:24 +1100 Subject: [PATCH 566/746] Updates (cherry picked from commit 94125667d9cdd1bd486aa58a2c4908c143b47225) --- assets/release_notes.md | 1 + lib/api.dart | 4 ++++ lib/inventree/purchase_order.dart | 7 +++++++ lib/l10n/app_en.arb | 3 +++ 4 files changed, 15 insertions(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index e4367d5..c72bd2c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Fixes barcode scanning bug which prevents scanning of DataMatrix codes +- Display "destination" information in PurchaseOrder detail view - Adds "assigned to me" filter for Purchase Order list - Adds "assigned to me" filter for Sales Order list diff --git a/lib/api.dart b/lib/api.dart index 704b7df..d686e1b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -333,6 +333,10 @@ class InvenTreeAPI { // Ref: https://github.com/inventree/InvenTree/pull/7420 bool get supportsModernAttachments => isConnected() && apiVersion >= 207; + // Does the server support the "destination" field on the PurchaseOrder model? + // Ref: https://github.com/inventree/InvenTree/pull/8403 + bool get supportsPurchaseOrderDestination => isConnected() && apiVersion >= 276; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index e472388..9a4f494 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -40,6 +40,7 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { "supplier_reference": {}, "description": {}, "project_code": {}, + "destination": {}, "target_date": {}, "link": {}, "responsible": {}, @@ -54,6 +55,10 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { fields.remove("project_code"); } + if (!InvenTreeAPI().supportsPurchaseOrderDestination) { + fields.remove("destination"); + } + return fields; } @@ -87,6 +92,8 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { String get supplierReference => getString("supplier_reference"); + int get destinationId => getInt("destination"); + bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED", "ON_HOLD"]); bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3ce9866..72d5d92 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -310,6 +310,9 @@ "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, + "destroyed": "Destroyed", "@destroyed": {}, From e2a688315d422a9547bb1a1c67c82c2b5bb748b1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 15:59:22 +1100 Subject: [PATCH 567/746] Display "destination" in purchase order detail (cherry picked from commit d0e4bf0246412938050f5de5a01b0b987cf9a0a2) --- lib/inventree/purchase_order.dart | 2 +- lib/widget/order/purchase_order_detail.dart | 54 +++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 9a4f494..b224458 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -226,7 +226,7 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { String get purchasePriceCurrency => getString("purchase_price_currency"); - int get destination => getInt("destination"); + int get destinationId => getInt("destination"); Map get destinationDetail => getMap("destination_detail"); } diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 29dc68b..89efb4d 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -1,8 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; -import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/order/po_line_list.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; @@ -10,8 +8,16 @@ import "package:inventree/barcode/purchase_order.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; +import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/purchase_order.dart"; + +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/stock/location_display.dart"; +import "package:inventree/widget/order/po_line_list.dart"; + + import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/notes_widget.dart"; @@ -42,6 +48,8 @@ class _PurchaseOrderDetailState extends RefreshableState lines = []; + InvenTreeStockLocation? destination; + int completedLines = 0; int attachmentCount = 0; @@ -258,6 +266,28 @@ class _PurchaseOrderDetailState extends RefreshableState 0) { + InvenTreeStockLocation().get(widget.order.destinationId).then((InvenTreeModel? loc) { + if (mounted) { + if (loc != null && loc is InvenTreeStockLocation) { + setState(() { + destination = loc; + }); + } else { + setState(() { + destination = null; + }); + } + } + }); + } else { + if (mounted) { + setState(() { + destination = null; + }); + } + } } // Edit the currently displayed PurchaseOrder @@ -348,6 +378,23 @@ class _PurchaseOrderDetailState extends RefreshableState { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationDisplayWidget(destination!) + ) + ) + } + )); + } + Color lineColor = completedLines < widget.order.lineItemCount ? COLOR_WARNING : COLOR_SUCCESS; tiles.add(ListTile( @@ -444,5 +491,4 @@ class _PurchaseOrderDetailState extends RefreshableState Date: Wed, 11 Dec 2024 15:59:32 +1100 Subject: [PATCH 568/746] Display "destination" in purchase order line item detail (cherry picked from commit 818f8cf7098df5dd83e86b9102288f22556c8700) --- lib/widget/order/po_line_detail.dart | 53 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index bddeb4d..7689c5a 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -5,14 +5,18 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/model.dart"; import "package:inventree/l10.dart"; -import "package:inventree/widget/progress.dart"; -import "package:inventree/widget/part/part_detail.dart"; -import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/stock.dart"; + +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/part/part_detail.dart"; +import "package:inventree/widget/stock/location_display.dart"; +import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/company/supplier_part_detail.dart"; @@ -38,6 +42,8 @@ class _POLineDetailWidgetState extends RefreshableState { _POLineDetailWidgetState(); + InvenTreeStockLocation? destination; + @override String getAppBarTitle() => L10().lineItem; @@ -84,6 +90,29 @@ class _POLineDetailWidgetState extends RefreshableState { @override Future request(BuildContext context) async { await widget.item.reload(); + + if (widget.item.destinationId > 0) { + InvenTreeStockLocation().get(widget.item.destinationId).then((InvenTreeModel? loc) { + if (mounted) { + if (loc != null && loc is InvenTreeStockLocation) { + setState(() { + destination = loc; + }); + } else { + setState(() { + destination = null; + }); + } + } + }); + } else { + if (mounted) { + setState(() { + destination = null; + }); + } + } + } // Callback to edit this line item @@ -199,6 +228,24 @@ class _POLineDetailWidgetState extends RefreshableState { ) ); + // Destination + if (destination != null) { + tiles.add(ListTile( + title: Text(L10().destination), + subtitle: Text(destination!.name), + leading: Icon(TablerIcons.map_pin, color: COLOR_ACTION), + onTap: () => + { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationDisplayWidget(destination!) + ) + ) + } + )); + } + // Received quantity tiles.add( ListTile( From d016a663d8d9a0c4fd385d41f418e4424a295b46 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 16:07:00 +1100 Subject: [PATCH 569/746] Add order reference to app bar (cherry picked from commit 260bfb56a225cb653d630a81098142b80569e302) --- lib/widget/order/purchase_order_detail.dart | 10 +++++++++- lib/widget/order/sales_order_detail.dart | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 89efb4d..9040228 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -58,7 +58,15 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; + String getAppBarTitle() { + String title = L10().purchaseOrder; + + if (widget.order.reference.isNotEmpty) { + title += " - ${widget.order.reference}"; + } + + return title; + } @override List appBarActions(BuildContext context) { diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 30c218e..54c6800 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -46,7 +46,15 @@ class _SalesOrderDetailState extends RefreshableState { int attachmentCount = 0; @override - String getAppBarTitle() => L10().salesOrder; + String getAppBarTitle() { + String title = L10().salesOrder; + + if (widget.order.reference.isNotEmpty) { + title += " - ${widget.order.reference}"; + } + + return title; + } @override List appBarActions(BuildContext context) { From 52a1eedc7ef868c80b600d7a051411fa14e87a02 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 16:28:43 +1100 Subject: [PATCH 570/746] Update company display --- lib/widget/company/company_detail.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 65f65d1..c0ab481 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -48,7 +48,15 @@ class _CompanyDetailState extends RefreshableState { int attachmentCount = 0; @override - String getAppBarTitle() => L10().company; + String getAppBarTitle() { + String title = L10().company; + + if (widget.company.name.isNotEmpty) { + title += " - ${widget.company.name}"; + } + + return title; + } @override List appBarActions(BuildContext context) { From cc0085e50f5aa688670afd3d636b1babf865a81b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 16:38:09 +1100 Subject: [PATCH 571/746] Adjust --- lib/widget/order/po_line_detail.dart | 2 +- lib/widget/order/purchase_order_detail.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index 7689c5a..9dc178f 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -239,7 +239,7 @@ class _POLineDetailWidgetState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => LocationDisplayWidget(destination!) + builder: (context) => LocationDisplayWidget(destination) ) ) } diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 9040228..f4a45d0 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -396,7 +396,7 @@ class _PurchaseOrderDetailState extends RefreshableState LocationDisplayWidget(destination!) + builder: (context) => LocationDisplayWidget(destination) ) ) } From 3887458f0d4826fe1e946c4d22aa8b64128b6f42 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:08 +1100 Subject: [PATCH 572/746] New translations app_en.arb (Italian) --- lib/l10n/it_IT/app_it_IT.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index b7a0a9c..0351b3e 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descrizione", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Distrutto", "@destroyed": {}, "details": "Dettagli", From 18930e62018eb51a335573a271ed1cf568b4fe89 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:09 +1100 Subject: [PATCH 573/746] New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index a1e9613..c516d1f 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Détruit", "@destroyed": {}, "details": "Détails", From 0f4e1c8404fac16931ff5a0225b5391f6a55ac50 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:11 +1100 Subject: [PATCH 574/746] New translations app_en.arb (Spanish) --- lib/l10n/es_ES/app_es_ES.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index a3b12a0..f37e7d5 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descripción", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destruido", "@destroyed": {}, "details": "Detalles", From a0c0e9dca433a847324a76f8767d2541ba934aab Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:12 +1100 Subject: [PATCH 575/746] New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 6ec0b77..4a5482c 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Popis", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Zničeno", "@destroyed": {}, "details": "Detaily", From e0857b0462e0f786af3e2ee291c4983dac6948ef Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:13 +1100 Subject: [PATCH 576/746] New translations app_en.arb (Greek) --- lib/l10n/el_GR/app_el_GR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 7e22db9..3b7bf63 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 0b043dcaebbf1359b8200b13aa4ca53d9933ad87 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:14 +1100 Subject: [PATCH 577/746] New translations app_en.arb (Hebrew) --- lib/l10n/he_IL/app_he_IL.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 793206b..09cfeed 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "תיאור", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "מושמד", "@destroyed": {}, "details": "פרטים", From 5c85c98a0fd28fcf77d416e6fa04c2d8296f45f2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:17 +1100 Subject: [PATCH 578/746] New translations app_en.arb (Dutch) --- lib/l10n/nl_NL/app_nl_NL.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 2884aa0..e3d0d9d 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Omschrijving", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Vernietigd", "@destroyed": {}, "details": "Details", From c2ef434988af021223bf3b2fec2139bb3a01d91d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:18 +1100 Subject: [PATCH 579/746] New translations app_en.arb (Polish) --- lib/l10n/pl_PL/app_pl_PL.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 0198c9b..dca06ad 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Opis", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Zniszczony", "@destroyed": {}, "details": "Szczegóły", From 3937bb37e65ac56bb960b01db1c2032f0323020c Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:19 +1100 Subject: [PATCH 580/746] New translations app_en.arb (Russian) --- lib/l10n/ru_RU/app_ru_RU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 1c9a9bb..5d3b5c0 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Описание", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Разрушено", "@destroyed": {}, "details": "Подробности", From 6aa2e3cdef4a28947240d0d4b30958bdaca56b75 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:20 +1100 Subject: [PATCH 581/746] New translations app_en.arb (Turkish) --- lib/l10n/tr_TR/app_tr_TR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index f3927cc..7f2b5a3 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Açıklama", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Yok edildi", "@destroyed": {}, "details": "Detaylar", From 940efa6aa94c28d348159b73374643be0e30ca8b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:22 +1100 Subject: [PATCH 582/746] New translations app_en.arb (Chinese Traditional) --- lib/l10n/zh_TW/app_zh_TW.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 6e06908..90c5bf8 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "敘述", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "已損毀", "@destroyed": {}, "details": "詳細資訊", From 6ab241b0b568226e24b43ef5f4c8537d92804896 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:23 +1100 Subject: [PATCH 583/746] New translations app_en.arb (Indonesian) --- lib/l10n/id_ID/app_id_ID.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 4fe0cf8..a3f81e4 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Deskripsi", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Hancur", "@destroyed": {}, "details": "Detail", From 75fe2fe9f4fe66da6578b81e30141e01d838d9d7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:24 +1100 Subject: [PATCH 584/746] New translations app_en.arb (Persian) --- lib/l10n/fa_IR/app_fa_IR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index e00406b..161e3f5 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 4e73b4e43b519e1ba8d6ebf8fd02b2059faa124c Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:25 +1100 Subject: [PATCH 585/746] New translations app_en.arb (Estonian) --- lib/l10n/et_EE/app_et_EE.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 5d8a0c6..34f0e6c 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Kirjeldus", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Üksikasjad", From 27022ac33c8fa42d12cd6c16191907627457c0ea Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:27 +1100 Subject: [PATCH 586/746] New translations app_en.arb (Romanian) --- lib/l10n/ro_RO/app_ro_RO.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 8f496dd..fb84828 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descriere", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Distrus", "@destroyed": {}, "details": "Detalii", From 85265d781a1d2f5a8f91eead902195eb1a662020 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:28 +1100 Subject: [PATCH 587/746] New translations app_en.arb (Arabic) --- lib/l10n/ar_SA/app_ar_SA.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 90b9d45..437b5e4 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 626b66c0553ab2ed72b2c3e8a2501d63133a4158 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:29 +1100 Subject: [PATCH 588/746] New translations app_en.arb (Bulgarian) --- lib/l10n/bg_BG/app_bg_BG.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 4322e66..ad9f7f4 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 7fa92fec1778a8d6257de5b1c267cdb0f92505b6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:30 +1100 Subject: [PATCH 589/746] New translations app_en.arb (Danish) --- lib/l10n/da_DK/app_da_DK.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index e732c3b..db9f0f5 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Beskrivelse", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destrueret", "@destroyed": {}, "details": "Detaljer", From 3c5e884b38303fe9772d788a6c945d2721bc9a5e Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:31 +1100 Subject: [PATCH 590/746] New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 6875ea0..3409274 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Beschreibung", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Vernichtet", "@destroyed": {}, "details": "Details", From 345bb8be12fdf6fbcd2c223e712bfa03a7edfe25 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:33 +1100 Subject: [PATCH 591/746] New translations app_en.arb (Finnish) --- lib/l10n/fi_FI/app_fi_FI.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index c105037..cff01b3 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Kuvaus", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Tuhottu", "@destroyed": {}, "details": "Yksityiskohdat", From 968dab0a96f0064debe604268a5f6f95979ca3ff Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:34 +1100 Subject: [PATCH 592/746] New translations app_en.arb (Hungarian) --- lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 20b2558..7579c51 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Leírás", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Megsemmisült", "@destroyed": {}, "details": "Részletek", From 777a074331f11d6966f8d0bec5a7d132f3624445 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:35 +1100 Subject: [PATCH 593/746] New translations app_en.arb (Japanese) --- lib/l10n/ja_JP/app_ja_JP.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 601f684..13d6cc0 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "説明", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "破壊", "@destroyed": {}, "details": "詳細", From e3c24e76bf3214ab45c6e4f22dd28e566267227f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:37 +1100 Subject: [PATCH 594/746] New translations app_en.arb (Korean) --- lib/l10n/ko_KR/app_ko_KR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index c5f5cf4..fb000f2 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 5281a1b6d25a40778d795efd3dc7c0447ed32e15 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:38 +1100 Subject: [PATCH 595/746] New translations app_en.arb (Lithuanian) --- lib/l10n/lt_LT/app_lt_LT.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 60d6c92..7c616bb 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 32ac2e0b6b407b1ef92df6acc31db2d1debe1c0a Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:39 +1100 Subject: [PATCH 596/746] New translations app_en.arb (Norwegian) --- lib/l10n/no_NO/app_no_NO.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 0a021b2..b839ea0 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Beskrivelse", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Ødelagt", "@destroyed": {}, "details": "Detaljer", From 1ea11b5d7e9929b040868b3c692c7010cfdec3b9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:40 +1100 Subject: [PATCH 597/746] New translations app_en.arb (Portuguese) --- lib/l10n/pt_PT/app_pt_PT.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 48307d9..b3cee06 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descrição", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destruído", "@destroyed": {}, "details": "Detalhes", From 5e7df6a3f041e22a22ce3ba9e51e1218eff2ff18 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:42 +1100 Subject: [PATCH 598/746] New translations app_en.arb (Slovak) --- lib/l10n/sk_SK/app_sk_SK.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index ab51751..263506f 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 5728da5361a242b724c2ee1693fa4f57a7e6813d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:43 +1100 Subject: [PATCH 599/746] New translations app_en.arb (Slovenian) --- lib/l10n/sl_SI/app_sl_SI.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 7b78afc..026f953 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 3fe350a35e23d4efa1ae14f25f4584338b993f1f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:44 +1100 Subject: [PATCH 600/746] New translations app_en.arb (Swedish) --- lib/l10n/sv_SE/app_sv_SE.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 96e85a5..9f38baa 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Beskrivning", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Förstörd", "@destroyed": {}, "details": "Detaljer", From 3bf9692c2a92425bfe14b886b78b0fbfbe9e58b3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:45 +1100 Subject: [PATCH 601/746] New translations app_en.arb (Ukrainian) --- lib/l10n/uk_UA/app_uk_UA.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 16c6520..cf1032d 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 1e4509854b3c2acde1063c749a1c93c8e99659ce Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:47 +1100 Subject: [PATCH 602/746] New translations app_en.arb (Chinese Simplified) --- lib/l10n/zh_CN/app_zh_CN.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 47169bd..8d5bdac 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "描述", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "销毁", "@destroyed": {}, "details": "详细信息", From 0bb7af735091a93e6785d88dd9c4de2ae69e2677 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:48 +1100 Subject: [PATCH 603/746] New translations app_en.arb (Vietnamese) --- lib/l10n/vi_VN/app_vi_VN.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index bdc1bb4..3111b38 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Mô tả", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Đã hủy", "@destroyed": {}, "details": "Chi tiết", From 09dd7684f06e50a91dea1fefc5386f29e915bb19 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:49 +1100 Subject: [PATCH 604/746] New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index de96e14..bc1266d 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descrição", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destruído", "@destroyed": {}, "details": "Detalhes", From 50b7286be3f63f032aa47f452656c359734fab55 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:50 +1100 Subject: [PATCH 605/746] New translations app_en.arb (Spanish, Mexico) --- lib/l10n/es_MX/app_es_MX.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 6aae33f..50be329 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Descripción", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destruido", "@destroyed": {}, "details": "Detalles", From 0d10c0f53923e6d175a5e5811d377e492f1adbc4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:52 +1100 Subject: [PATCH 606/746] New translations app_en.arb (Thai) --- lib/l10n/th_TH/app_th_TH.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index a6c4481..b2739c2 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From fbe5ee2455548cd040f9fe71b9f08ab1bb0fd739 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:53 +1100 Subject: [PATCH 607/746] New translations app_en.arb (Latvian) --- lib/l10n/lv_LV/app_lv_LV.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 2ae70cc..b14e9c1 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From d8bba1daba9d53006d93391843073cb3dc0d62ea Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:54 +1100 Subject: [PATCH 608/746] New translations app_en.arb (Hindi) --- lib/l10n/hi_IN/app_hi_IN.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 36edfe5..4146cb1 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 3025a3c2808058cba74a2d15a7ae661f30cddd92 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Dec 2024 19:24:55 +1100 Subject: [PATCH 609/746] New translations app_en.arb (Serbian (Latin)) --- lib/l10n/sr_CS/app_sr_CS.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index b4bc2b6..878b0cd 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -211,6 +211,8 @@ "@deleteSuccess": {}, "description": "Description", "@description": {}, + "destination": "Destination", + "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, "details": "Details", From 19fdac46a7397c9a2cdb62e7d197cca963923389 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 21:33:06 +1100 Subject: [PATCH 610/746] Pre-fill the "location" field when receiving an item --- ios/Runner.xcodeproj/project.pbxproj | 8 ++++---- lib/inventree/purchase_order.dart | 12 ++++-------- lib/widget/order/po_line_detail.dart | 11 +++++++++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3a6f42d..bda4a2a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -272,7 +272,6 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", @@ -280,21 +279,21 @@ "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", + "${BUILT_PRODUCTS_DIR}/flutter_zxing/flutter_zxing.framework", "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", "${BUILT_PRODUCTS_DIR}/open_filex/open_filex.framework", "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", - "${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework", "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", + "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", @@ -302,15 +301,16 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_zxing.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_filex.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index b224458..ba19a30 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -178,16 +178,10 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { } @override - Map defaultGetFilters() { - return { - "part_detail": "true", - }; - } - - @override - Map defaultListFilters() { + Map defaultFilters() { return { "part_detail": "true", + "order_detail": "true", }; } @@ -228,6 +222,8 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { int get destinationId => getInt("destination"); + Map get orderDetail => getMap("order_detail"); + Map get destinationDetail => getMap("destination_detail"); } diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index 9dc178f..4482a94 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -133,6 +133,13 @@ class _POLineDetailWidgetState extends RefreshableState { // Launch a form to 'receive' this line item Future receiveLineItem(BuildContext context) async { + // Pre-fill the "destination" to receive into + int destination = widget.item.destinationId; + + if (destination < 0) { + destination = (widget.item.orderDetail["destination"] ?? -1) as int; + } + // Construct fields to receive Map fields = { "line_item": { @@ -164,6 +171,10 @@ class _POLineDetailWidgetState extends RefreshableState { } }; + if (destination > 0) { + fields["location"]?["value"] = destination; + } + showLoadingOverlay(context); var order = await InvenTreePurchaseOrder().get(widget.item.orderId); hideLoadingOverlay(); From d5a9f4310e6168def43da8d38eaf92874a83685b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 21:35:56 +1100 Subject: [PATCH 611/746] Refactoring --- lib/inventree/bom.dart | 9 +-------- lib/inventree/company.dart | 12 ++---------- lib/inventree/part.dart | 11 ++--------- lib/inventree/purchase_order.dart | 9 +-------- lib/inventree/sales_order.dart | 18 ++---------------- lib/inventree/stock.dart | 12 +----------- 6 files changed, 9 insertions(+), 62 deletions(-) diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart index cf708c6..8019ecf 100644 --- a/lib/inventree/bom.dart +++ b/lib/inventree/bom.dart @@ -18,7 +18,7 @@ class InvenTreeBomItem extends InvenTreeModel { String get URL => "bom/"; @override - Map defaultListFilters() { + Map defaultFilters() { return { "sub_part_detail": "true", "part_detail": "true", @@ -26,13 +26,6 @@ class InvenTreeBomItem extends InvenTreeModel { }; } - @override - Map defaultGetFilters() { - return { - "sub_part_detail": "true", - }; - } - // Extract the 'reference' value associated with this BomItem String get reference => getString("reference"); diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index b9ac214..3c3ac6a 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -155,7 +155,8 @@ class InvenTreeSupplierPart extends InvenTreeModel { return fields; } - Map _filters() { + @override + Map defaultFilters() { return { "manufacturer_detail": "true", "supplier_detail": "true", @@ -163,15 +164,6 @@ class InvenTreeSupplierPart extends InvenTreeModel { }; } - @override - Map defaultListFilters() { - return _filters(); - } - - @override - Map defaultGetFilters() { - return _filters(); - } int get manufacturerId => getInt("pk", subKey: "manufacturer_detail"); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 1102393..103fa58 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -227,16 +227,9 @@ class InvenTreePart extends InvenTreeModel { } @override - Map defaultListFilters() { + Map defaultFilters() { return { - "location_detail": "true", - }; - } - - @override - Map defaultGetFilters() { - return { - "category_detail": "true", // Include category detail information + "category_detail": "true", }; } diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index ba19a30..f57dd13 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -64,14 +64,7 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { } @override - Map defaultGetFilters() { - return { - "supplier_detail": "true", - }; - } - - @override - Map defaultListFilters() { + Map defaultFilters() { return { "supplier_detail": "true", }; diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 5bdd484..b1ee37f 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -65,14 +65,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { } @override - Map defaultGetFilters() { - return { - "customer_detail": "true", - }; - } - - @override - Map defaultListFilters() { + Map defaultFilters() { return { "customer_detail": "true", }; @@ -180,14 +173,7 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { } @override - Map defaultGetFilters() { - return { - "part_detail": "true", - }; - } - - @override - Map defaultListFilters() { + Map defaultFilters() { return { "part_detail": "true", }; diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index df15803..7b03d18 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -253,7 +253,7 @@ class InvenTreeStockItem extends InvenTreeModel { } @override - Map defaultGetFilters() { + Map defaultFilters() { return { "part_detail": "true", @@ -263,16 +263,6 @@ class InvenTreeStockItem extends InvenTreeModel { }; } - @override - Map defaultListFilters() { - - return { - "part_detail": "true", - "location_detail": "true", - "supplier_detail": "true", - }; - } - List testTemplates = []; int get testTemplateCount => testTemplates.length; From e44d1ea5b4c4f4d90caacdd579e35de9ee3fc3aa Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 21:45:43 +1100 Subject: [PATCH 612/746] Refactor loading overlay --- lib/api_form.dart | 6 +++--- lib/barcode/controller.dart | 2 +- lib/inventree/purchase_order.dart | 5 +++++ lib/inventree/sales_order.dart | 5 +++++ lib/labels.dart | 2 +- lib/settings/app_settings.dart | 2 +- lib/settings/login.dart | 2 +- lib/widget/attachment_widget.dart | 4 ++-- lib/widget/company/supplier_part_detail.dart | 6 +++--- lib/widget/order/po_line_detail.dart | 6 +++--- lib/widget/order/po_line_list.dart | 2 +- lib/widget/order/purchase_order_detail.dart | 4 ++-- lib/widget/order/sales_order_detail.dart | 2 +- lib/widget/order/so_line_detail.dart | 2 +- lib/widget/order/so_line_list.dart | 2 +- lib/widget/part/bom_list.dart | 2 +- lib/widget/part/category_display.dart | 2 +- lib/widget/part/part_detail.dart | 4 ++-- lib/widget/part/part_parameter_widget.dart | 2 +- lib/widget/progress.dart | 5 ++++- lib/widget/stock/location_display.dart | 2 +- lib/widget/stock/stock_detail.dart | 6 +++--- 22 files changed, 44 insertions(+), 31 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 432e49c..f8e335d 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -977,7 +977,7 @@ Future launchApiForm( IconData icon = TablerIcons.device_floppy }) async { - showLoadingOverlay(context); + showLoadingOverlay(); // List of fields defined by the server Map serverFields = {}; @@ -1229,7 +1229,7 @@ class _APIFormWidgetState extends State { if (widget.method == "POST") { - showLoadingOverlay(context); + showLoadingOverlay(); final response = await InvenTreeAPI().post( widget.url, body: data, @@ -1240,7 +1240,7 @@ class _APIFormWidgetState extends State { return response; } else { - showLoadingOverlay(context); + showLoadingOverlay(); final response = await InvenTreeAPI().patch( widget.url, body: data, diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index 559bac9..7a1fb1f 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -65,7 +65,7 @@ class InvenTreeBarcodeControllerState extends State context = OneContext.hasContext ? OneContext().context : null; } - showLoadingOverlay(context); + showLoadingOverlay(); await pauseScan(); await widget.handler.processBarcode(data); diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index f57dd13..82cb0f3 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -3,6 +3,7 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/orders.dart"; +import "package:inventree/widget/progress.dart"; /* @@ -121,7 +122,9 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { return; } + showLoadingOverlay(); await api.post("${url}issue/", expectedStatusCode: 201); + hideLoadingOverlay(); } /// Mark this order as "cancelled" @@ -130,7 +133,9 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { return; } + showLoadingOverlay(); await api.post("${url}cancel/", expectedStatusCode: 201); + hideLoadingOverlay(); } } diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index b1ee37f..9acc374 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -6,6 +6,7 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/orders.dart"; import "package:inventree/api.dart"; +import "package:inventree/widget/progress.dart"; /* @@ -76,7 +77,9 @@ class InvenTreeSalesOrder extends InvenTreeOrder { return; } + showLoadingOverlay(); await api.post("${url}issue/", expectedStatusCode: 201); + hideLoadingOverlay(); } /// Mark this order as "cancelled" @@ -85,7 +88,9 @@ class InvenTreeSalesOrder extends InvenTreeOrder { return; } + showLoadingOverlay(); await api.post("${url}cancel/", expectedStatusCode: 201); + hideLoadingOverlay(); } int get customerId => getInt("customer"); diff --git a/lib/labels.dart b/lib/labels.dart index 4d053ba..1e15bd4 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -98,7 +98,7 @@ Future selectAndPrintLabel( if (labelId != -1 && pluginKey != null) { - showLoadingOverlay(context); + showLoadingOverlay(); if (InvenTreeAPI().supportsModernLabelPrinting) { diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 7b6b08d..8eba55b 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -50,7 +50,7 @@ class _InvenTreeAppSettingsState extends State { Future loadSettings(BuildContext context) async { - showLoadingOverlay(context); + showLoadingOverlay(); barcodeSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; serverSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; diff --git a/lib/settings/login.dart b/lib/settings/login.dart index d580b1d..908d09a 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -50,7 +50,7 @@ class _InvenTreeLoginState extends State { currentFocus.unfocus(); } - showLoadingOverlay(context); + showLoadingOverlay(); // Attempt login final response = await InvenTreeAPI().fetchToken(widget.profile, username, password); diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index ab9c61c..42f3e84 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -79,7 +79,7 @@ class _AttachmentWidgetState extends RefreshableState { if (file == null) return; - showLoadingOverlay(context); + showLoadingOverlay(); final bool result = await widget.attachmentClass.uploadAttachment( file, @@ -178,7 +178,7 @@ class _AttachmentWidgetState extends RefreshableState { subtitle: Text(attachment.comment), leading: Icon(attachment.icon, color: COLOR_ACTION), onTap: () async { - showLoadingOverlay(context); + showLoadingOverlay(); await attachment.downloadAttachment(); hideLoadingOverlay(); }, diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index 2b6a9d4..c6c5046 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -119,7 +119,7 @@ class _SupplierPartDisplayState extends RefreshableState { fields["location"]?["value"] = destination; } - showLoadingOverlay(context); + showLoadingOverlay(); var order = await InvenTreePurchaseOrder().get(widget.item.orderId); hideLoadingOverlay(); @@ -210,7 +210,7 @@ class _POLineDetailWidgetState extends RefreshableState { leading: Icon(TablerIcons.box, color: COLOR_ACTION), trailing: api.getThumbnail(widget.item.partImage), onTap: () async { - showLoadingOverlay(context); + showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); hideLoadingOverlay(); @@ -228,7 +228,7 @@ class _POLineDetailWidgetState extends RefreshableState { subtitle: Text(widget.item.SKU), leading: Icon(TablerIcons.building, color: COLOR_ACTION), onTap: () async { - showLoadingOverlay(context); + showLoadingOverlay(); var part = await InvenTreeSupplierPart().get(widget.item.supplierPartId); hideLoadingOverlay(); diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart index e7f53d4..94c0d92 100644 --- a/lib/widget/order/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -77,7 +77,7 @@ class _PaginatedPOLineListState extends PaginatedSearchState POLineDetailWidget(item))); diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index f4a45d0..297bc46 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -185,7 +185,7 @@ class _PurchaseOrderDetailState extends RefreshableState { color: Colors.blue, acceptText: L10().issue, onAccept: () async { - await widget.order.issueOrder().then((dynamic) { + widget.order.issueOrder().then((dynamic) { refresh(context); }); } diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index c2d4181..9dcd218 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -187,7 +187,7 @@ class _SOLineDetailWidgetState extends RefreshableState { leading: Icon(TablerIcons.box, color: COLOR_ACTION), trailing: api.getThumbnail(widget.item.partImage), onTap: () async { - showLoadingOverlay(context); + showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); hideLoadingOverlay(); diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart index 11ba227..a4c7454 100644 --- a/lib/widget/order/so_line_list.dart +++ b/lib/widget/order/so_line_list.dart @@ -65,7 +65,7 @@ class _PaginatedSOLineListState extends PaginatedSearchState { leading: InvenTreeAPI().getThumbnail(subPart?.thumbnail ?? ""), onTap: subPart == null ? null : () async { - showLoadingOverlay(context); + showLoadingOverlay(); var part = await InvenTreePart().get(subPart.pk); hideLoadingOverlay(); diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart index bc7ab08..79dd602 100644 --- a/lib/widget/part/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -159,7 +159,7 @@ class _CategoryDisplayState extends RefreshableState { Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } else { - showLoadingOverlay(context); + showLoadingOverlay(); var cat = await InvenTreePartCategory().get(parentId); hideLoadingOverlay(); diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 4718e6e..0e2f2ca 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -366,7 +366,7 @@ class _PartDisplayState extends RefreshableState { onTap: () async { if (part.categoryId > 0) { - showLoadingOverlay(context); + showLoadingOverlay(); var cat = await InvenTreePartCategory().get(part.categoryId); hideLoadingOverlay(); @@ -646,7 +646,7 @@ class _PartDisplayState extends RefreshableState { if (part.isTrackable) { // read the next available serial number - showLoadingOverlay(context); + showLoadingOverlay(); var response = await api.get("/api/part/${part.pk}/serial-numbers/", expectedStatusCode: null); hideLoadingOverlay(); diff --git a/lib/widget/part/part_parameter_widget.dart b/lib/widget/part/part_parameter_widget.dart index ea7e7df..53e772d 100644 --- a/lib/widget/part/part_parameter_widget.dart +++ b/lib/widget/part/part_parameter_widget.dart @@ -127,7 +127,7 @@ class _PaginatedParameterState extends PaginatedSearchState { Navigator.push(context, MaterialPageRoute( builder: (context) => LocationDisplayWidget(null))); } else { - showLoadingOverlay(context); + showLoadingOverlay(); var loc = await InvenTreeStockLocation().get(parentId); hideLoadingOverlay(); diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 106d050..0081708 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -523,7 +523,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: () async { if (widget.item.partId > 0) { - showLoadingOverlay(context); + showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); hideLoadingOverlay(); @@ -566,7 +566,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: () async { if (widget.item.locationId > 0) { - showLoadingOverlay(context); + showLoadingOverlay(); var loc = await InvenTreeStockLocation().get(widget.item.locationId); hideLoadingOverlay(); @@ -651,7 +651,7 @@ class _StockItemDisplayState extends RefreshableState { leading: Icon(TablerIcons.building, color: COLOR_ACTION), trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage, hideIfNull: true), onTap: () async { - showLoadingOverlay(context); + showLoadingOverlay(); var sp = await InvenTreeSupplierPart().get( widget.item.supplierPartId); hideLoadingOverlay(); From 2d9bc145bfea6a1d2b8b9fd70833c60dc7ef834d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 21:49:13 +1100 Subject: [PATCH 613/746] Update release notes --- assets/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index c72bd2c..a445713 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Fixes barcode scanning bug which prevents scanning of DataMatrix codes - Display "destination" information in PurchaseOrder detail view +- Pre-fill "location" field when receiving items against PurchaseOrder - Adds "assigned to me" filter for Purchase Order list - Adds "assigned to me" filter for Sales Order list From 5c1ceb7a0cd3f78fe45ab5c8cbbb3a0385461d4f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 21:55:31 +1100 Subject: [PATCH 614/746] Remove unused var --- lib/barcode/controller.dart | 6 ------ lib/widget/progress.dart | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index 7a1fb1f..f1c3789 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -59,12 +59,6 @@ class InvenTreeBarcodeControllerState extends State processingBarcode = true; }); - BuildContext? context; - - if (hasContext()) { - context = OneContext.hasContext ? OneContext().context : null; - } - showLoadingOverlay(); await pauseScan(); diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index 618941b..a2a296d 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -45,7 +45,7 @@ Widget progressIndicator() { void showLoadingOverlay() { - BuildContext? context = OneContext().context; + BuildContext? context = OneContext.hasContext ? OneContext().context : null; if (context == null) { return; From 2dd20d9565d489cc08a9631eba46ed93fadef0f6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:00:13 +1100 Subject: [PATCH 615/746] Cleanup --- lib/barcode/controller.dart | 4 ---- pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index f1c3789..3a8fa2c 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -1,11 +1,7 @@ import "package:flutter/material.dart"; -import "package:inventree/helpers.dart"; -import "package:one_context/one_context.dart"; import "package:inventree/preferences.dart"; - import "package:inventree/barcode/handler.dart"; - import "package:inventree/widget/progress.dart"; /* diff --git a/pubspec.lock b/pubspec.lock index 2a5876e..0d720b7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -278,14 +278,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" - datetime_picker_formfield: + datetime_picker_formfield_new: dependency: "direct main" description: - name: datetime_picker_formfield - sha256: "6d0412c98cc5da18a5dca1f81f82a834fbacdb5d249fd6d9bed42d912339720e" + name: datetime_picker_formfield_new + sha256: "04e353b959fa9f2654bb41ec016100152bdcd0afdef7b7b74a83d7d97bdba0a3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.0" dbus: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 84572dd..079de53 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: camera: ^0.10.3 # Camera cupertino_icons: ^1.0.8 currency_formatter: ^2.2.1 # Currency formatting - datetime_picker_formfield: ^2.0.1 # Date / time picker + datetime_picker_formfield_new: ^2.1.0 # Date / time picker device_info_plus: ^10.1.2 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields file_picker: ^8.1.2 # Select files from the device From 541eca387dbba53acdcc031b470fed0f65f8a636 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:09:35 +1100 Subject: [PATCH 616/746] Revert package change --- pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 0d720b7..2a5876e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -278,14 +278,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" - datetime_picker_formfield_new: + datetime_picker_formfield: dependency: "direct main" description: - name: datetime_picker_formfield_new - sha256: "04e353b959fa9f2654bb41ec016100152bdcd0afdef7b7b74a83d7d97bdba0a3" + name: datetime_picker_formfield + sha256: "6d0412c98cc5da18a5dca1f81f82a834fbacdb5d249fd6d9bed42d912339720e" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.0.1" dbus: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 079de53..84572dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: camera: ^0.10.3 # Camera cupertino_icons: ^1.0.8 currency_formatter: ^2.2.1 # Currency formatting - datetime_picker_formfield_new: ^2.1.0 # Date / time picker + datetime_picker_formfield: ^2.0.1 # Date / time picker device_info_plus: ^10.1.2 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields file_picker: ^8.1.2 # Select files from the device From 676de0dfe95ab5432acd804e7b4597a3aa9ead53 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:23:52 +1100 Subject: [PATCH 617/746] Display part name --- lib/inventree/company.dart | 6 ++++-- lib/widget/order/po_line_list.dart | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 3c3ac6a..b9bba77 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -189,8 +189,10 @@ class InvenTreeSupplierPart extends InvenTreeModel { String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - String get partName => getString("full_name", subKey: "part_detail"); - + String get partName => getString("name", subKey: "part_detail"); + + Map get partDetail => getMap("part_detail"); + String get partDescription => getString("description", subKey: "part_detail"); String get note => getString("note"); diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart index 94c0d92..5050477 100644 --- a/lib/widget/order/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -71,9 +71,10 @@ class _PaginatedPOLineListState extends PaginatedSearchState Date: Wed, 11 Dec 2024 22:25:41 +1100 Subject: [PATCH 618/746] Update release notes --- assets/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index a445713..1b22659 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -4,6 +4,7 @@ - Fixes barcode scanning bug which prevents scanning of DataMatrix codes - Display "destination" information in PurchaseOrder detail view - Pre-fill "location" field when receiving items against PurchaseOrder +- Fix display of part name in PurchaseOrderLineItem list - Adds "assigned to me" filter for Purchase Order list - Adds "assigned to me" filter for Sales Order list From e1912d68789f29b69a41e4dc3eb8c57121720357 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:31:01 +1100 Subject: [PATCH 619/746] Tweak barcode overlay --- lib/barcode/camera_controller.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 0932995..b3e26fc 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -185,7 +185,12 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { child: Align( alignment: Alignment.topCenter, child: Padding( - padding: EdgeInsets.all(10), + padding: EdgeInsets.only( + left: 10, + right: 10, + top: 75, + bottom: 10 + ), child: Text( widget.handler.getOverlayText(context), style: TextStyle( @@ -213,7 +218,12 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { child: Align( alignment: Alignment.bottomCenter, child: Padding( - padding: EdgeInsets.all(10), + padding: EdgeInsets.only( + left: 10, + right: 10, + top: 10, + bottom: 75 + ), child: Text( text, textAlign: TextAlign.center, From d25c47ccc3f411e49e6a2235477178a6b37ab9b1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:39:33 +1100 Subject: [PATCH 620/746] Fix for unit test --- lib/widget/progress.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index a2a296d..cc00c85 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -1,5 +1,7 @@ +import "dart:io"; + import "package:flutter/material.dart"; import "package:flutter_overlay_loader/flutter_overlay_loader.dart"; import "package:inventree/app_colors.dart"; @@ -45,6 +47,11 @@ Widget progressIndicator() { void showLoadingOverlay() { + // Do not show overlay if running unit tests + if (Platform.environment.containsKey("FLUTTER_TEST")) { + return; + } + BuildContext? context = OneContext.hasContext ? OneContext().context : null; if (context == null) { From 6690f10118036209e2073b0056b845a8aacba88f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 11 Dec 2024 22:53:03 +1100 Subject: [PATCH 621/746] Handle condition where camera controller fails to initialize --- lib/barcode/camera_controller.dart | 26 ++++++++++++++++++++++++++ lib/l10n/app_en.arb | 3 +++ lib/widget/snacks.dart | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index b3e26fc..4c6edd7 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,10 +1,14 @@ import "dart:math"; import "dart:typed_data"; +import "package:camera/camera.dart"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/sentry.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/snacks.dart"; +import "package:one_context/one_context.dart"; import "package:wakelock_plus/wakelock_plus.dart"; import "package:flutter_zxing/flutter_zxing.dart"; @@ -133,7 +137,28 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { } }); } + } + void onControllerCreated(CameraController? controller, Exception? error) { + if (error != null) { + sentryReportError( + "CameraBarcodeController.onControllerCreated", + error, + null + ); + } + + if (controller == null) { + showSnackIcon( + L10().cameraCreationError, + icon: TablerIcons.camera_x, + success: false + ); + + if (OneContext.hasContext) { + Navigator.pop(OneContext().context!); + } + } } /* @@ -167,6 +192,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { tryInverted: true, tryRotate: true, showGallery: false, + onControllerCreated: onControllerCreated, scanDelay: Duration(milliseconds: scan_delay), resolution: ResolutionPreset.high, lensDirection: CameraLensDirection.back, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 72d5d92..d6693bd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -202,6 +202,9 @@ "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "cameraInternal": "Internal Camera", "@cameraInternal": {}, diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index c5a1aba..398a484 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -72,7 +72,7 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc onAction(); } ), - duration: Duration(seconds: onAction == null ? 1 : 2), + duration: Duration(seconds: onAction == null ? 5 : 10), ) ); From 6b179d108c0073105b9018d4f3162aa7676be97f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Dec 2024 10:16:43 +1100 Subject: [PATCH 622/746] New Crowdin updates (#576) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 2 ++ lib/l10n/bg_BG/app_bg_BG.arb | 2 ++ lib/l10n/cs_CZ/app_cs_CZ.arb | 2 ++ lib/l10n/da_DK/app_da_DK.arb | 2 ++ lib/l10n/de_DE/app_de_DE.arb | 2 ++ lib/l10n/el_GR/app_el_GR.arb | 2 ++ lib/l10n/es_ES/app_es_ES.arb | 2 ++ lib/l10n/es_MX/app_es_MX.arb | 2 ++ lib/l10n/et_EE/app_et_EE.arb | 2 ++ lib/l10n/fa_IR/app_fa_IR.arb | 2 ++ lib/l10n/fi_FI/app_fi_FI.arb | 2 ++ lib/l10n/fr_FR/app_fr_FR.arb | 2 ++ lib/l10n/he_IL/app_he_IL.arb | 2 ++ lib/l10n/hi_IN/app_hi_IN.arb | 2 ++ lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ lib/l10n/id_ID/app_id_ID.arb | 2 ++ lib/l10n/it_IT/app_it_IT.arb | 2 ++ lib/l10n/ja_JP/app_ja_JP.arb | 2 ++ lib/l10n/ko_KR/app_ko_KR.arb | 2 ++ lib/l10n/lt_LT/app_lt_LT.arb | 2 ++ lib/l10n/lv_LV/app_lv_LV.arb | 2 ++ lib/l10n/nl_NL/app_nl_NL.arb | 2 ++ lib/l10n/no_NO/app_no_NO.arb | 2 ++ lib/l10n/pl_PL/app_pl_PL.arb | 2 ++ lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ lib/l10n/pt_PT/app_pt_PT.arb | 2 ++ lib/l10n/ro_RO/app_ro_RO.arb | 2 ++ lib/l10n/ru_RU/app_ru_RU.arb | 2 ++ lib/l10n/sk_SK/app_sk_SK.arb | 2 ++ lib/l10n/sl_SI/app_sl_SI.arb | 2 ++ lib/l10n/sr_CS/app_sr_CS.arb | 2 ++ lib/l10n/sv_SE/app_sv_SE.arb | 2 ++ lib/l10n/th_TH/app_th_TH.arb | 2 ++ lib/l10n/tr_TR/app_tr_TR.arb | 2 ++ lib/l10n/uk_UA/app_uk_UA.arb | 2 ++ lib/l10n/vi_VN/app_vi_VN.arb | 2 ++ lib/l10n/zh_CN/app_zh_CN.arb | 2 ++ lib/l10n/zh_TW/app_zh_TW.arb | 2 ++ 38 files changed, 76 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 437b5e4..3a86005 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index ad9f7f4..9541b2a 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 4a5482c..a2650f4 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Sestavení", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Interní kamera", "@cameraInternal": {}, "cameraInternalDetail": "Použít interní kameru pro čtení čárových kódů", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index db9f0f5..8a790e7 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 3409274..e0ac2e3 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Gebäude", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Integrierte Kamera", "@cameraInternal": {}, "cameraInternalDetail": "Integrierte Kamera zum Lesen von Barcodes verwenden", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 3b7bf63..db8044c 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index f37e7d5..8036aaa 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Construyendo", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Cámara interna", "@cameraInternal": {}, "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 50be329..5bec625 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Construyendo", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Cámara interna", "@cameraInternal": {}, "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 34f0e6c..d9debf2 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 161e3f5..d69769c 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "ساختمان", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "دوربین داخلی", "@cameraInternal": {}, "cameraInternalDetail": "دسترسی دوبین برای خواندن بارکد", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index cff01b3..0d9fde0 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index c516d1f..fbe571e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Assemblage en cours", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Caméra interne", "@cameraInternal": {}, "cameraInternalDetail": "Utiliser la caméra interne pour lire les codes à barres", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 09cfeed..12bd441 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "מצלמה פנימית", "@cameraInternal": {}, "cameraInternalDetail": "השתמש במצלמה פנימית לקריאת ברקודים", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 4146cb1..70f3123 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 7579c51..5e24efa 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Gyártásban", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Belső kamera", "@cameraInternal": {}, "cameraInternalDetail": "Beépített kamera használata vonalkódolvasásra", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index a3f81e4..a23e959 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Bangunan", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Kamera Internal", "@cameraInternal": {}, "cameraInternalDetail": "Gunakan internal kamera untuk membaca barcode", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 0351b3e..21bb5ac 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "In Costruzione", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Fotocamera interna", "@cameraInternal": {}, "cameraInternalDetail": "Utilizza la fotocamera interna per leggere i codici a barre", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 13d6cc0..a7efad1 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "ビルド", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index fb000f2..5c369f3 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 7c616bb..5631e3f 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index b14e9c1..38dd26b 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index e3d0d9d..76c0dfb 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Produceren", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Interne Camera", "@cameraInternal": {}, "cameraInternalDetail": "Gebruik interne camera om barcodes te lezen", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index b839ea0..240f298 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Produserer", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internt kamera", "@cameraInternal": {}, "cameraInternalDetail": "Bruk internt kamera til å lese strekkoder", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index dca06ad..7cb2301 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Budowanie", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Kamera wewnętrzna", "@cameraInternal": {}, "cameraInternalDetail": "Użyj wewnętrznej kamery do odczytu kodów kreskowych", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index bc1266d..2e5c46c 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Produzindo", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Câmera Interna", "@cameraInternal": {}, "cameraInternalDetail": "Usar câmera interna para ler códigos de barras", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index b3cee06..7c79856 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Compilando", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Câmera Interna", "@cameraInternal": {}, "cameraInternalDetail": "Usar a câmera interna para ler códigos de barras", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index fb84828..a9924fc 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Asamblează", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Cameră internă", "@cameraInternal": {}, "cameraInternalDetail": "Folosește camera internă pentru a citi codurile de bare", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 5d3b5c0..fc3f94d 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Построение", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Внутренняя камера", "@cameraInternal": {}, "cameraInternalDetail": "Использовать внутреннюю камеру для чтения штрих-кодов", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 263506f..00bcc39 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 026f953..e028aab 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 878b0cd..10b6531 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 9f38baa..5fbe22f 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Bygger", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Intern kamera", "@cameraInternal": {}, "cameraInternalDetail": "Använd intern kamera för att läsa streckkoder", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index b2739c2..bae1bb5 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 7f2b5a3..9902308 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Oluşturma", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Dahili Kamera", "@cameraInternal": {}, "cameraInternalDetail": "Barkodları okumak için dahili kamera kullan", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index cf1032d..9a9414b 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Building", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Internal Camera", "@cameraInternal": {}, "cameraInternalDetail": "Use internal camera to read barcodes", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 3111b38..f6cd79e 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "Tòa nhà", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "Camera nội bộ", "@cameraInternal": {}, "cameraInternalDetail": "Sử dụng camera nội bộ để đọc mã vạch", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 8d5bdac..036a561 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "正在构建", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "内置相机", "@cameraInternal": {}, "cameraInternalDetail": "使用内置相机读取条形码", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 90c5bf8..521d6a4 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -138,6 +138,8 @@ "@build": {}, "building": "生產中", "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, "cameraInternal": "內置相機", "@cameraInternal": {}, "cameraInternalDetail": "使用內置相機讀取條碼", From 524c5469f1369c5392de90e94a0e29e5e8605b1f Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Dec 2024 15:24:23 +1100 Subject: [PATCH 623/746] [refactor] Scan improvements (#577) * Handle error on unexpected barcode response * Add ManufacturerPart detail view * Support barcode scanning for manufacturer part * Refactoring for null checks * Ignore selected errors in sentry * Fix API implementation for ManufacturerPart * Update release notes * More error handling * Decode quantity betterer * Refactoring * Add option to confirm checkin details * Improve response handlign * Cleanup * Remove unused imports * Fix async function * Fix for assigning custom barcode * Handle barcode scan result for company * Fix * Adjust scan priority * Refactoring MODEL_TYPE - Use instead of duplicated const strings * @override fix --- assets/release_notes.md | 3 + lib/api_form.dart | 43 ++-- lib/barcode/barcode.dart | 111 +++++++---- lib/barcode/camera_controller.dart | 14 +- lib/barcode/handler.dart | 21 +- lib/barcode/purchase_order.dart | 97 +++++----- lib/barcode/stock.dart | 4 +- lib/inventree/company.dart | 51 ++++- lib/inventree/model.dart | 2 +- lib/inventree/part.dart | 7 +- lib/inventree/project_code.dart | 2 + lib/inventree/purchase_order.dart | 84 +++++++- lib/inventree/sales_order.dart | 5 +- lib/inventree/sentry.dart | 20 ++ lib/inventree/stock.dart | 18 +- lib/l10n/app_en.arb | 15 ++ lib/preferences.dart | 1 + lib/settings/purchase_order_settings.dart | 16 ++ .../company/manufacturer_part_detail.dart | 183 ++++++++++++++++++ lib/widget/company/supplier_part_detail.dart | 25 ++- lib/widget/order/po_line_detail.dart | 68 +------ lib/widget/part/part_detail.dart | 2 +- lib/widget/stock/location_display.dart | 2 +- lib/widget/stock/stock_detail.dart | 2 +- 24 files changed, 576 insertions(+), 220 deletions(-) create mode 100644 lib/widget/company/manufacturer_part_detail.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 1b22659..8b0b61d 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,12 +1,15 @@ ### 0.17.1 - December 2024 --- +- Add support for ManufacturerPart model +- Support barcode scanning for ManufacturerPart - Fixes barcode scanning bug which prevents scanning of DataMatrix codes - Display "destination" information in PurchaseOrder detail view - Pre-fill "location" field when receiving items against PurchaseOrder - Fix display of part name in PurchaseOrderLineItem list - Adds "assigned to me" filter for Purchase Order list - Adds "assigned to me" filter for Sales Order list +- Updated translations ### 0.17.0 - December 2024 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index f8e335d..7b8cb42 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -11,15 +11,17 @@ import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/helpers.dart"; -import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/project_code.dart"; -import "package:inventree/inventree/sentry.dart"; +import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/inventree/sentry.dart"; + import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/fields.dart"; import "package:inventree/widget/progress.dart"; @@ -562,11 +564,17 @@ class APIFormField { Map data = item as Map; switch (model) { - case "part": + case InvenTreePart.MODEL_TYPE: return InvenTreePart.fromJson(data).fullname; - case "partcategory": + case InvenTreeCompany.MODEL_TYPE: + return InvenTreeCompany.fromJson(data).name; + case InvenTreePurchaseOrder.MODEL_TYPE: + return InvenTreePurchaseOrder.fromJson(data).reference; + case InvenTreeSalesOrder.MODEL_TYPE: + return InvenTreeSalesOrder.fromJson(data).reference; + case InvenTreePartCategory.MODEL_TYPE: return InvenTreePartCategory.fromJson(data).pathstring; - case "stocklocation": + case InvenTreeStockLocation.MODEL_TYPE: return InvenTreeStockLocation.fromJson(data).pathstring; default: return "itemAsString not implemented for '${model}'"; @@ -606,10 +614,12 @@ class APIFormField { Map _relatedFieldFilters() { switch (model) { - case "supplierpart": + case InvenTreeSupplierPart.MODEL_TYPE: return InvenTreeSupplierPart().defaultListFilters(); - case "stockitem": + case InvenTreeStockItem.MODEL_TYPE: return InvenTreeStockItem().defaultListFilters(); + default: + break; } return {}; @@ -643,7 +653,7 @@ class APIFormField { } switch (model) { - case "part": + case InvenTreePart.MODEL_TYPE: var part = InvenTreePart.fromJson(data); return ListTile( @@ -657,14 +667,14 @@ class APIFormField { ) : null, leading: extended ? InvenTreeAPI().getThumbnail(part.thumbnail) : null, ); - case "parttesttemplate": + case InvenTreePartTestTemplate.MODEL_TYPE: var template = InvenTreePartTestTemplate.fromJson(data); return ListTile( title: Text(template.testName), subtitle: Text(template.description), ); - case "supplierpart": + case InvenTreeSupplierPart.MODEL_TYPE: var part = InvenTreeSupplierPart.fromJson(data); return ListTile( @@ -673,7 +683,7 @@ class APIFormField { leading: extended ? InvenTreeAPI().getThumbnail(part.partImage) : null, trailing: extended && part.supplierImage.isNotEmpty ? InvenTreeAPI().getThumbnail(part.supplierImage) : null, ); - case "partcategory": + case InvenTreePartCategory.MODEL_TYPE: var cat = InvenTreePartCategory.fromJson(data); @@ -687,7 +697,7 @@ class APIFormField { style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), ) : null, ); - case "stockitem": + case InvenTreeStockItem.MODEL_TYPE: var item = InvenTreeStockItem.fromJson(data); return ListTile( @@ -697,8 +707,7 @@ class APIFormField { leading: InvenTreeAPI().getThumbnail(item.partThumbnail), trailing: Text(item.quantityString()), ); - case "stocklocation": - + case InvenTreeStockLocation.MODEL_TYPE: var loc = InvenTreeStockLocation.fromJson(data); return ListTile( @@ -711,7 +720,7 @@ class APIFormField { style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), ) : null, ); - case "salesordershipment": + case InvenTreeSalesOrderShipment.MODEL_TYPE: var shipment = InvenTreeSalesOrderShipment.fromJson(data); return ListTile( @@ -733,14 +742,14 @@ class APIFormField { title: Text(name), subtitle: Text(role), ); - case "company": + case InvenTreeCompany.MODEL_TYPE: var company = InvenTreeCompany.fromJson(data); return ListTile( title: Text(company.name), subtitle: extended ? Text(company.description) : null, leading: InvenTreeAPI().getThumbnail(company.thumbnail) ); - case "projectcode": + case InvenTreeProjectCode.MODEL_TYPE: var project_code = InvenTreeProjectCode.fromJson(data); return ListTile( title: Text(project_code.code), diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index dd2a6c8..0de089e 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -4,7 +4,9 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/inventree/sentry.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/company/manufacturer_part_detail.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; import "package:one_context/one_context.dart"; @@ -30,6 +32,7 @@ import "package:inventree/widget/order/purchase_order_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock/stock_detail.dart"; +import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/company/supplier_part_detail.dart"; @@ -176,15 +179,37 @@ class BarcodeScanHandler extends BarcodeHandler { */ Future handleSupplierPart(int pk) async { - var supplierpart = await InvenTreeSupplierPart().get(pk); + var supplierPart = await InvenTreeSupplierPart().get(pk); - if (supplierpart is InvenTreeSupplierPart) { + if (supplierPart is InvenTreeSupplierPart) { OneContext().pop(); OneContext().push(MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(supplierpart))); + builder: (context) => SupplierPartDetailWidget(supplierPart))); } } + /* + * Response when a "ManufacturerPart" instance is scanned + */ + Future handleManufacturerPart(int pk) async { + var manufacturerPart = await InvenTreeManufacturerPart().get(pk); + + if (manufacturerPart is InvenTreeManufacturerPart) { + OneContext().pop(); + OneContext().push(MaterialPageRoute( + builder: (context) => ManufacturerPartDetailWidget(manufacturerPart))); + } + } + + Future handleCompany(int pk) async { + var company = await InvenTreeCompany().get(pk); + + if (company is InvenTreeCompany) { + OneContext().pop(); + OneContext().push(MaterialPageRoute( + builder: (context) => CompanyDetailWidget(company))); + } + } /* * Response when a "PurchaseOrder" instance is scanned @@ -218,26 +243,32 @@ class BarcodeScanHandler extends BarcodeHandler { // The following model types can be matched with barcodes List validModels = [ - "part", - "stockitem", - "stocklocation", - "supplierpart", + InvenTreePart.MODEL_TYPE, + InvenTreeCompany.MODEL_TYPE, + InvenTreeStockItem.MODEL_TYPE, + InvenTreeStockLocation.MODEL_TYPE, + InvenTreeSupplierPart.MODEL_TYPE, + InvenTreeManufacturerPart.MODEL_TYPE, ]; if (InvenTreeAPI().supportsOrderBarcodes) { - validModels.add("purchaseorder"); - validModels.add("salesorder"); + validModels.add(InvenTreePurchaseOrder.MODEL_TYPE); + validModels.add(InvenTreeSalesOrder.MODEL_TYPE); } for (var key in validModels) { if (data.containsKey(key)) { - pk = (data[key]?["pk"] ?? -1) as int; + try { + pk = (data[key]?["pk"] ?? -1) as int; - // Break on the first valid match found - if (pk > 0) { - model = key; - break; + // Break on the first valid match found + if (pk > 0) { + model = key; + break; + } + } catch (error, stackTrace) { + sentryReportError("onBarcodeMatched", error, stackTrace); } } } @@ -248,25 +279,30 @@ class BarcodeScanHandler extends BarcodeHandler { barcodeSuccessTone(); switch (model) { - case "part": - await handlePart(pk); - return; - case "stockitem": + case InvenTreeStockItem.MODEL_TYPE: await handleStockItem(pk); return; - case "stocklocation": - await handleStockLocation(pk); - return; - case "supplierpart": - await handleSupplierPart(pk); - return; - case "purchaseorder": + case InvenTreePurchaseOrder.MODEL_TYPE: await handlePurchaseOrder(pk); return; - case "salesorder": + case InvenTreeSalesOrder.MODEL_TYPE: await handleSalesOrder(pk); return; - // TODO: Handle manufacturer part + case InvenTreeStockLocation.MODEL_TYPE: + await handleStockLocation(pk); + return; + case InvenTreeSupplierPart.MODEL_TYPE: + await handleSupplierPart(pk); + return; + case InvenTreeManufacturerPart.MODEL_TYPE: + await handleManufacturerPart(pk); + return; + case InvenTreePart.MODEL_TYPE: + await handlePart(pk); + return; + case InvenTreeCompany.MODEL_TYPE: + await handleCompany(pk); + return; default: // Fall through to failure state break; @@ -324,21 +360,6 @@ class UniqueBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(Map data) async { - - barcodeFailureTone(); - - // If the barcode is known, we can"t assign it to the stock item! - showSnackIcon( - L10().barcodeInUse, - icon: Icons.qr_code, - success: false - ); - } - - @override - Future onBarcodeUnknown(Map data) async { - // If the barcode is unknown, we *can* assign it to the stock item! - if (!data.containsKey("hash") && !data.containsKey("barcode_hash")) { showServerError( "barcode/", @@ -370,6 +391,12 @@ class UniqueBarcodeHandler extends BarcodeHandler { } } } + + @override + Future onBarcodeUnknown(Map data) async { + await onBarcodeMatched(data); + } + } diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 4c6edd7..ece027c 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -93,7 +93,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { /* * Callback function when a barcode is scanned */ - void _onScanSuccess(Code? code) { + Future onScanSuccess(Code? code) async { if (scanning_paused) { return; @@ -122,18 +122,16 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { if (mounted) { setState(() { scanned_code = barcode; - scanning_paused = barcode.isNotEmpty; }); } if (barcode.isNotEmpty) { - handleBarcodeData(barcode).then((_) { + pauseScan(); + + await handleBarcodeData(barcode).then((_) { if (!single_scanning && mounted) { - // Resume next scan - setState(() { - scanning_paused = false; - }); + resumeScan(); } }); } @@ -186,7 +184,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { Widget BarcodeReader(BuildContext context) { return ReaderWidget( - onScan: _onScanSuccess, + onScan: onScanSuccess, isMultiScan: false, tryHarder: true, tryInverted: true, diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index 20dc9e9..48831f9 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -79,14 +79,27 @@ class BarcodeHandler { return; } - var response = await InvenTreeAPI().post( + APIResponse? response; + + try { + response = await InvenTreeAPI().post( url, body: { "barcode": barcode, ...extra_data, }, - expectedStatusCode: null, // Do not show an error on "unexpected code" - ); + expectedStatusCode: null, // Do not show an error on "unexpected code" + ); + } catch (error, stackTrace) { + sentryReportError("Barcode.processBarcode", error, stackTrace); + response = null; + } + + if (response == null) { + barcodeFailureTone(); + showSnackIcon(L10().barcodeError, success: false); + return; + } debug("Barcode scan response" + response.data.toString()); @@ -94,7 +107,7 @@ class BarcodeHandler { // Handle strange response from the server if (!response.isValid() || !response.isMap()) { - onBarcodeUnknown({}); + await onBarcodeUnknown({}); showSnackIcon(L10().serverError, success: false); diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart index e8bba61..8b2f984 100644 --- a/lib/barcode/purchase_order.dart +++ b/lib/barcode/purchase_order.dart @@ -1,9 +1,7 @@ import "package:flutter/material.dart"; -import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/preferences.dart"; import "package:one_context/one_context.dart"; - import "package:inventree/l10.dart"; -import "package:inventree/api_form.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/handler.dart"; @@ -23,10 +21,11 @@ import "package:inventree/widget/snacks.dart"; */ class POReceiveBarcodeHandler extends BarcodeHandler { - POReceiveBarcodeHandler({this.purchaseOrder, this.location}); + POReceiveBarcodeHandler({this.purchaseOrder, this.location, this.lineItem}); InvenTreePurchaseOrder? purchaseOrder; InvenTreeStockLocation? location; + InvenTreePOLineItem? lineItem; @override String getOverlayText(BuildContext context) => L10().barcodeReceivePart; @@ -34,11 +33,15 @@ class POReceiveBarcodeHandler extends BarcodeHandler { @override Future processBarcode(String barcode, {String url = "barcode/po-receive/", - Map extra_data = const {}}) { + Map extra_data = const {}}) async { + + final bool confirm = await InvenTreeSettingsManager().getBool(INV_PO_CONFIRM_SCAN, true); final po_extra_data = { "purchase_order": purchaseOrder?.pk, "location": location?.pk, + "line_item": lineItem?.pk, + "auto_allocate": !confirm, ...extra_data, }; @@ -47,11 +50,13 @@ class POReceiveBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(Map data) async { - if (!data.containsKey("lineitem")) { + + if (data.containsKey("lineitem") || data.containsKey("success")) { + barcodeSuccess(L10().receivedItem); + return; + } else { return onBarcodeUnknown(data); } - - barcodeSuccess(L10().receivedItem); } @override @@ -66,49 +71,41 @@ class POReceiveBarcodeHandler extends BarcodeHandler { showSnackIcon(L10().missingData, success: false); } - // Construct fields to receive - Map fields = { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - "value": lineItemData["pk"] as int, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": lineItemData["quantity"] as double?, - }, - "status": { - "parent": "items", - "nested": true, - }, - "location": { - "value": lineItemData["location"] as int?, - }, - "barcode": { - "parent": "items", - "nested": true, - "hidden": true, - "type": "barcode", - "value": data["barcode_data"] as String, + // At minimum, we need the line item ID value + final int? lineItemId = lineItemData["pk"] as int?; + + if (lineItemId == null) { + barcodeFailureTone(); + return; + } + + InvenTreePOLineItem? lineItem = await InvenTreePOLineItem().get(lineItemId) as InvenTreePOLineItem?; + + if (lineItem == null) { + barcodeFailureTone(); + return; + } + + // Next, extract the "optional" fields + + // Extract information from the returned server response + double? quantity = double.tryParse((lineItemData["quantity"] ?? "0").toString()); + int? destination = lineItemData["location"] as int?; + String? barcode = data["barcode_data"] as String?; + + // Discard the barcode scanner at this stage + if (OneContext.hasContext) { + OneContext().pop(); + } + + await lineItem.receive( + OneContext().context!, + destination: destination, + quantity: quantity, + barcode: barcode, + onSuccess: () { + showSnackIcon(L10().receivedItem, success: true); } - }; - - final context = OneContext().context!; - final purchase_order_pk = lineItemData["purchase_order"]; - final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; - - launchApiForm( - context, - L10().receiveItem, - receive_url, - fields, - method: "POST", - icon: TablerIcons.transition_right, - onSuccess: (data) async { - showSnackIcon(L10().receivedItem, success: true); - } ); } diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart index d230901..126d1d0 100644 --- a/lib/barcode/stock.dart +++ b/lib/barcode/stock.dart @@ -33,7 +33,7 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { // We expect that the barcode points to a 'stocklocation' if (data.containsKey("stocklocation")) { - int _loc = (data["stocklocation"]["pk"] ?? -1) as int; + int _loc = (data["stocklocation"]?["pk"] ?? -1) as int; // A valid stock location! if (_loc > 0) { @@ -83,7 +83,7 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { Future onBarcodeMatched(Map data) async { // We expect that the barcode points to a 'stockitem' if (data.containsKey("stockitem")) { - int _item = (data["stockitem"]["pk"] ?? -1) as int; + int _item = (data["stockitem"]?["pk"] ?? -1) as int; // A valid stock location! if (_item > 0) { diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index b9bba77..18e543e 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -18,6 +18,8 @@ class InvenTreeCompany extends InvenTreeModel { @override String get URL => "company/"; + static const String MODEL_TYPE = "company"; + @override List get rolesRequired => ["purchase_order", "sales_order", "return_order"]; @@ -128,6 +130,8 @@ class InvenTreeSupplierPart extends InvenTreeModel { @override String get URL => "company/part/"; + static const String MODEL_TYPE = "supplierpart"; + @override List get rolesRequired => ["part", "purchase_order"]; @@ -171,7 +175,7 @@ class InvenTreeSupplierPart extends InvenTreeModel { String get MPN => getString("MPN", subKey: "manufacturer_part_detail"); - String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; int get manufacturerPartId => getInt("manufacturer_part"); @@ -179,14 +183,14 @@ class InvenTreeSupplierPart extends InvenTreeModel { String get supplierName => getString("name", subKey: "supplier_detail"); - String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; String get SKU => getString("SKU"); bool get active => getBool("active", backup: true); int get partId => getInt("part"); - + String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; String get partName => getString("name", subKey: "part_detail"); @@ -219,21 +223,52 @@ class InvenTreeManufacturerPart extends InvenTreeModel { InvenTreeManufacturerPart.fromJson(Map json) : super.fromJson(json); @override - String url = "company/part/manufacturer/"; + String URL = "company/part/manufacturer/"; + + static const String MODEL_TYPE = "manufacturerpart"; @override - Map defaultListFilters() { + List get rolesRequired => ["part"]; + + @override + Map> formFields() { + Map> fields = { + "manufacturer": {}, + "MPN": {}, + "link": {}, + }; + + return fields; + } + + @override + Map defaultFilters() { return { "manufacturer_detail": "true", + "part_detail": "true", }; } int get partId => getInt("part"); - + + String get partName => getString("name", subKey: "part_detail"); + + String get partDescription => getString("description", subKey: "part_detail"); + + String get partIPN => getString("IPN", subKey: "part_detail"); + + String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + int get manufacturerId => getInt("manufacturer"); - + + String get manufacturerName => getString("name", subKey: "manufacturer_detail"); + + String get manufacturerDescription => getString("description", subKey: "manufacturer_detail"); + + String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get MPN => getString("MPN"); - + @override InvenTreeModel createFromJson(Map json) => InvenTreeManufacturerPart.fromJson(json); } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 6d0e890..42ced88 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -66,7 +66,7 @@ class InvenTreeModel { String get WEB_URL => ""; // Return the "model type" of this model - String get MODEL_TYPE => ""; + static const String MODEL_TYPE = ""; // Helper function to set a value in the JSON data void setValue(String key, dynamic value) { diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 103fa58..c803c32 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -23,6 +23,8 @@ class InvenTreePartCategory extends InvenTreeModel { @override String get URL => "part/category/"; + static const String MODEL_TYPE = "partcategory"; + @override List get rolesRequired => ["part_category"]; @@ -79,6 +81,8 @@ class InvenTreePartTestTemplate extends InvenTreeModel { @override String get URL => "part/test-template/"; + static const String MODEL_TYPE = "parttesttemplate"; + String get key => getString("key"); String get testName => getString("test_name"); @@ -192,8 +196,7 @@ class InvenTreePart extends InvenTreeModel { @override String get URL => "part/"; - @override - String get MODEL_TYPE => "part"; + static const String MODEL_TYPE = "part"; @override List get rolesRequired => ["part"]; diff --git a/lib/inventree/project_code.dart b/lib/inventree/project_code.dart index 07a0c19..e5d4528 100644 --- a/lib/inventree/project_code.dart +++ b/lib/inventree/project_code.dart @@ -16,6 +16,8 @@ class InvenTreeProjectCode extends InvenTreeModel { @override String get URL => "project-code/"; + static const String MODEL_TYPE = "projectcode"; + @override Map> formFields() { return { diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 82cb0f3..c258c8b 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,3 +1,5 @@ +import "package:flutter/cupertino.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; @@ -5,6 +7,9 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/orders.dart"; import "package:inventree/widget/progress.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/l10.dart"; + /* * Class representing an individual PurchaseOrder instance @@ -21,8 +26,7 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { @override String get URL => "order/po/"; - @override - String get MODEL_TYPE => "purchaseorder"; + static const String MODEL_TYPE = "purchaseorder"; @override List get rolesRequired => ["purchase_order"]; @@ -212,6 +216,16 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { } } + InvenTreePurchaseOrder? get purchaseOrder { + dynamic detail = jsondata["order_detail"]; + + if (detail == null) { + return null; + } else { + return InvenTreePurchaseOrder.fromJson(detail as Map); + } + } + String get SKU => getString("SKU", subKey: "supplier_part_detail"); double get purchasePrice => getDouble("purchase_price"); @@ -223,6 +237,72 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { Map get orderDetail => getMap("order_detail"); Map get destinationDetail => getMap("destination_detail"); + + // Receive this line item into stock + Future receive(BuildContext context, {int? destination, double? quantity, String? barcode, Function? onSuccess}) async { + // Infer the destination location from the line item if not provided + if (destinationId > 0) { + destination = destinationId; + } + + destination ??= (orderDetail["destination"]) as int?; + + quantity ??= outstanding; + + // Construct form fields + Map fields = { + "line_item": { + "parent": "items", + "nested": true, + "hidden": true, + "value": pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": quantity, + }, + "location": {}, + "status": { + "parent": "items", + "nested": true, + }, + "batch_code": { + "parent": "items", + "nested": true, + }, + "barcode": { + "parent": "items", + "nested": true, + "type": "barcode", + "label": L10().barcodeAssign, + "value": barcode, + "required": false, + } + }; + + if (destination != null && destination > 0) { + fields["location"]?["value"] = destination; + } + + InvenTreePurchaseOrder? order = purchaseOrder; + + if (order != null) { + await launchApiForm( + context, + L10().receiveItem, + order.receive_url, + fields, + method: "POST", + icon: TablerIcons.transition_right, + onSuccess: (data) { + if (onSuccess != null) { + onSuccess(); + } + } + ); + } + } } /* diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 9acc374..7372250 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -24,8 +24,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { @override String get URL => "order/so/"; - @override - String get MODEL_TYPE => "salesorder"; + static const String MODEL_TYPE = "salesorder"; @override List get rolesRequired => ["sales_order"]; @@ -250,6 +249,8 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { @override String get URL => "/order/so/shipment/"; + static const String MODEL_TYPE = "salesordershipment"; + @override Map> formFields() { Map> fields = { diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 34894ff..a052ed5 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -158,6 +158,11 @@ Future sentryReportMessage(String message, {Map? context}) */ Future sentryReportError(String source, dynamic error, StackTrace? stackTrace, {Map context = const {}}) async { + if (sentryIgnoreError(error)) { + // No action on this error + return; + } + print("----- Sentry Intercepted error: $error -----"); print(stackTrace); @@ -228,3 +233,18 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr print("Uploaded information to Sentry.io : ${response.toString()}"); }); } + + +/* + * Test if a certain error should be ignored by Sentry + */ +bool sentryIgnoreError(dynamic error) { + // Ignore 404 errors for media files + if (error is HttpException) { + if (error.uri.toString().contains("/media/") && error.message.contains("404")) { + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 7b03d18..1ae5e7f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -98,7 +98,7 @@ class InvenTreeStockItemHistory extends InvenTreeModel { String get URL => "stock/track/"; @override - Map defaultListFilters() { + Map defaultFilters() { // By default, order by decreasing date return { @@ -168,8 +168,7 @@ class InvenTreeStockItem extends InvenTreeModel { @override String get URL => "stock/"; - @override - String get MODEL_TYPE => "stockitem"; + static const String MODEL_TYPE = "stockitem"; @override List get rolesRequired => ["stock"]; @@ -206,7 +205,7 @@ class InvenTreeStockItem extends InvenTreeModel { if (isSerialized()) { // Prevent editing of 'quantity' field if the item is serialized - fields["quantity"]["hidden"] = true; + fields["quantity"]?["hidden"] = true; } // Old API does not support these fields @@ -395,7 +394,7 @@ class InvenTreeStockItem extends InvenTreeModel { // Use the detailed part information as priority if (jsondata.containsKey("part_detail")) { - nm = (jsondata["part_detail"]["full_name"] ?? "") as String; + nm = (jsondata["part_detail"]?["full_name"] ?? "") as String; } // Backup if first value fails @@ -411,7 +410,7 @@ class InvenTreeStockItem extends InvenTreeModel { // Use the detailed part description as priority if (jsondata.containsKey("part_detail")) { - desc = (jsondata["part_detail"]["description"] ?? "") as String; + desc = (jsondata["part_detail"]?["description"] ?? "") as String; } if (desc.isEmpty) { @@ -425,7 +424,7 @@ class InvenTreeStockItem extends InvenTreeModel { String img = ""; if (jsondata.containsKey("part_detail")) { - img = (jsondata["part_detail"]["thumbnail"] ?? "") as String; + img = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; } if (img.isEmpty) { @@ -468,7 +467,7 @@ class InvenTreeStockItem extends InvenTreeModel { if (jsondata.containsKey("supplier_part_detail")) { thumb = (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") as String; } else if (jsondata.containsKey("supplier_detail")) { - thumb = (jsondata["supplier_detail"]["image"] ?? "") as String; + thumb = (jsondata["supplier_detail"]?["image"] ?? "") as String; } return thumb; @@ -681,8 +680,7 @@ class InvenTreeStockLocation extends InvenTreeModel { @override String get URL => "stock/location/"; - @override - String get MODEL_TYPE => "stocklocation"; + static const String MODEL_TYPE = "stocklocation"; @override List get rolesRequired => ["stock_location"]; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index d6693bd..ef3b9d9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -608,6 +608,9 @@ "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", "@keywords": {}, @@ -684,6 +687,12 @@ "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, @@ -915,6 +924,12 @@ "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, diff --git a/lib/preferences.dart b/lib/preferences.dart index 5700487..8507cd3 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -39,6 +39,7 @@ const String INV_STOCK_CONFIRM_SCAN = "stockConfirmScan"; // Purchase order settings const String INV_PO_ENABLE = "poEnable"; const String INV_PO_SHOW_CAMERA = "poShowCamera"; +const String INV_PO_CONFIRM_SCAN = "poConfirmScan"; // Sales order settings const String INV_SO_ENABLE = "soEnable"; diff --git a/lib/settings/purchase_order_settings.dart b/lib/settings/purchase_order_settings.dart index 5a3b430..888b89b 100644 --- a/lib/settings/purchase_order_settings.dart +++ b/lib/settings/purchase_order_settings.dart @@ -19,6 +19,7 @@ class _InvenTreePurchaseOrderSettingsState extends State loadSettings() async { poEnable = await InvenTreeSettingsManager().getBool(INV_PO_ENABLE, true); poShowCamera = await InvenTreeSettingsManager().getBool(INV_PO_SHOW_CAMERA, true); + poConfirmScan = await InvenTreeSettingsManager().getBool(INV_PO_CONFIRM_SCAN, true); if (mounted) { setState(() { @@ -75,6 +77,20 @@ class _InvenTreePurchaseOrderSettingsState extends State _ManufacturerPartDisplayState(); +} + + +class _ManufacturerPartDisplayState extends RefreshableState { + + _ManufacturerPartDisplayState(); + + @override + String getAppBarTitle() => L10().manufacturerPart; + + @override + Future request(BuildContext context) async { + final bool result = widget.manufacturerPart.pk > 0 && + await widget.manufacturerPart.reload(); + + if (!result) { + Navigator.of(context).pop(); + } + } + + Future editManufacturerPart(BuildContext context) async { + widget.manufacturerPart.editForm( + context, + L10().manufacturerPartEdit, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().itemUpdated, success: true); + } + ); + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + // TODO: Barcode actions? + + return actions; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.manufacturerPart.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().edit, + onPressed: () { + editManufacturerPart(context); + } + ) + ); + } + + return actions; + } + + /* + * Build a set of tiles to display for this ManufacturerPart instance + */ + @override + List getTiles(BuildContext context) { + List tiles = []; + + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + + // Internal Part + tiles.add( + ListTile( + title: Text(L10().internalPart), + subtitle: Text(widget.manufacturerPart.partName), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: InvenTreeAPI().getThumbnail(widget.manufacturerPart.partImage), + onTap: () async { + showLoadingOverlay(); + final part = await InvenTreePart().get(widget.manufacturerPart.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => PartDetailWidget(part))); + } + }, + ) + ); + + // Manufacturer details + tiles.add( + ListTile( + title: Text(L10().manufacturer), + subtitle: Text(widget.manufacturerPart.manufacturerName), + leading: Icon(TablerIcons.building_factory_2, color: COLOR_ACTION), + trailing: InvenTreeAPI().getThumbnail(widget.manufacturerPart.manufacturerImage), + onTap: () async { + showLoadingOverlay(); + var supplier = await InvenTreeCompany().get(widget.manufacturerPart.manufacturerId); + hideLoadingOverlay(); + + if (supplier is InvenTreeCompany) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => CompanyDetailWidget(supplier) + )); + } + } + ) + ); + + // MPN (part number) + tiles.add( + ListTile( + title: Text(L10().manufacturerPartNumber), + subtitle: Text(widget.manufacturerPart.MPN), + leading: Icon(TablerIcons.hash), + ) + ); + + // Description + if (widget.manufacturerPart.description.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().description), + subtitle: Text(widget.manufacturerPart.description), + leading: Icon(TablerIcons.info_circle), + ) + ); + } + + if (widget.manufacturerPart.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text(widget.manufacturerPart.link), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () async { + var uri = Uri.tryParse(widget.manufacturerPart.link); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); + } + }, + ) + ); + } + + return tiles; + } + +} diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index c6c5046..c287f0a 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -1,21 +1,23 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:url_launcher/url_launcher.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; -import "package:inventree/barcode/barcode.dart"; import "package:inventree/l10.dart"; +import "package:inventree/barcode/barcode.dart"; + import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/company.dart"; -import "package:inventree/widget/company/company_detail.dart"; -import "package:inventree/widget/part/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:url_launcher/url_launcher.dart"; +import "package:inventree/widget/company/company_detail.dart"; +import "package:inventree/widget/company/manufacturer_part_detail.dart"; +import "package:inventree/widget/part/part_detail.dart"; /* @@ -180,7 +182,7 @@ class _SupplierPartDisplayState extends RefreshableState ManufacturerPartDetailWidget(manufacturerPart) + )); + } + }, ) ); } diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index 06e0a73..6ae896e 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -2,7 +2,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; -import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/model.dart"; @@ -132,72 +131,15 @@ class _POLineDetailWidgetState extends RefreshableState { // Launch a form to 'receive' this line item Future receiveLineItem(BuildContext context) async { - - // Pre-fill the "destination" to receive into - int destination = widget.item.destinationId; - - if (destination < 0) { - destination = (widget.item.orderDetail["destination"] ?? -1) as int; - } - - // Construct fields to receive - Map fields = { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - "value": widget.item.pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": widget.item.outstanding, - }, - "status": { - "parent": "items", - "nested": true, - }, - "location": {}, - "batch_code": { - "parent": "items", - "nested": true, - }, - "barcode": { - "parent": "items", - "nested": true, - "type": "barcode", - "label": L10().barcodeAssign, - "required": false, - } - }; - - if (destination > 0) { - fields["location"]?["value"] = destination; - } - - showLoadingOverlay(); - var order = await InvenTreePurchaseOrder().get(widget.item.orderId); - hideLoadingOverlay(); - - if (order is InvenTreePurchaseOrder) { - launchApiForm( + widget.item.receive( context, - L10().receiveItem, - order.receive_url, - fields, - method: "POST", - icon: TablerIcons.transition_right, - onSuccess: (data) async { - showSnackIcon(L10().receivedItem, success: true); - refresh(context); + onSuccess: () => { + showSnackIcon(L10().receivedItem, success: true), + refresh(context) } ); - } else { - showSnackIcon(L10().error); - return; - } } - + @override List getTiles(BuildContext context) { List tiles = []; diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 0e2f2ca..a11fe4c 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -239,7 +239,7 @@ class _PartDisplayState extends RefreshableState { if (allowLabelPrinting) { - String model_type = api.supportsModernLabelPrinting ? InvenTreePart().MODEL_TYPE : "part"; + String model_type = api.supportsModernLabelPrinting ? InvenTreePart.MODEL_TYPE : "part"; String item_key = api.supportsModernLabelPrinting ? "items" : "part"; _labels = await getLabelTemplates( diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 42e8907..07a8464 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -246,7 +246,7 @@ class _LocationDisplayState extends RefreshableState { if (widget.location != null) { - String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "location"; + String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation.MODEL_TYPE : "location"; String item_key = api.supportsModernLabelPrinting ? "items" : "location"; _labels = await getLabelTemplates( diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 0081708..1b21598 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -298,7 +298,7 @@ class _StockItemDisplayState extends RefreshableState { // Request information on labels available for this stock item if (allowLabelPrinting) { - String model_type = api.supportsModernLabelPrinting ? InvenTreeStockItem().MODEL_TYPE : "stock"; + String model_type = api.supportsModernLabelPrinting ? InvenTreeStockItem.MODEL_TYPE : "stock"; String item_key = api.supportsModernLabelPrinting ? "items" : "item"; // Clear the existing labels list From 665de2bd5abb0e398329c870ad0528ccaff9e0d2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Dec 2024 17:29:35 +1100 Subject: [PATCH 624/746] Refactor search widget (#578) * Refactor search widget * Cleanup * Fix for unallocated stock count * Fix race condition - Only upate results which match the current search term - Prevents issues with multiple "competing" queries * Fix for stock quantity * Fix icon credits * Tweak app bar color * Cleanup visual stylinh --- assets/credits.md | 5 +- assets/release_notes.md | 1 + lib/app_colors.dart | 2 +- lib/inventree/model.dart | 8 +- lib/inventree/part.dart | 17 ++- lib/widget/part/part_detail.dart | 10 +- lib/widget/search.dart | 230 +++++++++++++++++++------------ 7 files changed, 168 insertions(+), 105 deletions(-) diff --git a/assets/credits.md b/assets/credits.md index abffb6d..16f2801 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -7,14 +7,15 @@ Thanks to the following contributors, for their work building this app! - [GoryMoon](https://github.com/GoryMoon) - [simonkuehling](https://github.com/simonkuehling) - [Bobbe](https://github.com/30350n) - +- [awnz](https://github.com/awnz) +- [joaomnuno](https://github.com/joaomnuno) -------- ## Assets The InvenTree App makes use of the following third party assets -- Icons are provided by [fontawesome](https://fontawesome.com) +- Icons are provided by [tabler.io](https://tabler.io/icons) - Sound files have been sourced from [zapsplat](https://www.zapsplat.com) -------- diff --git a/assets/release_notes.md b/assets/release_notes.md index 8b0b61d..004e115 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Add support for ManufacturerPart model - Support barcode scanning for ManufacturerPart +- Fix bugs in global search view - Fixes barcode scanning bug which prevents scanning of DataMatrix codes - Display "destination" information in PurchaseOrder detail view - Pre-fill "location" field when receiving items against PurchaseOrder diff --git a/lib/app_colors.dart b/lib/app_colors.dart index d9b0da9..5ed9e20 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -29,7 +29,7 @@ Color get COLOR_ACTION { // Return an "app bar" color based on the current theme Color get COLOR_APP_BAR { - return Colors.blueGrey; + return Color.fromRGBO(55, 150, 175, 1); } const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 42ced88..2078f86 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -301,13 +301,7 @@ class InvenTreeModel { /* * Attempt to extract a custom icon for this model. - * If icon data is provided, attempt to convert to a FontAwesome icon - * - * Icon data *should* be presented something like "fas fa-boxes" / "fab fa-github" (etc): - * - * - First part specifies the *style* - * - Second part specifies the icon - * + * If icon data is provided, attempt to convert to a TablerIcon icon */ IconData? get customIcon { String icon = (jsondata["icon"] ?? "").toString().trim(); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index c803c32..29fa99e 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -1,4 +1,5 @@ import "dart:io"; +import "dart:math"; import "package:flutter/material.dart"; @@ -311,19 +312,29 @@ class InvenTreePart extends InvenTreeModel { String get onOrderString => simpleNumberString(onOrder); - double get inStock => getDouble("in_stock"); + double get inStock { + if (jsondata.containsKey("total_in_stock")) { + return getDouble("total_in_stock"); + } else { + return getDouble("in_stock"); + } + } String get inStockString => simpleNumberString(inStock); // Get the 'available stock' for this Part double get unallocatedStock { + double unallocated = 0; + // Note that the 'available_stock' was not added until API v35 if (jsondata.containsKey("unallocated_stock")) { - return double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; + unallocated = double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; } else { - return inStock; + unallocated = inStock; } + + return max(0, unallocated); } String get unallocatedStockString => simpleNumberString(unallocatedStock); diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index a11fe4c..ee18c55 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -703,12 +703,10 @@ class _PartDisplayState extends RefreshableState { @override List getTabs(BuildContext context) { List tabs = [ - Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: partTiles() - ).toList() + SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: partTiles(), ) ), PaginatedStockItemList({"part": part.pk.toString()}) diff --git a/lib/widget/search.dart b/lib/widget/search.dart index dfa0d13..c76924f 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -8,6 +8,8 @@ import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/sales_order.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/stock.dart"; @@ -16,8 +18,10 @@ import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/stock/stock_list.dart"; import "package:inventree/widget/part/category_list.dart"; -import "package:inventree/widget/company/company_list.dart"; import "package:inventree/widget/stock/location_list.dart"; +import "package:inventree/widget/order/sales_order_list.dart"; +import "package:inventree/widget/company/company_list.dart"; +import "package:inventree/widget/company/supplier_part_list.dart"; // Widget for performing database-wide search @@ -86,12 +90,34 @@ class _SearchDisplayState extends RefreshableState { // Individual search result count (for legacy search API) int nPendingSearches = 0; + int nPartResults = 0; int nCategoryResults = 0; int nStockResults = 0; int nLocationResults = 0; - int nSupplierResults = 0; int nPurchaseOrderResults = 0; + int nSalesOrderResults = 0; + int nCompanyResults = 0; + int nSupplierPartResults = 0; + int nManufacturerPartResults = 0; + + void resetSearchResults() { + if (mounted) { + setState(() { + nPendingSearches = 0; + + nPartResults = 0; + nCategoryResults = 0; + nStockResults = 0; + nLocationResults = 0; + nPurchaseOrderResults = 0; + nSalesOrderResults = 0; + nCompanyResults = 0; + nSupplierPartResults = 0; + nManufacturerPartResults = 0; + }); + } + } // Callback when the text is being edited // Incorporates a debounce timer to restrict search frequency @@ -104,7 +130,7 @@ class _SearchDisplayState extends RefreshableState { if (immediate) { search(text); } else { - debounceTimer = Timer(Duration(milliseconds: 250), () { + debounceTimer = Timer(Duration(milliseconds: 300), () { search(text); }); } @@ -142,24 +168,33 @@ class _SearchDisplayState extends RefreshableState { "search/", body: body, expectedStatusCode: 200).then((APIResponse response) { - decrementPendingSearches(); + String searchTerm = (body["search"] ?? "").toString(); - Map results = {}; + // Only update if the results correspond to the current search term + if (searchTerm == searchController.text && mounted) { - if (response.data is Map) { - results = response.data as Map; - } + decrementPendingSearches(); - if (mounted) { - setState(() { - nPartResults = getSearchResultCount(results, "part"); - nCategoryResults = getSearchResultCount(results, "partcategory"); - nStockResults = getSearchResultCount(results, "stockitem"); - nLocationResults = getSearchResultCount(results, "stocklocation"); - nSupplierResults = 0; //getSearchResultCount(results, "") - nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder"); - }); + Map results = {}; + + if (response.isValid() && response.data is Map) { + results = response.data as Map; + + setState(() { + nPartResults = getSearchResultCount(results, InvenTreePart.MODEL_TYPE); + nCategoryResults = getSearchResultCount(results, InvenTreePartCategory.MODEL_TYPE); + nStockResults = getSearchResultCount(results, InvenTreeStockItem.MODEL_TYPE); + nLocationResults = getSearchResultCount(results, InvenTreeStockLocation.MODEL_TYPE); + nPurchaseOrderResults = getSearchResultCount(results, InvenTreePurchaseOrder.MODEL_TYPE); + nSalesOrderResults = getSearchResultCount(results, InvenTreeSalesOrder.MODEL_TYPE); + nCompanyResults = getSearchResultCount(results, InvenTreeCompany.MODEL_TYPE); + nSupplierPartResults = getSearchResultCount(results, InvenTreeSupplierPart.MODEL_TYPE); + nManufacturerPartResults = getSearchResultCount(results, InvenTreeManufacturerPart.MODEL_TYPE); + }); + } else { + resetSearchResults(); + } } }); } @@ -174,17 +209,7 @@ class _SearchDisplayState extends RefreshableState { return; } - setState(() { - // Do not search on an empty string - nPartResults = 0; - nCategoryResults = 0; - nStockResults = 0; - nLocationResults = 0; - nSupplierResults = 0; - nPurchaseOrderResults = 0; - - nPendingSearches = 0; - }); + resetSearchResults(); // Cancel the previous search query (if in progress) if (_search_query != null) { @@ -201,46 +226,34 @@ class _SearchDisplayState extends RefreshableState { // Consolidated search allows us to perform *all* searches in a single query if (api.supportsConsolidatedSearch) { + Map body = { "limit": 1, "search": term, + + InvenTreePart.MODEL_TYPE: {}, + InvenTreePartCategory.MODEL_TYPE: {}, + InvenTreeStockItem.MODEL_TYPE: {}, + InvenTreeStockLocation.MODEL_TYPE: {}, + InvenTreePurchaseOrder.MODEL_TYPE: {}, + InvenTreeSalesOrder.MODEL_TYPE: {}, + InvenTreeCompany.MODEL_TYPE: {}, + InvenTreeSupplierPart.MODEL_TYPE: {}, + InvenTreeManufacturerPart.MODEL_TYPE: {}, }; - // Part search - if (InvenTreePart().canView) { - body["part"] = {}; - } - - // PartCategory search - if (InvenTreePartCategory().canView) { - body["partcategory"] = {}; - } - - // StockItem search - if (InvenTreeStockItem().canView) { - body["stockitem"] = { - "in_stock": true, - }; - } - - // StockLocation search - if (InvenTreeStockLocation().canView) { - body["stocklocation"] = {}; - } - - // PurchaseOrder search - if (InvenTreePurchaseOrder().canView) { - body["purchaseorder"] = { - "outstanding": true - }; - } - if (body.isNotEmpty) { - nPendingSearches++; - _search_query = CancelableOperation.fromFuture( - _perform_search(body), - ); + if (mounted) { + setState(() { + nPendingSearches = 1; + }); + + _search_query = CancelableOperation.fromFuture( + _perform_search(body), + ); + } + } } else { legacySearch(term); @@ -466,31 +479,6 @@ class _SearchDisplayState extends RefreshableState { ); } - // Suppliers - if (nSupplierResults > 0) { - results.add( - ListTile( - title: Text(L10().suppliers), - leading: Icon(TablerIcons.building), - trailing: Text("${nSupplierResults}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().suppliers, - { - "is_supplier": "true", - "original_search": query - } - ) - ) - ); - }, - ) - ); - } - // Purchase orders if (nPurchaseOrderResults > 0) { results.add( @@ -514,6 +502,76 @@ class _SearchDisplayState extends RefreshableState { ); } + // Sales orders + if (nSalesOrderResults > 0) { + results.add( + ListTile( + title: Text(L10().salesOrders), + leading: Icon(TablerIcons.shopping_cart), + trailing: Text("${nSalesOrderResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget( + filters: { + "original_search": query + } + ) + ) + ); + }, + ) + ); + } + + // Company results + if (nCompanyResults > 0) { + results.add( + ListTile( + title: Text(L10().companies), + leading: Icon(TablerIcons.building), + trailing: Text("${nCompanyResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyListWidget( + L10().companies, + { + "original_search": query + } + ) + ) + ); + }, + ) + ); + } + + // Supplier part results + if (nSupplierPartResults > 0) { + results.add( + ListTile( + title: Text(L10().supplierParts), + leading: Icon(TablerIcons.box), + trailing: Text("${nSupplierPartResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SupplierPartList( + { + "original_search": query + } + ) + ) + ); + }, + ) + ); + } + if (isSearching()) { tiles.add( ListTile( From 51fb88985451333df56747430a8305305d930404 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 15 Dec 2024 08:55:32 +1100 Subject: [PATCH 625/746] New Crowdin updates (#579) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 10 ++++++++++ lib/l10n/bg_BG/app_bg_BG.arb | 10 ++++++++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 10 ++++++++++ lib/l10n/da_DK/app_da_DK.arb | 10 ++++++++++ lib/l10n/de_DE/app_de_DE.arb | 10 ++++++++++ lib/l10n/el_GR/app_el_GR.arb | 10 ++++++++++ lib/l10n/es_ES/app_es_ES.arb | 10 ++++++++++ lib/l10n/es_MX/app_es_MX.arb | 10 ++++++++++ lib/l10n/et_EE/app_et_EE.arb | 10 ++++++++++ lib/l10n/fa_IR/app_fa_IR.arb | 10 ++++++++++ lib/l10n/fi_FI/app_fi_FI.arb | 10 ++++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 10 ++++++++++ lib/l10n/he_IL/app_he_IL.arb | 10 ++++++++++ lib/l10n/hi_IN/app_hi_IN.arb | 10 ++++++++++ lib/l10n/hu_HU/app_hu_HU.arb | 10 ++++++++++ lib/l10n/id_ID/app_id_ID.arb | 10 ++++++++++ lib/l10n/it_IT/app_it_IT.arb | 10 ++++++++++ lib/l10n/ja_JP/app_ja_JP.arb | 10 ++++++++++ lib/l10n/ko_KR/app_ko_KR.arb | 10 ++++++++++ lib/l10n/lt_LT/app_lt_LT.arb | 10 ++++++++++ lib/l10n/lv_LV/app_lv_LV.arb | 10 ++++++++++ lib/l10n/nl_NL/app_nl_NL.arb | 10 ++++++++++ lib/l10n/no_NO/app_no_NO.arb | 10 ++++++++++ lib/l10n/pl_PL/app_pl_PL.arb | 10 ++++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 10 ++++++++++ lib/l10n/pt_PT/app_pt_PT.arb | 10 ++++++++++ lib/l10n/ro_RO/app_ro_RO.arb | 10 ++++++++++ lib/l10n/ru_RU/app_ru_RU.arb | 10 ++++++++++ lib/l10n/sk_SK/app_sk_SK.arb | 10 ++++++++++ lib/l10n/sl_SI/app_sl_SI.arb | 10 ++++++++++ lib/l10n/sr_CS/app_sr_CS.arb | 10 ++++++++++ lib/l10n/sv_SE/app_sv_SE.arb | 10 ++++++++++ lib/l10n/th_TH/app_th_TH.arb | 10 ++++++++++ lib/l10n/tr_TR/app_tr_TR.arb | 10 ++++++++++ lib/l10n/uk_UA/app_uk_UA.arb | 10 ++++++++++ lib/l10n/vi_VN/app_vi_VN.arb | 10 ++++++++++ lib/l10n/zh_CN/app_zh_CN.arb | 10 ++++++++++ lib/l10n/zh_TW/app_zh_TW.arb | 10 ++++++++++ 38 files changed, 380 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 3a86005..e7a552a 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 9541b2a..ef04695 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index a2650f4..5d834e2 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Položka byla odebrána", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Klíčová slova", "@keywords": {}, "labelPrinting": "Tisk štítku", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Ztraceno", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Číslo dílu výrobce", "@manufacturerPartNumber": {}, "manufacturer": "Výrobce", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Kód projektu", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 8a790e7..ff8f2a6 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index e0ac2e3..674b590 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Element wurde gelöscht", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Schlüsselwörter", "@keywords": {}, "labelPrinting": "Etikettendruck", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Teilenummer des Herstellers", "@manufacturerPartNumber": {}, "manufacturer": "Hersteller", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Projektcode", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index db8044c..795db0b 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 8036aaa..92a4719 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "El artículo ha sido eliminado", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Palabras claves", "@keywords": {}, "labelPrinting": "Impresión de etiquetas", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Número de pieza del fabricante", "@manufacturerPartNumber": {}, "manufacturer": "Fabricante", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Habilitar órdenes de compra", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Activar funcionalidad de orden de compra", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 5bec625..75061b7 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "El artículo ha sido eliminado", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Palabras claves", "@keywords": {}, "labelPrinting": "Impresión de etiquetas", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Número de parte del fabricante", "@manufacturerPartNumber": {}, "manufacturer": "Fabricante", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Código del proyecto", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Habilitar órdenes de compra", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Habilitar funcionalidad de orden de compra", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index d9debf2..0812912 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Märksõnad", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Kadunud", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Projekti kood", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index d69769c..06daf85 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 0d9fde0..70c13c1 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Avainsanat", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Valmistaja", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index fbe571e..e37d07f 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "L'article a été supprimé", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Mots clés", "@keywords": {}, "labelPrinting": "Impression étiquettes", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perdu", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Numéro de pièce fabricant", "@manufacturerPartNumber": {}, "manufacturer": "Fabricant", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Code Projet", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 12bd441..72bf6b4 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "הפרריט הוסר", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "מילות מפתח", "@keywords": {}, "labelPrinting": "הדפסת תווית", @@ -462,6 +464,10 @@ "@link": {}, "lost": "אבודים", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "מספר פריט של היצרן", "@manufacturerPartNumber": {}, "manufacturer": "יצרן", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "קוד פרויקט ", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 70f3123..7015356 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 5e24efa..d3f1728 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Termék el lett távolítva", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Kulcsszavak", "@keywords": {}, "labelPrinting": "Címke nyomtatás", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Elveszett", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Gyártói cikkszám", "@manufacturerPartNumber": {}, "manufacturer": "Gyártó", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Projektszám", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index a23e959..a45667a 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Kata Kunci", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 21bb5ac..98adb2c 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "L'elemento è stato rimosso", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Parole Chiave", "@keywords": {}, "labelPrinting": "Etichetta in stampa", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perso", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Codice articolo produttore", "@manufacturerPartNumber": {}, "manufacturer": "Produttore", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Codice del progetto", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index a7efad1..4e74987 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "キーワード", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "損失", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 5c369f3..7a60a68 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "키워드", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 5631e3f..05542aa 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 38dd26b..12e845e 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 76c0dfb..981bdf6 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item is verwijderd", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Trefwoorden", "@keywords": {}, "labelPrinting": "Label afdrukken", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Verloren", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Onderdeelnummer fabrikant", "@manufacturerPartNumber": {}, "manufacturer": "Fabrikant", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 240f298..6d2758f 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Elementet har blitt fjernet", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Nøkkelord", "@keywords": {}, "labelPrinting": "Etikettutskrift", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Tapt", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Produsentens varenummer", "@manufacturerPartNumber": {}, "manufacturer": "Produsent", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Prosjektkode", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 7cb2301..78e8944 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Element został usunięty", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Słowa kluczowe", "@keywords": {}, "labelPrinting": "Drukowanie etykiet", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Zagubiono", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Numer Części Producenta (MPN)", "@manufacturerPartNumber": {}, "manufacturer": "Producent", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Kod projektu", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 2e5c46c..03a4b9e 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "O item foi removido", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Palavras chave", "@keywords": {}, "labelPrinting": "Impressão de Etiqueta", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Número de Peça do Fabricante", "@manufacturerPartNumber": {}, "manufacturer": "Fabricante", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Código do projeto", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 7c79856..1f9e022 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Perdido", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Número da Peça do Fabricante", "@manufacturerPartNumber": {}, "manufacturer": "Fabricante", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index a9924fc..e8fc048 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Articolul a fost eliminat", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Cuvinte cheie", "@keywords": {}, "labelPrinting": "Printare etichete", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Pierdut", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Număr Serie Producător", "@manufacturerPartNumber": {}, "manufacturer": "Producător", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index fc3f94d..3b3bf2b 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Позиция была удалена", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Ключевые слова", "@keywords": {}, "labelPrinting": "Печать этикеток", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Потерян", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Код производителя", "@manufacturerPartNumber": {}, "manufacturer": "Производитель", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Код проекта", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 00bcc39..6de91f9 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index e028aab..7759628 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 10b6531..f0df4cb 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 5fbe22f..78963ad 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Objektet har tagits bort", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Nyckelord", "@keywords": {}, "labelPrinting": "Utskrift av etiketter", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Förlorad", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Tillverkarens artikelnummer", "@manufacturerPartNumber": {}, "manufacturer": "Tillverkare", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Projektkod", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index bae1bb5..bfc0c5a 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 9902308..06ca4c2 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Öge kaldırıldı", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, "labelPrinting": "Etiket Yazdırma", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Kayıp", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Üretici Parça Numarası", "@manufacturerPartNumber": {}, "manufacturer": "Üretici", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Proje Kodu", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 9a9414b..58a6fb5 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Item has been removed", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, "labelPrinting": "Label Printing", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Lost", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Manufacturer Part Number", "@manufacturerPartNumber": {}, "manufacturer": "Manufacturer", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Project Code", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index f6cd79e..46627d0 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "Hàng hóa đã bị xóa", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "Từ khóa", "@keywords": {}, "labelPrinting": "In nhãn mã vạch", @@ -462,6 +464,10 @@ "@link": {}, "lost": "Mất", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Mã số nhà sản xuất", "@manufacturerPartNumber": {}, "manufacturer": "Nhà sản xuất", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "Mã dự án", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 036a561..68abff9 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "项目已移除", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "关键词", "@keywords": {}, "labelPrinting": "打印标签", @@ -462,6 +464,10 @@ "@link": {}, "lost": "丢失", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "制造商零件号", "@manufacturerPartNumber": {}, "manufacturer": "制造商", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "项目编码", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 521d6a4..d79d2b7 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -412,6 +412,8 @@ "@itemInLocation": {}, "itemDeleted": "項目已移除", "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, "keywords": "關鍵字", "@keywords": {}, "labelPrinting": "標籤印製", @@ -462,6 +464,10 @@ "@link": {}, "lost": "丟失", "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, "manufacturerPartNumber": "製造商零件號", "@manufacturerPartNumber": {}, "manufacturer": "製造商", @@ -618,6 +624,10 @@ "@profileTapToCreate": {}, "projectCode": "項目編碼", "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Enable Purchase Orders", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", From 09625c81e257efdf6dd0bfe29ee930190647b402 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 17 Dec 2024 17:36:41 +1100 Subject: [PATCH 626/746] New translations app_en.arb (Turkish) (#580) --- lib/l10n/tr_TR/app_tr_TR.arb | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 06ca4c2..f0e507d 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -44,9 +44,9 @@ "@appSettings": {}, "appSettingsDetails": "Uygulama ayarlarından yapılandır", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Bana Atanmış", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Bana Atanan Emirleri Göster", "@assignedToMeDetail": {}, "attachments": "Ekler", "@attachments": {}, @@ -138,7 +138,7 @@ "@build": {}, "building": "Oluşturma", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Kamera Kontrolcüsü Açılamadı", "@cameraCreationError": {}, "cameraInternal": "Dahili Kamera", "@cameraInternal": {}, @@ -193,9 +193,9 @@ "@customerReference": {}, "damaged": "Hasarlı", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Renk Şeması", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Renk Şeması Seç", "@colorSchemeDetail": {}, "darkMode": "Koyu Tema", "@darkMode": {}, @@ -213,7 +213,7 @@ "@deleteSuccess": {}, "description": "Açıklama", "@description": {}, - "destination": "Destination", + "destination": "Varış Yeri", "@destination": {}, "destroyed": "Yok edildi", "@destroyed": {}, @@ -412,7 +412,7 @@ "@itemInLocation": {}, "itemDeleted": "Öge kaldırıldı", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Ürün Güncellendi", "@itemUpdated": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, @@ -464,9 +464,9 @@ "@link": {}, "lost": "Kayıp", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Parça Üreticisi", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Parça Üreticisini Düzenle", "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Üretici Parça Numarası", "@manufacturerPartNumber": {}, @@ -624,17 +624,17 @@ "@profileTapToCreate": {}, "projectCode": "Proje Kodu", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Tarama Verisini Onayla", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Taranan Ürünlerin Detaylarını Onayla", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Satın Alma Emirlerini Etkinleştir", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Satın Alma Emirlerinin İşlevselliğini Etkinleştir", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Kamera Kısayolu", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Satın alma emirleri ekranında fotoğraf yükleme kısayolunu etkinleştir", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Satınalma Siparişi", "@purchaseOrder": {}, @@ -642,7 +642,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Satın Alma siparişini düzenle", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Satın Alma Emri Ayarları", "@purchaseOrderSettings": {}, "purchaseOrders": "Satınalma Siparişleri", "@purchaseOrders": {}, @@ -750,15 +750,15 @@ "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Satış Emirlerini Etkinleştir", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Satış Siparişlerinin İşlevselliğini Etkinleştir", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Kamera Kısayolu", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Satış emirleri ekranında fotoğraf yükleme kısayolunu etkinleştir", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Satış emirleri ayarları", "@salesOrderSettings": {}, "salesOrderCreate": "Yeni Satış Siparişi", "@saleOrderCreate": {}, @@ -1012,9 +1012,9 @@ "@translate": {}, "translateHelp": "Çeviriye yardım et", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Mevcut Değil", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Ürün Mevcut Değil", "@unavailableDetail": {}, "unitPrice": "Birim Fiyat", "@unitPrice": {}, From ea3410a3daadc0453aa0feb68caf58011a79301a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 17 Dec 2024 17:46:48 +1100 Subject: [PATCH 627/746] Sounds fix (#583) * Prevent notification sounds from pausing external media - Closes https://github.com/inventree/inventree-app/issues/582 * Bump release notes * Bump version number * Update release notes --- assets/release_notes.md | 6 ++++++ lib/helpers.dart | 11 +++++++++++ pubspec.yaml | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 004e115..91c6b49 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.17.2 - December 2024 +--- + +- Prevent notification sounds from pause media playback +- Updated translations + ### 0.17.1 - December 2024 --- diff --git a/lib/helpers.dart b/lib/helpers.dart index 993814f..3a35d73 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -107,6 +107,17 @@ Future playAudioFile(String path) async { } final player = AudioPlayer(); + + // Specify context options for the audio player + // Ref: https://github.com/inventree/inventree-app/issues/582 + player.setAudioContext(AudioContext( + android: AudioContextAndroid( + usageType: AndroidUsageType.notification, + audioFocus: AndroidAudioFocus.none, + ), + iOS: AudioContextIOS() + )); + player.play(AssetSource(path)); } diff --git a/pubspec.yaml b/pubspec.yaml index 84572dd..c9091d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.17.1+93 +version: 0.17.2+94 environment: sdk: ">=2.19.5 <3.13.0" From dc8191c3d880937a18fbe3a34223ccfd30d70199 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Dec 2024 09:50:27 +1100 Subject: [PATCH 628/746] New translations app_en.arb (French) (#585) --- lib/l10n/fr_FR/app_fr_FR.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index e37d07f..3aa4344 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -44,7 +44,7 @@ "@appSettings": {}, "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "", "@assignedToMe": {}, "assignedToMeDetail": "Show orders which are assigned to me", "@assignedToMeDetail": {}, From bc44b99d43a67b7587effce7b69e0fa256a5d6a4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Dec 2024 09:57:13 +1100 Subject: [PATCH 629/746] Label printing fix (#587) * Handle blank URL provided for file download * Improved printing checks * Auto-select the correct printer --- assets/release_notes.md | 1 + lib/api.dart | 7 ++++++- lib/inventree/model.dart | 2 +- lib/labels.dart | 22 +++++++++++++++------- lib/widget/progress.dart | 4 +++- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 91c6b49..3b1237c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.17.2 - December 2024 --- +- Fixed error message when printing a label to a remote machine - Prevent notification sounds from pause media playback - Updated translations diff --git a/lib/api.dart b/lib/api.dart index d686e1b..24e8c1f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -817,6 +817,11 @@ class InvenTreeAPI { */ Future downloadFile(String url, {bool openOnDownload = true}) async { + if (url.isEmpty) { + // No URL provided for download + return; + } + // Find the local downlods directory final Directory dir = await getTemporaryDirectory(); @@ -1538,7 +1543,7 @@ class InvenTreeAPI { return setting.value; } - final response = await InvenTreeGlobalSetting().getModel(key); + final response = await InvenTreeUserSetting().getModel(key); if (response is InvenTreeUserSetting) { response.lastReload = DateTime.now(); diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 2078f86..fc90a2b 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -904,7 +904,7 @@ class InvenTreeUserSetting extends InvenTreeGlobalSetting { @override InvenTreeGlobalSetting createFromJson(Map json) { - return InvenTreeGlobalSetting.fromJson(json); + return InvenTreeUserSetting.fromJson(json); } @override diff --git a/lib/labels.dart b/lib/labels.dart index 1e15bd4..819df71 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -63,7 +63,11 @@ Future selectAndPrintLabel( }); } - if (plugin_options.length == 1) { + String selectedPlugin = await InvenTreeAPI().getUserSetting("LABEL_DEFAULT_PRINTER"); + + if (selectedPlugin.isNotEmpty) { + initial_plugin = selectedPlugin; + } else if (plugin_options.length == 1) { initial_plugin = plugin_options.first["value"]; } @@ -111,27 +115,29 @@ Future selectAndPrintLabel( "items": [instanceId] } ).then((APIResponse response) { - hideLoadingOverlay(); if (response.isValid() && response.statusCode >= 200 && response.statusCode <= 201) { var data = response.asMap(); if (data.containsKey("output")) { - var label_file = (data["output"] ?? "") as String; + String? label_file = (data["output"]) as String?; + + if (label_file != null && label_file.isNotEmpty) { + // Attempt to open generated file + InvenTreeAPI().downloadFile(label_file); + } - // Attempt to open generated file - InvenTreeAPI().downloadFile(label_file); result = true; } } }); - } else { + + } else { // Legacy label printing API // Uses a GET request to a specially formed URL which depends on the parameters String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; await InvenTreeAPI().get(url).then((APIResponse response) { - hideLoadingOverlay(); if (response.isValid() && response.statusCode == 200) { var data = response.asMap(); if (data.containsKey("file")) { @@ -145,6 +151,8 @@ Future selectAndPrintLabel( }); } + hideLoadingOverlay(); + if (result) { showSnackIcon( L10().printLabelSuccess, diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index cc00c85..3deb938 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -66,5 +66,7 @@ void showLoadingOverlay() { void hideLoadingOverlay() { - Loader.hide(); + if (Loader.isShown) { + Loader.hide(); + } } From d84f76d482c599e79b0b4721e62b90f2b5242119 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Dec 2024 10:36:36 +1100 Subject: [PATCH 630/746] Improve error management for label printing (#588) - Handle empty label - Handle empty printer --- lib/api_form.dart | 11 +++++++++++ lib/l10n/app_en.arb | 6 ++++++ lib/labels.dart | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/lib/api_form.dart b/lib/api_form.dart index 7b8cb42..a906d90 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -982,6 +982,7 @@ Future launchApiForm( Map modelData = const {}, String method = "PATCH", Function(Map)? onSuccess, + bool Function(Map)? validate, Function? onCancel, IconData icon = TablerIcons.device_floppy }) async { @@ -1071,6 +1072,7 @@ Future launchApiForm( formFields, method, onSuccess: onSuccess, + validate: validate, fileField: fileField, icon: icon, )) @@ -1088,6 +1090,7 @@ class APIFormWidget extends StatefulWidget { { Key? key, this.onSuccess, + this.validate, this.fileField = "", this.icon = TablerIcons.device_floppy, } @@ -1111,6 +1114,8 @@ class APIFormWidget extends StatefulWidget { final Function(Map)? onSuccess; + final bool Function(Map)? validate; + @override _APIFormWidgetState createState() => _APIFormWidgetState(); @@ -1401,6 +1406,12 @@ class _APIFormWidgetState extends State { } } } + + final bool isValid = widget.validate?.call(data) ?? true; + + if (!isValid) { + return; + } // Run custom onSuccess function var successFunc = widget.onSuccess; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ef3b9d9..8ea01ad 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -623,6 +623,12 @@ "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "language": "Language", "@language": {}, diff --git a/lib/labels.dart b/lib/labels.dart index 819df71..ca145e9 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -94,6 +94,28 @@ Future selectAndPrintLabel( "", fields, icon: TablerIcons.printer, + validate: (Map data) { + final template = data["label"]; + final plugin = data["plugin"]; + + if (template == null) { + showSnackIcon( + L10().labelSelectTemplate, + success: false, + ); + return false; + } + + if (plugin == null) { + showSnackIcon( + L10().labelSelectPrinter, + success: false, + ); + return false; + } + + return true; + }, onSuccess: (Map data) async { int labelId = (data["label"] ?? -1) as int; var pluginKey = data["plugin"]; From aac13ed5d6ddcedec4d9b622065ff73f6408c8c2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Dec 2024 22:25:55 +1100 Subject: [PATCH 631/746] Stock expiry (#590) * Add stock expiry getters * refactor date getters * Display expiry information * Update release notes * Remove unused import --- assets/release_notes.md | 1 + lib/api.dart | 4 +- lib/inventree/model.dart | 25 +++++++++++ lib/inventree/stock.dart | 69 +++++++----------------------- lib/l10n/app_en.arb | 9 ++++ lib/widget/stock/stock_detail.dart | 23 ++++++++++ 6 files changed, 75 insertions(+), 56 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3b1237c..2f83b6d 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Fixed error message when printing a label to a remote machine - Prevent notification sounds from pause media playback +- Display stock expiry information - Updated translations ### 0.17.1 - December 2024 diff --git a/lib/api.dart b/lib/api.dart index 24e8c1f..549b000 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1532,7 +1532,7 @@ class InvenTreeAPI { // Return a boolean global setting value Future getGlobalBooleanSetting(String key) async { String value = await getGlobalSetting(key); - return value.toLowerCase() == "true"; + return value.toLowerCase().trim() == "true"; } Future getUserSetting(String key) async { @@ -1557,7 +1557,7 @@ class InvenTreeAPI { // Return a boolean user setting value Future getUserBooleanSetting(String key) async { String value = await getUserSetting(key); - return value.toLowerCase() == "true"; + return value.toLowerCase().trim() == "true"; } /* diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index fc90a2b..0804699 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -3,6 +3,7 @@ import "dart:io"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter/material.dart"; +import "package:intl/intl.dart"; import "package:inventree/widget/snacks.dart"; import "package:url_launcher/url_launcher.dart"; import "package:path/path.dart" as path; @@ -156,6 +157,30 @@ class InvenTreeModel { return value.toString().toLowerCase() == "true"; } + // Helper function to get date value from json data + DateTime? getDate(String key, {DateTime? backup, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + return DateTime.tryParse(value as String); + } + + // Helper function to get date as a string + String getDateString(String key, {DateTime? backup, String subKey = ""}) { + DateTime? dt = getDate(key, backup: backup, subKey: subKey); + + if (dt == null) { + return ""; + } + + final DateFormat fmt = DateFormat("yyyy-MM-dd"); + + return fmt.format(dt); + } + // Return the InvenTree web server URL for this object String get webUrl { diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 1ae5e7f..baa328a 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -1,7 +1,5 @@ import "dart:async"; -import "package:intl/intl.dart"; - import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; @@ -107,23 +105,9 @@ class InvenTreeStockItemHistory extends InvenTreeModel { }; } - DateTime? get date { - if (jsondata.containsKey("date")) { - return DateTime.tryParse((jsondata["date"] ?? "") as String); - } else { - return null; - } - } + DateTime? get date => getDate("date"); - String get dateString { - var d = date; - - if (d == null) { - return ""; - } - - return DateFormat("yyyy-MM-dd").format(d); - } + String get dateString => getDateString("date"); String get label => getString("label"); @@ -258,6 +242,7 @@ class InvenTreeStockItem extends InvenTreeModel { "part_detail": "true", "location_detail": "true", "supplier_detail": "true", + "supplier_part_detail": "true", "cascade": "false" }; } @@ -347,46 +332,22 @@ class InvenTreeStockItem extends InvenTreeModel { bool get hasCustomer => customerId > 0; + bool get stale => getBool("stale"); + + bool get expired => getBool("expired"); + + DateTime? get expiryDate => getDate("expiry_date"); + + String get expiryDateString => getDateString("expiry_date"); + // Date of last update - DateTime? get updatedDate { - if (jsondata.containsKey("updated")) { - return DateTime.tryParse((jsondata["updated"] ?? "") as String); - } else { - return null; - } - } + DateTime? get updatedDate => getDate("updated"); - String get updatedDateString { - var _updated = updatedDate; + String get updatedDateString => getDateString("updated"); - if (_updated == null) { - return ""; - } + DateTime? get stocktakeDate => getDate("stocktake_date"); - final DateFormat _format = DateFormat("yyyy-MM-dd"); - - return _format.format(_updated); - } - - DateTime? get stocktakeDate { - if (jsondata.containsKey("stocktake_date")) { - return DateTime.tryParse((jsondata["stocktake_date"] ?? "") as String); - } else { - return null; - } - } - - String get stocktakeDateString { - var _stocktake = stocktakeDate; - - if (_stocktake == null) { - return ""; - } - - final DateFormat _format = DateFormat("yyyy-MM-dd"); - - return _format.format(_stocktake); - } + String get stocktakeDateString => getDateString("stocktake_date"); String get partName { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8ea01ad..3fef1f3 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -399,6 +399,15 @@ "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + + "expiryExpired": "Expired", + "@expiryExpired": {}, + + "expiryStale": "Stale", + "@expiryStale": {}, + "feedback": "Feedback", "@feedback": {}, diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 1b21598..1390637 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -53,6 +53,7 @@ class _StockItemDisplayState extends RefreshableState { bool stockShowHistory = false; bool stockShowTests = true; + bool expiryEnabled = false; // Linked data fields InvenTreePart? part; @@ -231,6 +232,8 @@ class _StockItemDisplayState extends RefreshableState { Navigator.of(context).pop(); } + expiryEnabled = await api.getGlobalBooleanSetting("STOCK_ENABLE_EXPIRY"); + // Request part information part = await InvenTreePart().get(widget.item.partId) as InvenTreePart?; @@ -731,6 +734,26 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (expiryEnabled && widget.item.expiryDate != null) { + + Widget? _expiryIcon; + + if (widget.item.stale) { + _expiryIcon = Text(L10().expiryStale, style: TextStyle(color: COLOR_WARNING)); + } else if (widget.item.expired) { + _expiryIcon = Text(L10().expiryExpired, style: TextStyle(color: COLOR_DANGER)); + } + + tiles.add( + ListTile( + title: Text(L10().expiryDate), + subtitle: Text(widget.item.expiryDateString), + leading: Icon(TablerIcons.calendar_x), + trailing: _expiryIcon, + ) + ); + } + // Last update? if (widget.item.updatedDateString.isNotEmpty) { From 1a5992042abe3a45a14eafcc721aa3f421ba7603 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Dec 2024 23:16:07 +1100 Subject: [PATCH 632/746] New Crowdin updates (#589) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++++ lib/l10n/da_DK/app_da_DK.arb | 4 ++++ lib/l10n/de_DE/app_de_DE.arb | 4 ++++ lib/l10n/el_GR/app_el_GR.arb | 4 ++++ lib/l10n/es_ES/app_es_ES.arb | 4 ++++ lib/l10n/es_MX/app_es_MX.arb | 4 ++++ lib/l10n/et_EE/app_et_EE.arb | 4 ++++ lib/l10n/fa_IR/app_fa_IR.arb | 4 ++++ lib/l10n/fi_FI/app_fi_FI.arb | 4 ++++ lib/l10n/fr_FR/app_fr_FR.arb | 16 ++++++++++------ lib/l10n/he_IL/app_he_IL.arb | 4 ++++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++++ lib/l10n/id_ID/app_id_ID.arb | 4 ++++ lib/l10n/it_IT/app_it_IT.arb | 4 ++++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++++ lib/l10n/nl_NL/app_nl_NL.arb | 4 ++++ lib/l10n/no_NO/app_no_NO.arb | 4 ++++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++++ lib/l10n/pt_PT/app_pt_PT.arb | 4 ++++ lib/l10n/ro_RO/app_ro_RO.arb | 4 ++++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++++ lib/l10n/th_TH/app_th_TH.arb | 4 ++++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++++ lib/l10n/zh_CN/app_zh_CN.arb | 4 ++++ lib/l10n/zh_TW/app_zh_TW.arb | 4 ++++ 38 files changed, 158 insertions(+), 6 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index e7a552a..9049152 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index ef04695..aad1483 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 5d834e2..93c5a79 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Šablona štítku", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Jazyk", "@language": {}, "languageDefault": "Výchozí jazyk systému", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index ff8f2a6..68596e8 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 674b590..4994ce9 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Vorlage", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Sprache", "@language": {}, "languageDefault": "Standard-Systemsprache", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 795db0b..01893f8 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 92a4719..222c7ba 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Plantilla de etiqueta", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Idioma", "@language": {}, "languageDefault": "Idioma predeterminado del sistema", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 75061b7..d16f9d4 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Plantilla de etiqueta", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Idioma", "@language": {}, "languageDefault": "Idioma por defecto del sistema", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 0812912..a939b32 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Keel", "@language": {}, "languageDefault": "Süsteemi vaikimisi keel", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 06daf85..0f643f3 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 70c13c1..e20fbb5 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Kieli", "@language": {}, "languageDefault": "Järjestelmän oletuskieli", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 3aa4344..c371487 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -44,7 +44,7 @@ "@appSettings": {}, "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "", + "assignedToMe": "Mes assignations", "@assignedToMe": {}, "assignedToMeDetail": "Show orders which are assigned to me", "@assignedToMeDetail": {}, @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Modèle d'étiquette", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Langue", "@language": {}, "languageDefault": "Langue par défaut du système", @@ -632,7 +636,7 @@ "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Raccourcie caméra", "@purchaseOrderShowCamera": {}, "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", "@purchaseOrderShowCameraDetail": {}, @@ -642,7 +646,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Modifier la commande d'achat", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Paramètres des demandes d'achats", "@purchaseOrderSettings": {}, "purchaseOrders": "Commandes d'achat", "@purchaseOrders": {}, @@ -750,11 +754,11 @@ "@salesOrder": {}, "salesOrders": "Ventes", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Activer les demandes de ventes", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Activer la fonctionnalité des demandes de ventes", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Raccourcie caméra", "@salesOrderShowCamera": {}, "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", "@salesOrderShowCameraDetail": {}, diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 72bf6b4..45c77e9 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "תבנית תווית", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "שפה", "@language": {}, "languageDefault": "שפת מערכת ברירת מחדל", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 7015356..85c544a 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index d3f1728..19fc74c 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Címke sablon", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Nyelv", "@language": {}, "languageDefault": "Alapértelmezett nyelv", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index a45667a..211bb96 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Bahasa", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 98adb2c..269704f 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Modello Etichetta", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Lingua", "@language": {}, "languageDefault": "Lingua di sistema predefinita", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 4e74987..9acd329 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "言語設定", "@language": {}, "languageDefault": "システムのデフォルト言語", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 7a60a68..cb99ad6 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 05542aa..5aa3b16 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 12e845e..be51740 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 981bdf6..454bfb6 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Taal", "@language": {}, "languageDefault": "Standaard systeemtaal", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 6d2758f..d747e96 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Etikettmal", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Språk", "@language": {}, "languageDefault": "Standard systemspråk", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 78e8944..604d6fb 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Szablon etykiety", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Język", "@language": {}, "languageDefault": "Domyślny język systemu", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 03a4b9e..576d6ac 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Modelo de descricao", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Idioma", "@language": {}, "languageDefault": "Idioma padrão do sistema", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 1f9e022..3fa2c02 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index e8fc048..b392b49 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Sablon eticheta", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Limba", "@language": {}, "languageDefault": "Limba de sistem implicită", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 3b3bf2b..94e18eb 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Шаблон этикетки", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Язык", "@language": {}, "languageDefault": "Язык системы по умолчанию", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 6de91f9..1df84aa 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 7759628..55fa14d 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index f0df4cb..c5d689c 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 78963ad..dacfd48 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Etikettmall", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Språk", "@language": {}, "languageDefault": "Standard systemspråk", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index bfc0c5a..9bd5965 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index f0e507d..63e1848 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Etiket Şablonu", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Dil", "@language": {}, "languageDefault": "Varsayılan sistem dili", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 58a6fb5..77fafd6 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Label Template", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Language", "@language": {}, "languageDefault": "Default system language", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 46627d0..c75b729 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "Khuôn mẫu nhãn tem", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "Ngôn ngữ", "@language": {}, "languageDefault": "Ngôn ngữ hệ thống mặc định", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 68abff9..ee23c67 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "标签模板", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "语言", "@language": {}, "languageDefault": "系统默认语言", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index d79d2b7..124feeb 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -422,6 +422,10 @@ "@labelPrintingDetail": {}, "labelTemplate": "標籤模板", "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, "language": "語言", "@language": {}, "languageDefault": "系統默認語言", From f5e3b4ac80fd58a4646f171a1f07b33bca4743b5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 24 Dec 2024 01:05:59 +1100 Subject: [PATCH 633/746] Fix order of operations (#591) --- lib/widget/stock/stock_detail.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 1390637..50331f2 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -738,19 +738,19 @@ class _StockItemDisplayState extends RefreshableState { Widget? _expiryIcon; - if (widget.item.stale) { - _expiryIcon = Text(L10().expiryStale, style: TextStyle(color: COLOR_WARNING)); - } else if (widget.item.expired) { + if (widget.item.expired) { _expiryIcon = Text(L10().expiryExpired, style: TextStyle(color: COLOR_DANGER)); + } else if (widget.item.stale) { + _expiryIcon = Text(L10().expiryStale, style: TextStyle(color: COLOR_WARNING)); } tiles.add( - ListTile( - title: Text(L10().expiryDate), - subtitle: Text(widget.item.expiryDateString), - leading: Icon(TablerIcons.calendar_x), - trailing: _expiryIcon, - ) + ListTile( + title: Text(L10().expiryDate), + subtitle: Text(widget.item.expiryDateString), + leading: Icon(TablerIcons.calendar_x), + trailing: _expiryIcon, + ) ); } From 562cbffb1845c62cdf829740e2f59507abccd44f Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 24 Dec 2024 10:58:21 +1100 Subject: [PATCH 634/746] New Crowdin updates (#592) * New translations app_en.arb (Italian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Dutch) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 6 ++++++ lib/l10n/bg_BG/app_bg_BG.arb | 6 ++++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 6 ++++++ lib/l10n/da_DK/app_da_DK.arb | 6 ++++++ lib/l10n/de_DE/app_de_DE.arb | 6 ++++++ lib/l10n/el_GR/app_el_GR.arb | 6 ++++++ lib/l10n/es_ES/app_es_ES.arb | 6 ++++++ lib/l10n/es_MX/app_es_MX.arb | 6 ++++++ lib/l10n/et_EE/app_et_EE.arb | 6 ++++++ lib/l10n/fa_IR/app_fa_IR.arb | 6 ++++++ lib/l10n/fi_FI/app_fi_FI.arb | 6 ++++++ lib/l10n/fr_FR/app_fr_FR.arb | 6 ++++++ lib/l10n/he_IL/app_he_IL.arb | 6 ++++++ lib/l10n/hi_IN/app_hi_IN.arb | 6 ++++++ lib/l10n/hu_HU/app_hu_HU.arb | 6 ++++++ lib/l10n/id_ID/app_id_ID.arb | 6 ++++++ lib/l10n/it_IT/app_it_IT.arb | 6 ++++++ lib/l10n/ja_JP/app_ja_JP.arb | 6 ++++++ lib/l10n/ko_KR/app_ko_KR.arb | 6 ++++++ lib/l10n/lt_LT/app_lt_LT.arb | 6 ++++++ lib/l10n/lv_LV/app_lv_LV.arb | 6 ++++++ lib/l10n/nl_NL/app_nl_NL.arb | 6 ++++++ lib/l10n/no_NO/app_no_NO.arb | 6 ++++++ lib/l10n/pl_PL/app_pl_PL.arb | 6 ++++++ lib/l10n/pt_BR/app_pt_BR.arb | 6 ++++++ lib/l10n/pt_PT/app_pt_PT.arb | 6 ++++++ lib/l10n/ro_RO/app_ro_RO.arb | 6 ++++++ lib/l10n/ru_RU/app_ru_RU.arb | 6 ++++++ lib/l10n/sk_SK/app_sk_SK.arb | 6 ++++++ lib/l10n/sl_SI/app_sl_SI.arb | 6 ++++++ lib/l10n/sr_CS/app_sr_CS.arb | 6 ++++++ lib/l10n/sv_SE/app_sv_SE.arb | 6 ++++++ lib/l10n/th_TH/app_th_TH.arb | 6 ++++++ lib/l10n/tr_TR/app_tr_TR.arb | 6 ++++++ lib/l10n/uk_UA/app_uk_UA.arb | 6 ++++++ lib/l10n/vi_VN/app_vi_VN.arb | 6 ++++++ lib/l10n/zh_CN/app_zh_CN.arb | 6 ++++++ lib/l10n/zh_TW/app_zh_TW.arb | 6 ++++++ 38 files changed, 228 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 9049152..462bd99 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index aad1483..972a58c 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 93c5a79..6f43cec 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Nahrát anonymní chybová hlášení a protokoly chyb", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Komentář", "@feedback": {}, "feedbackError": "Chyba při odesílání komentáře", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 68596e8..0726488 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 4994ce9..ea5e919 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Fehler beim Senden des Feedbacks", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 01893f8..29cb84a 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 222c7ba..fe88c1c 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Subir reportes de error anónimos y registros de errores", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Comentarios", "@feedback": {}, "feedbackError": "Error al enviar comentarios", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index d16f9d4..03d87e7 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Subir informes de errores anónimos y registros de errores", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Comentarios", "@feedback": {}, "feedbackError": "Error al enviar comentarios", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index a939b32..d7c10c9 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Tagasiside", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 0f643f3..f2f9720 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index e20fbb5..4016b74 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Lähetä nimettömät virheilmoitukset ja kaatumislokit", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Palaute", "@feedback": {}, "feedbackError": "Palautetta lähetettäessä tapahtui virhe", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index c371487..5918ea0 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Donner votre avis", "@feedback": {}, "feedbackError": "Erreur lors de l'envoi du commentaire", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 45c77e9..720b101 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "העלאת דוחות שגיאה אנונימיים ויומני קריסה", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "משוב", "@feedback": {}, "feedbackError": "שגיאה בהגשת משוב", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 85c544a..61c724d 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 19fc74c..0496f88 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Visszajelzés", "@feedback": {}, "feedbackError": "Visszajelzés küldése sikertelen", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 211bb96..d5458f2 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Unggah laporan kesalahan anonim dan log kerusakan", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Umpan Balik", "@feedback": {}, "feedbackError": "Kesalahan saat mengirimkan umpan balik", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 269704f..cd8bf46 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Carica i report degli errori anonimi e i crash log", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Commenti e suggerimenti", "@feedback": {}, "feedbackError": "Errore nell'invio del feedback", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 9acd329..c40ad51 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "フィードバック", "@feedback": {}, "feedbackError": "フィードバックの送信エラー", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index cb99ad6..a26d97d 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 5aa3b16..08fedf9 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index be51740..3ff9f77 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 454bfb6..6c344c2 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonieme foutrapporten en crashlogs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Fout bij indienen feedback", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index d747e96..a00484e 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Last opp anonyme feilrapporter og krasjlogger", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Tilbakemelding", "@feedback": {}, "feedbackError": "Feil ved innsending av tilbakemelding", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 604d6fb..9eeaa07 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Opinie", "@feedback": {}, "feedbackError": "Błąd dodawania opinii", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 576d6ac..b0df67f 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Enviar relatórios de erros anônimos e logs de falhas", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Erro ao enviar o feedback", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 3fa2c02..a812526 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Enviar relatórios de erros e registos anónimos", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Comentários", "@feedback": {}, "feedbackError": "Erro ao enviar comentário", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index b392b49..029b4dc 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Încarcă rapoarte anonime de erori și jurnale de eroare", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Eroare la trimiterea feedback-ului", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 94e18eb..4a7f142 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Загружать анонимные отчеты об ошибках и журналы сбоев", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Обратная Связь", "@feedback": {}, "feedbackError": "Ошибка отправки отзыва", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 1df84aa..a02f315 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 55fa14d..7a699e4 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index c5d689c..e9b0163 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index dacfd48..b896616 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Ladda upp anonyma felrapporter och kraschloggar", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Det gick inte att skicka feedback", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 9bd5965..3c47cf6 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Upload anonymous error reports and crash logs", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 63e1848..b95a98d 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Anonim olarak hata ve log yükle", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Geri Bildirim", "@feedback": {}, "feedbackError": "Geribildirim gönderme hatası", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 77fafd6..3100235 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Вивантажувати анонімні звіти про помилки та журнали помилок", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Feedback", "@feedback": {}, "feedbackError": "Error submitting feedback", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index c75b729..ba4c2db 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Tải lên nhật ký bị treo hệ thống và báo cáo lỗi nặc danh", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "Phản hồi", "@feedback": {}, "feedbackError": "Lỗi gửi phản hồi", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index ee23c67..cc0a6d9 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "上传匿名错误报告和崩溃日志", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "意见反馈", "@feedback": {}, "feedbackError": "提交反馈时出现了一个错误", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 124feeb..719c59c 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -273,6 +273,12 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "上傳匿名錯誤報告和崩潰日誌", "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, "feedback": "回饋", "@feedback": {}, "feedbackError": "提交反饋時出現了一個錯誤", From d97e4bc01072b8cbacb6882f1dbf6239d1010642 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 10 Jan 2025 12:24:33 +1100 Subject: [PATCH 635/746] Remove out-dated permissions (#594) * Remove out-dated permissions * Fix github action --- .github/workflows/ci.yaml | 1 + android/app/src/main/AndroidManifest.xml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f5e5bcf..69e8310 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,6 +10,7 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INVENTREE_SITE_URL: http://localhost:8000 INVENTREE_DB_ENGINE: django.db.backends.sqlite3 INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3 INVENTREE_MEDIA_ROOT: ../test_inventree_media diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c852e9e..3bf7ae2 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -51,8 +51,6 @@ - - diff --git a/android/gradle.properties b/android/gradle.properties index ce4fa01..f2b745e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -2,7 +2,7 @@ org.gradle.daemon=true org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4096M android.enableD8=true android.enableJetifier=true android.useAndroidX=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 829e1a5..3bfe7cf 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip -networkTimeout=10000 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip +networkTimeout=30000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/settings.gradle b/android/settings.gradle index 16ce359..eb1096e 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.4.1" apply false - id "org.jetbrains.kotlin.android" version "1.8.10" apply false + id "com.android.application" version "8.6.0" apply false + id "org.jetbrains.kotlin.android" version "1.9.25" apply false } include ":app" \ No newline at end of file diff --git a/assets/release_notes.md b/assets/release_notes.md index 045ce4c..f8405aa 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,7 @@ +### 0.19.0 - June 2025 +--- +- Replace barcode scanning library for better performance + ### 0.18.1 - April 2025 --- - Fix bug associated with handling invalid URLs diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 0000000..a88caf9 --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 0000000..e3ba6fb --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index ece027c..7e44de5 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -3,14 +3,15 @@ import "dart:typed_data"; import "package:camera/camera.dart"; import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/snacks.dart"; +import "package:mobile_scanner/mobile_scanner.dart"; import "package:one_context/one_context.dart"; import "package:wakelock_plus/wakelock_plus.dart"; -import "package:flutter_zxing/flutter_zxing.dart"; import "package:inventree/l10.dart"; @@ -37,9 +38,14 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { int scan_delay = 500; bool single_scanning = false; bool scanning_paused = false; + bool multiple_barcodes = false; String scanned_code = ""; + final MobileScannerController controller = MobileScannerController( + autoZoom: true + ); + @override void initState() { super.initState(); @@ -74,6 +80,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future pauseScan() async { + if (mounted) { setState(() { scanning_paused = true; @@ -83,6 +90,9 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future resumeScan() async { + + controller.start(); + if (mounted) { setState(() { scanning_paused = false; @@ -93,46 +103,71 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { /* * Callback function when a barcode is scanned */ - Future onScanSuccess(Code? code) async { - - if (scanning_paused) { + Future onScanSuccess(BarcodeCapture result) async { + if (!mounted || scanning_paused) { return; } - Uint8List raw_data = code?.rawBytes ?? Uint8List(0); + // TODO: Display outline of barcodes on the screen? + + if (result.barcodes.isEmpty) { + setState(() { + multiple_barcodes = false; + }); + } + else if (result.barcodes.length > 1) { + setState(() { + multiple_barcodes = true; + }); + return; + } else { + setState(() { + multiple_barcodes = false; + }); + } + + Uint8List rawData = result.barcodes.first.rawBytes ?? Uint8List(0); - // Reconstruct barcode from raw data String barcode; - if (raw_data.isNotEmpty) { - barcode = ""; - + if (rawData.isNotEmpty) { final buffer = StringBuffer(); - for (int i = 0; i < raw_data.length; i++) { - buffer.writeCharCode(raw_data[i]); + for (int ii = 0; ii < rawData.length; ii++) { + buffer.writeCharCode(rawData[ii]); } barcode = buffer.toString(); + print(barcode); } else { - barcode = code?.text ?? ""; + // Fall back to text value + barcode = result.barcodes.first.rawValue ?? ""; } + if (barcode.isEmpty) { + // TODO: Error message "empty barcode" + return; + } + + setState(() { + scanned_code = barcode; + }); + + pauseScan(); + + await handleBarcodeData(barcode).then((_) { + if (!single_scanning && mounted) { + resumeScan(); + } + }); + + resumeScan(); + if (mounted) { setState(() { - scanned_code = barcode; - }); - } - - if (barcode.isNotEmpty) { - - pauseScan(); - - await handleBarcodeData(barcode).then((_) { - if (!single_scanning && mounted) { - resumeScan(); - } + scanned_code = ""; + multiple_barcodes = false; }); } } @@ -159,22 +194,40 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { } } - /* - * Build the barcode scanner overlay - */ - FixedScannerOverlay BarcodeOverlay(BuildContext context) { + Widget BarcodeOverlay(BuildContext context) { - // Note: Copied from reader_widget.dart:ReaderWidget.build - final Size size = MediaQuery.of(context).size; - final double cropSize = min(size.width, size.height) * 0.5; + final Size screenSize = MediaQuery.of(context).size; + final double width = screenSize.width; + final double height = screenSize.height; - return FixedScannerOverlay( - borderColor: scanning_paused ? COLOR_WARNING : COLOR_ACTION, - overlayColor: Colors.black45, - borderRadius: 1, - borderLength: 15, - borderWidth: 8, - cutOutSize: cropSize, + final double D = min(width, height) * 0.8; + + // Color for the barcode scan? + Color overlayColor = COLOR_ACTION; + + if (multiple_barcodes) { + overlayColor = COLOR_DANGER; + } else if (scanned_code.isNotEmpty) { + overlayColor = COLOR_SUCCESS; + } else if (scanning_paused) { + overlayColor = COLOR_WARNING; + } + + return Stack( + children: [ + Center( + child: Container( + width: D, + height: D, + decoration: BoxDecoration( + border: Border.all( + color: overlayColor, + width: 4, + ), + ), + ) + ) + ] ); } @@ -183,24 +236,25 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { */ Widget BarcodeReader(BuildContext context) { - return ReaderWidget( - onScan: onScanSuccess, - isMultiScan: false, - tryHarder: true, - tryInverted: true, - tryRotate: true, - showGallery: false, - onControllerCreated: onControllerCreated, - scanDelay: Duration(milliseconds: scan_delay), - resolution: ResolutionPreset.high, - lensDirection: CameraLensDirection.back, - flashOnIcon: const Icon(Icons.flash_on), - flashOffIcon: const Icon(Icons.flash_off), - toggleCameraIcon: const Icon(TablerIcons.camera_rotate), - actionButtonsBackgroundBorderRadius: - BorderRadius.circular(40), - scannerOverlay: BarcodeOverlay(context), - actionButtonsBackgroundColor: Colors.black.withOpacity(0.7), + final Size screenSize = MediaQuery.of(context).size; + final double width = screenSize.width; + final double height = screenSize.height; + + final double D = min(width, height) * 0.8; + + return MobileScanner( + controller: controller, + overlayBuilder: (context, constraints) { + return BarcodeOverlay(context); + }, + scanWindow: Rect.fromCenter( + center: Offset(width / 2, height / 2), + width: D, + height: D + ), + onDetect: (result) { + onScanSuccess(result); + }, ); } @@ -262,33 +316,33 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { ); } + Widget? buildActions(BuildContext context) { - /* - * Display an overlay at the bottom right of the screen - */ - Widget bottomRightOverlay() { - return SafeArea( - child: Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: EdgeInsets.all(10), - child: ClipRRect( - borderRadius: BorderRadius.circular(40), - child: ColoredBox( - color: Colors.black45, - child: Row( - mainAxisSize: MainAxisSize.min, - children: scanning_paused ? [] : [ - CircularProgressIndicator( - value: null - ) - // actionIcon, - ] - ) - ) - ) - ) - ) + List actions = [ + SpeedDialChild( + child: Icon(flash_status ? TablerIcons.bulb_off : TablerIcons.bulb), + label: L10().toggleTorch, + onTap: () async { + controller.toggleTorch(); + if (mounted) { + setState(() { + flash_status = !flash_status; + }); + } + } + ), + SpeedDialChild( + child: Icon(TablerIcons.camera), + label: L10().switchCamera, + onTap: () async { + controller.switchCamera(); + } + ) + ]; + + return SpeedDial( + icon: Icons.more_horiz, + children: actions, ); } @@ -300,11 +354,15 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { backgroundColor: COLOR_APP_BAR, title: Text(L10().scanBarcode), ), + floatingActionButton: buildActions(context), body: GestureDetector( onTap: () async { - setState(() { - scanning_paused = !scanning_paused; - }); + if (mounted) { + setState(() { + // Toggle the 'scan paused' state + scanning_paused = !scanning_paused; + }); + } }, child: Stack( children: [ @@ -316,8 +374,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { ], ), topCenterOverlay(), - bottomCenterOverlay(), - bottomRightOverlay(), + bottomCenterOverlay() ], ), ), diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart index 1c553e1..b3147e5 100644 --- a/lib/barcode/wedge_controller.dart +++ b/lib/barcode/wedge_controller.dart @@ -105,7 +105,7 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { backgroundColor: COLOR_APP_BAR, title: Text(L10().scanBarcode), ), - backgroundColor: Colors.black.withOpacity(0.9), + backgroundColor: Colors.black.withValues(alpha: 0.9), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/l10.dart b/lib/l10.dart index f5f6eec..76a7558 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -1,5 +1,5 @@ -import "package:flutter_gen/gen_l10n/app_localizations.dart"; -import "package:flutter_gen/gen_l10n/app_localizations_en.dart"; +import "package:inventree/l10n/collected/app_localizations.dart"; +import "package:inventree/l10n/collected/app_localizations_en.dart"; import "package:one_context/one_context.dart"; import "package:flutter/material.dart"; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 683812b..0915a4f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1446,6 +1446,9 @@ "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "takePicture": "Take Picture", "@takePicture": {}, @@ -1492,6 +1495,9 @@ "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", "@tokenError": {}, diff --git a/lib/main.dart b/lib/main.dart index 545c8cd..e1ea41a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,17 +4,17 @@ import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:adaptive_theme/adaptive_theme.dart"; -import "package:flutter_gen/gen_l10n/app_localizations.dart"; import "package:flutter_localizations/flutter_localizations.dart"; import "package:flutter_localized_locales/flutter_localized_locales.dart"; import "package:one_context/one_context.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:sentry_flutter/sentry_flutter.dart"; - import "package:inventree/dsn.dart"; + import "package:inventree/preferences.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/l10n/supported_locales.dart"; +import "package:inventree/l10n/collected/app_localizations.dart"; import "package:inventree/settings/release.dart"; import "package:inventree/widget/home.dart"; diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 36eb3a8..f7a8404 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -362,7 +362,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr Spacer(), Image.asset( "assets/image/logo_transparent.png", - color: Colors.white.withOpacity(0.05), + color: Colors.white.withValues(alpha: 0.05), colorBlendMode: BlendMode.modulate, scale: 0.5, ), diff --git a/pubspec.lock b/pubspec.lock index 582ddd5..002a6e3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,15 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f url: "https://pub.dev" source: hosted - version: "72.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" + version: "82.0.0" adaptive_theme: dependency: "direct main" description: @@ -26,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "7.4.5" archive: dependency: transitive description: @@ -50,10 +45,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" audioplayers: dependency: "direct main" description: @@ -122,10 +117,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" cached_network_image: dependency: "direct main" description: @@ -154,34 +149,34 @@ packages: dependency: "direct main" description: name: camera - sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8 + sha256: "413d2b34fe28496c35c69ede5b232fb9dd5ca2c3a4cb606b14efc1c7546cc8cb" url: "https://pub.dev" source: hosted - version: "0.10.6" - camera_android: + version: "0.11.1" + camera_android_camerax: dependency: transitive description: - name: camera_android - sha256: "32f04948a284b71d938fe275616faf4957d07f9b3aab8021bfc8c418301a289e" + name: camera_android_camerax + sha256: "0bd3d1645df00af2540a22df13ba466ac5fb2838a09bce4089cecdb1712a9e94" url: "https://pub.dev" source: hosted - version: "0.10.9+11" + version: "0.6.18" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "7c28969a975a7eb2349bc2cb2dfe3ad218a33dba9968ecfb181ce08c87486655" + sha256: fdc0e668f65c8ddfb3be6c10ef4737fb6274cd04d8053a9525d410642f7989c0 url: "https://pub.dev" source: hosted - version: "0.9.17+3" + version: "0.9.19+1" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 + sha256: "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.10.0" camera_web: dependency: transitive description: @@ -194,10 +189,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -206,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" cli_util: dependency: transitive description: @@ -218,18 +221,18 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: transitive description: @@ -242,10 +245,10 @@ packages: dependency: transitive description: name: coverage - sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5 + sha256: "4b8701e48a58f7712492c9b1f7ba0bb9d525644dd66d023b62e1fc8cdb560c8a" url: "https://pub.dev" source: hosted - version: "1.9.2" + version: "1.14.0" cross_file: dependency: transitive description: @@ -274,10 +277,10 @@ packages: dependency: "direct main" description: name: currency_formatter - sha256: "8d4e1762e226289e4abe902075d167029617553c913309b34a227c52c61dd063" + sha256: c2a32f8ab74649fa8df22e6d2e0288fdcddd733655bb95ccbabbf181e98f280a url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" datetime_picker_formfield: dependency: "direct main" description: @@ -290,10 +293,10 @@ packages: dependency: transitive description: name: dbus - sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.11" device_info_plus: dependency: "direct main" description: @@ -322,10 +325,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: @@ -474,14 +477,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_zxing: - dependency: "direct main" - description: - name: flutter_zxing - sha256: "5b2670f151a6d96643204ff3a781e073739c23a91ef5fc39742bf13fb8287b4c" - url: "https://pub.dev" - source: hosted - version: "1.8.2" frontend_server_client: dependency: transitive description: @@ -502,10 +497,10 @@ packages: dependency: "direct main" description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.4.0" http_multi_server: dependency: transitive description: @@ -606,10 +601,10 @@ packages: dependency: "direct main" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" io: dependency: transitive description: @@ -638,18 +633,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -674,14 +669,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" markdown: dependency: transitive description: @@ -694,10 +681,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -710,10 +697,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mime: dependency: transitive description: @@ -722,6 +709,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + mobile_scanner: + dependency: "direct main" + description: + name: mobile_scanner + sha256: "54005bdea7052d792d35b4fef0f84ec5ddc3a844b250ecd48dc192fb9b4ebc95" + url: "https://pub.dev" + source: hosted + version: "7.0.1" node_preamble: dependency: transitive description: @@ -750,10 +745,10 @@ packages: dependency: "direct main" description: name: open_filex - sha256: dcb7bd3d32db8db5260253a62f1564c02c2c8df64bc0187cd213f65f827519bd + sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900" url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.7.0" package_config: dependency: transitive description: @@ -782,18 +777,18 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: "direct main" description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: @@ -874,6 +869,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" rxdart: dependency: transitive description: @@ -894,18 +897,18 @@ packages: dependency: transitive description: name: sentry - sha256: "033287044a6644a93498969449d57c37907e56f5cedb17b88a3ff20a882261dd" + sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb" url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.14.2" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "3780b5a0bb6afd476857cfbc6c7444d969c29a4d9bd1aa5b6960aa76c65b737a" + sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8" url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.14.2" shared_preferences: dependency: transitive description: @@ -998,7 +1001,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" sliver_tools: dependency: transitive description: @@ -1027,10 +1030,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" sqflite: dependency: transitive description: @@ -1051,18 +1054,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" stream_transform: dependency: transitive description: @@ -1075,10 +1078,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" synchronized: dependency: transitive description: @@ -1091,34 +1094,34 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.15" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.8" typed_data: dependency: transitive description: @@ -1131,10 +1134,10 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_android: dependency: transitive description: @@ -1211,26 +1214,26 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "15.0.0" wakelock_plus: dependency: "direct main" description: name: wakelock_plus - sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 url: "https://pub.dev" source: hosted - version: "1.2.8" + version: "1.3.2" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.3" watcher: dependency: transitive description: @@ -1275,10 +1278,10 @@ packages: dependency: transitive description: name: win32 - sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" url: "https://pub.dev" source: hosted - version: "5.5.4" + version: "5.13.0" win32_registry: dependency: transitive description: @@ -1312,5 +1315,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.5.0 <3.13.0" - flutter: ">=3.24.0" + dart: ">=3.7.0 <3.32.2" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index d5684f0..97e2a98 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,13 +4,13 @@ description: InvenTree stock management version: 0.18.1+98 environment: - sdk: ">=2.19.5 <3.13.0" + sdk: ">=2.19.5 <3.32.2" dependencies: adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) audioplayers: ^6.1.0 # Play audio files cached_network_image: ^3.3.1 # Download and cache remote images - camera: ^0.10.3 # Camera + camera: ^0.11.1 # Camera cupertino_icons: ^1.0.8 currency_formatter: ^2.2.1 # Currency formatting datetime_picker_formfield: ^2.0.1 # Date / time picker @@ -20,27 +20,27 @@ dependencies: flutter: sdk: flutter flutter_cache_manager: ^3.3.0 - flutter_localizations: + flutter_localizations: sdk: flutter - flutter_localized_locales: ^2.0.4 + flutter_localized_locales: ^2.0.5 flutter_markdown: ^0.6.19 # Rendering markdown flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation - flutter_tabler_icons: ^1.35.0 - flutter_zxing: ^1.8.2 # Barcode scanning - http: ^1.2.2 + flutter_tabler_icons: ^1.43.0 + http: ^1.4.0 image_picker: ^1.1.2 # Select or take photos infinite_scroll_pagination: ^4.0.0 # Let the server do all the work! - intl: ^0.19.0 + intl: ^0.20.2 + mobile_scanner: ^7.0.1 # Barcode scanning support one_context: ^4.0.0 # Dialogs without requiring context - open_filex: ^4.6.0 # Open local files + open_filex: ^4.7.0 # Open local files package_info_plus: ^8.1.1 # App information introspection path: ^1.9.0 - path_provider: ^2.1.3 # Local file storage + path_provider: ^2.1.5 # Local file storage sembast: ^3.6.0 # NoSQL data storage - sentry_flutter: 8.9.0 # Error reporting - url_launcher: ^6.3.0 # Open link in system browser - wakelock_plus: ^1.2.8 # Prevent device from sleeping + sentry_flutter: 8.14.2 # Error reporting + url_launcher: ^6.3.1 # Open link in system browser + wakelock_plus: ^1.3.2 # Prevent device from sleeping dev_dependencies: flutter_launcher_icons: ^0.14.1 @@ -60,7 +60,6 @@ flutter_icons: # The following section is specific to Flutter. flutter: uses-material-design: true - generate: true assets: diff --git a/test/fixtures/barcodes/test_sheet.png b/test/fixtures/barcodes/test_sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..026a5a53e1ce2e2fa42cc5fe10ed3a4ecbd1dd34 GIT binary patch literal 903295 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
oSdMzh*hgLdJNM2o$xVPnRNv7^>rP!S(o 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%0D&2CV84k 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

+ +

+ ## Installation You can install the app via the following channels: From 2bb89a96cea239d08d3bc46138345298520dacf4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 25 Jun 2025 18:49:02 +1000 Subject: [PATCH 683/746] New Crowdin updates (#666) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 36 +++++++++-- lib/l10n/bg_BG/app_bg_BG.arb | 36 +++++++++-- lib/l10n/cs_CZ/app_cs_CZ.arb | 36 +++++++++-- lib/l10n/da_DK/app_da_DK.arb | 36 +++++++++-- lib/l10n/de_DE/app_de_DE.arb | 36 +++++++++-- lib/l10n/el_GR/app_el_GR.arb | 36 +++++++++-- lib/l10n/es_ES/app_es_ES.arb | 36 +++++++++-- lib/l10n/es_MX/app_es_MX.arb | 36 +++++++++-- lib/l10n/et_EE/app_et_EE.arb | 36 +++++++++-- lib/l10n/fa_IR/app_fa_IR.arb | 36 +++++++++-- lib/l10n/fi_FI/app_fi_FI.arb | 36 +++++++++-- lib/l10n/fr_FR/app_fr_FR.arb | 42 ++++++++++--- lib/l10n/he_IL/app_he_IL.arb | 36 +++++++++-- lib/l10n/hi_IN/app_hi_IN.arb | 36 +++++++++-- lib/l10n/hu_HU/app_hu_HU.arb | 36 +++++++++-- lib/l10n/id_ID/app_id_ID.arb | 36 +++++++++-- lib/l10n/it_IT/app_it_IT.arb | 36 +++++++++-- lib/l10n/ja_JP/app_ja_JP.arb | 36 +++++++++-- lib/l10n/ko_KR/app_ko_KR.arb | 36 +++++++++-- lib/l10n/lt_LT/app_lt_LT.arb | 36 +++++++++-- lib/l10n/lv_LV/app_lv_LV.arb | 36 +++++++++-- lib/l10n/nl_NL/app_nl_NL.arb | 76 +++++++++++++++------- lib/l10n/no_NO/app_no_NO.arb | 36 +++++++++-- lib/l10n/pl_PL/app_pl_PL.arb | 36 +++++++++-- lib/l10n/pt_BR/app_pt_BR.arb | 36 +++++++++-- lib/l10n/pt_PT/app_pt_PT.arb | 36 +++++++++-- lib/l10n/ro_RO/app_ro_RO.arb | 36 +++++++++-- lib/l10n/ru_RU/app_ru_RU.arb | 118 ++++++++++++++++++++++------------- lib/l10n/sk_SK/app_sk_SK.arb | 36 +++++++++-- lib/l10n/sl_SI/app_sl_SI.arb | 36 +++++++++-- lib/l10n/sr_CS/app_sr_CS.arb | 36 +++++++++-- lib/l10n/sv_SE/app_sv_SE.arb | 36 +++++++++-- lib/l10n/th_TH/app_th_TH.arb | 36 +++++++++-- lib/l10n/tr_TR/app_tr_TR.arb | 36 +++++++++-- lib/l10n/uk_UA/app_uk_UA.arb | 36 +++++++++-- lib/l10n/vi_VN/app_vi_VN.arb | 36 +++++++++-- lib/l10n/zh_CN/app_zh_CN.arb | 36 +++++++++-- lib/l10n/zh_TW/app_zh_TW.arb | 36 +++++++++-- 38 files changed, 1280 insertions(+), 216 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 987d6c6..7b507d1 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 6740c8a..fce6456 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 88810e7..08611b5 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Přiděleno", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Přidělit zásoby", "@allocateStock": {}, "appReleaseNotes": "Zobrazit poznámky k verzi aplikace", @@ -177,6 +185,7 @@ "confirmScan": "Potvrdit převod", "@confirmScan": {}, "confirmScanDetail": "Potvrdit podrobnosti o převodu zásob při skenování čárových kódů", + "@confirmScanDetail": {}, "connectionRefused": "Spojení selhalo", "@connectionRefused": {}, "count": "Počet", @@ -189,6 +198,10 @@ }, "credits": "Poděkování", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Zákazník", "@customer": {}, "customers": "Zákazníci", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentace", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Stahování souboru", "@downloading": {}, - "downloadError": "Chyba při stahování", - "@downloadError": {}, "edit": "Upravit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Domů", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Domovská obrazovka", + "@homeScreen": {}, "homeScreenSettings": "Konfigurace nastavení domovské obrazovky", "@homeScreenSettings": {}, "homeShowPo": "Zobrazit objednávky", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Žádné výsledky", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Žádná podkategorie", "@noSubcategories": {}, "noSubcategoriesAvailable": "Žádné podkategorie nejsou k dispozici", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Obnovit", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Obnovuji", "@refreshing": {}, "rejected": "Zamítnuto", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Soubor nahrán", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Použito v", "@usedIn": {}, "usedInDetails": "Sestavy vyžadující tento díl", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index b325f50..6ea4439 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Tildelt", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Tildel lager", "@allocateStock": {}, "appReleaseNotes": "Vis app-udgivelsesnoter", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Overfører fil", "@downloading": {}, - "downloadError": "Fejl under download", - "@downloadError": {}, "edit": "Rediger", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Hjem", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Startskærm", + "@homeScreen": {}, "homeScreenSettings": "Konfigurér indstillinger for startskærmen", "@homeScreenSettings": {}, "homeShowPo": "Vis Indkøbsordrer", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 11ac52b..21cefe5 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Zugewiesen", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Bestand zuweisen", "@allocateStock": {}, "appReleaseNotes": "App-Versionshinweise anzeigen", @@ -177,6 +185,7 @@ "confirmScan": "Transfer bestätigen", "@confirmScan": {}, "confirmScanDetail": "Bestätigen Sie Bestandsverschiebungen beim Scannen von Barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Verbindung verweigert", "@connectionRefused": {}, "count": "Zählen", @@ -189,6 +198,10 @@ }, "credits": "Danksagungen", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Kunde", "@customer": {}, "customers": "Kunden", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Datei wird heruntergeladen", "@downloading": {}, - "downloadError": "Fehler beim Herunterladen", - "@downloadError": {}, "edit": "Bearbeiten", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Startseite", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Startseite", + "@homeScreen": {}, "homeScreenSettings": "Einstellungen für Startseite konfigurieren", "@homeScreenSettings": {}, "homeShowPo": "Bestellungen anzeigen", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Keine Ergebnisse", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Keine Unter-Kategorien", "@noSubcategories": {}, "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Neu laden", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Aktualisiere", "@refreshing": {}, "rejected": "Zurückgewiesen", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Datei hochgeladen", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Verwendet in", "@usedIn": {}, "usedInDetails": "Baugruppen, die dieses Teil benötigen", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 2351ef7..2aaba50 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Κατανεμημένο", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Κατανομή Αποθέματος", "@allocateStock": {}, "appReleaseNotes": "Προβολή πληροφοριών έκδοσης εφαρμογής", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 64e31e0..7901bd3 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Asignado", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Asignar stock", "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", @@ -177,6 +185,7 @@ "confirmScan": "Confirmar transferencia", "@confirmScan": {}, "confirmScanDetail": "Confirmar detalles de transferencia de stock al escanear códigos de barras", + "@confirmScanDetail": {}, "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Contar", @@ -189,6 +198,10 @@ }, "credits": "Créditos", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Cliente", "@customer": {}, "customers": "Clientes", @@ -227,10 +240,12 @@ }, "documentation": "Documentación", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Descargando archivo", "@downloading": {}, - "downloadError": "Error de descarga", - "@downloadError": {}, "edit": "Editar", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Inicio", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Pantalla de Inicio", + "@homeScreen": {}, "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", "@homeScreenSettings": {}, "homeShowPo": "Mostrar órdenes de compra", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Sin resultados", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No hay subcategorías", "@noSubcategories": {}, "noSubcategoriesAvailable": "No hay subcategorías disponibles", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refrescar", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Actualizando", "@refreshing": {}, "rejected": "Rechazado", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Archivo subido", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Usado En", "@usedIn": {}, "usedInDetails": "Ensamblados que requieren esta pieza", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 5596058..2a70f57 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Asignado", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Asignar existencias", "@allocateStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", @@ -177,6 +185,7 @@ "confirmScan": "Confirmar transferencia", "@confirmScan": {}, "confirmScanDetail": "Confirmar detalles de transferencia de stock al escanear códigos de barras", + "@confirmScanDetail": {}, "connectionRefused": "Conexión rechazada", "@connectionRefused": {}, "count": "Número", @@ -189,6 +198,10 @@ }, "credits": "Créditos", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Cliente", "@customer": {}, "customers": "Clientes", @@ -227,10 +240,12 @@ }, "documentation": "Documentación", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Descargando archivo", "@downloading": {}, - "downloadError": "Error de descarga", - "@downloadError": {}, "edit": "Editar", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Inicio", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Pantalla de Inicio", + "@homeScreen": {}, "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", "@homeScreenSettings": {}, "homeShowPo": "Mostrar órdenes de compra", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Sin resultados", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No hay subcategorías", "@noSubcategories": {}, "noSubcategoriesAvailable": "No hay subcategorías disponibles", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Actualizar", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Actualizando", "@refreshing": {}, "rejected": "Rechazado", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Archivo subido", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Usado en", "@usedIn": {}, "usedInDetails": "Ensambles que requieren esta parte", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 0cd1e01..f151102 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Eraldatud", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Jaota laoseis", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Kinnita ülekanne", "@confirmScan": {}, "confirmScanDetail": "Kinnitage laoseisu ülekande üksikasjad vöötkoodide skaneerimisel", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Kogus", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Klient", "@customer": {}, "customers": "Kliendid", @@ -227,10 +240,12 @@ }, "documentation": "Dokumendid", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Faili allalaadimine", "@downloading": {}, - "downloadError": "Allalaadimise viga", - "@downloadError": {}, "edit": "Muuda", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Avaleht", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Koduekraan", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Tulemusi pole", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Alamkategooriaid pole", "@noSubcategories": {}, "noSubcategoriesAvailable": "Ühtegi alamkategooriat pole saadaval", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Värskenda", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Värskendan", "@refreshing": {}, "rejected": "Tagasi lükatud", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Fail on üles laaditud", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 8bcf061..1b2b7f4 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "اختصاص داده شده", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "موجودی اختصاص داده شده", "@allocateStock": {}, "appReleaseNotes": "نمایش یادداشت های انتشار برنامه", @@ -177,6 +185,7 @@ "confirmScan": "تأیید انتقال", "@confirmScan": {}, "confirmScanDetail": "هنگام اسکن بارکد، جزئیات انتقال سهام را تأیید کنید", + "@confirmScanDetail": {}, "connectionRefused": "اتصال رد شد", "@connectionRefused": {}, "count": "تعداد", @@ -189,6 +198,10 @@ }, "credits": "اعتبارات", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "مشتری", "@customer": {}, "customers": "مشتریان", @@ -227,10 +240,12 @@ }, "documentation": "مستندات", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "در حال دانلود فایل", "@downloading": {}, - "downloadError": "خطای بارگیری", - "@downloadError": {}, "edit": "ویرایش", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "خانه", - "@homeScreen": {}, + "@home": {}, "homeScreen": "صفحه خانه", + "@homeScreen": {}, "homeScreenSettings": "پیکربندی تنظیمات صفحه خانه", "@homeScreenSettings": {}, "homeShowPo": "نمایش سفارش های خرید", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "بدون نتیجه", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "بدون زیر دسته بندی", "@noSubcategories": {}, "noSubcategoriesAvailable": "هیچ زیر دسته بندی ای در دسترس نیست", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "تازه سازی", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "در حال تازه سازی", "@refreshing": {}, "rejected": "رد شد", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "فایل اپلود شد", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "استفاده شده در", "@usedIn": {}, "usedInDetails": "مجموعه هایی که به این قطعه نیاز دارند", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 5dafb94..e01e387 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Näytä sovelluksen julkaisutiedot", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Yhteys evätty", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Asiakkaat", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentaatio", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Ladataan tiedostoa", "@downloading": {}, - "downloadError": "Latausvirhe", - "@downloadError": {}, "edit": "Muokkaa", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Koti", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Aloitusnäyttö", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Ei tuloksia", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Päivitä", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Päivitetään", "@refreshing": {}, "rejected": "Hylätty", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 1284091..3b01569 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allouée", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allouer un stock", "@allocateStock": {}, "appReleaseNotes": "Afficher les notes de version de l'application", @@ -177,6 +185,7 @@ "confirmScan": "Confirmer le transfert", "@confirmScan": {}, "confirmScanDetail": "Confirmation des détails du transfert de stock lors de la lecture des codes-barres", + "@confirmScanDetail": {}, "connectionRefused": "Connexion refusée", "@connectionRefused": {}, "count": "Nombre", @@ -189,6 +198,10 @@ }, "credits": "Crédits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Client", "@customer": {}, "customers": "Clients", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Téléchargement du fichier", "@downloading": {}, - "downloadError": "Erreur lors du téléchargement", - "@downloadError": {}, "edit": "Modifier", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Page d’accueil", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Ecran d'accueil", + "@homeScreen": {}, "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", "@homeScreenSettings": {}, "homeShowPo": "Voir bon de commande", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Aucun résultat", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Pas de sous-catégorie", "@noSubcategories": {}, "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", @@ -576,7 +594,7 @@ "@partNoResults": {}, "partPricing": "Tarification des pièces", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Afficher les informations sur le prix des pièces", "@pricingSettingDetail": {}, "partSettings": "Paramètres de la pièce", "@partSettings": {}, @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Actualiser", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Actualisation en cours", "@refreshing": {}, "rejected": "Rejeté", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Fichier transféré", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Utilisé dans", "@usedIn": {}, "usedInDetails": "Assemblages qui requièrent ce composant", @@ -1102,9 +1124,9 @@ "@bomCost": {}, "internalCost": "Coût interne", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Cout Variable", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Cout Global", "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, @@ -1115,5 +1137,11 @@ "noPricingAvailable": "Aucune tarification disponible", "@noPricingAvailable": {}, "noPricingDataFound": "Aucune donnée de tarification disponible pour cette pièce", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index bee67ce..84f525a 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "מוקצה", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "הקצאת מלאי", "@allocateStock": {}, "appReleaseNotes": " הצג הערות פרסום של האפליקציה", @@ -177,6 +185,7 @@ "confirmScan": "אשר העברה", "@confirmScan": {}, "confirmScanDetail": "אשר את פרטי העברת המלאי בעת סריקת ברקודים", + "@confirmScanDetail": {}, "connectionRefused": "החיבור סורב", "@connectionRefused": {}, "count": "ספירה", @@ -189,6 +198,10 @@ }, "credits": "קרדיטים", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "לקוח", "@customer": {}, "customers": "לקוחות", @@ -227,10 +240,12 @@ }, "documentation": "תיעוד", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "מוריד קובץ", "@downloading": {}, - "downloadError": "שגיאת הורדה", - "@downloadError": {}, "edit": "ערוך", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "בית", - "@homeScreen": {}, + "@home": {}, "homeScreen": "מסך הבית", + "@homeScreen": {}, "homeScreenSettings": "הגדר את הגדרות מסך הבית", "@homeScreenSettings": {}, "homeShowPo": "הצג הזמנות רכש", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "אין תוצאות", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "אין קטגורית משנה", "@noSubcategories": {}, "noSubcategoriesAvailable": "אין קטכוריות משנה זמינות", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "רענון", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "מרענן", "@refreshing": {}, "rejected": "נדחה", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "הקובץ הועלה", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "בשימוש ב ", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 76e48cf..1dcb0e9 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index c26f18d..ab5d544 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Lefoglalva", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Készlet foglalása", "@allocateStock": {}, "appReleaseNotes": "Kiadási közlemények", @@ -177,6 +185,7 @@ "confirmScan": "Mozgatás megerősítése", "@confirmScan": {}, "confirmScanDetail": "Készlet mozgatás megerősítése vonalkód olvasáskor", + "@confirmScanDetail": {}, "connectionRefused": "A kapcsolat visszautasítva", "@connectionRefused": {}, "count": "Mennyiség", @@ -189,6 +198,10 @@ }, "credits": "Közreműködők", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Vevő", "@customer": {}, "customers": "Vevők", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentáció", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Fájl letöltése", "@downloading": {}, - "downloadError": "Letöltési hiba", - "@downloadError": {}, "edit": "Szerkesztés", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Főoldal", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Főképernyő", + "@homeScreen": {}, "homeScreenSettings": "Főképernyő beállítások konfigurálása", "@homeScreenSettings": {}, "homeShowPo": "Beszerzési rendelések megjelenítése", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Nincs találat", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Nincsenek alkategóriák", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nincsenek alkategóriák", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Frissítés", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Frissítés...", "@refreshing": {}, "rejected": "Elutasított", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Fájl feltöltve", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Felhasználva ebben", "@usedIn": {}, "usedInDetails": "Gyártmányok amik ezt az alkatrészt igénylik", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 062b937..2638e8e 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Dialokasikan", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Alokasikan Stok", "@allocateStock": {}, "appReleaseNotes": "Tampilkan catatan rilis aplikasi", @@ -177,6 +185,7 @@ "confirmScan": "Konfirmasi Transfer", "@confirmScan": {}, "confirmScanDetail": "Konfirmasikan detail transfer stok saat memindai barcode", + "@confirmScanDetail": {}, "connectionRefused": "Koneksi ditolak", "@connectionRefused": {}, "count": "Hitung", @@ -189,6 +198,10 @@ }, "credits": "Kredit", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Pelanggan", "@customer": {}, "customers": "Pelanggan", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentasi", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Mengunduh File", "@downloading": {}, - "downloadError": "Unduh Mengalami Galat", - "@downloadError": {}, "edit": "Sunting", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Beranda", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Tampilan Beranda", + "@homeScreen": {}, "homeScreenSettings": "Konfigurasikan pengaturan layar beranda", "@homeScreenSettings": {}, "homeShowPo": "Tampilkan Pembelian Pesanan", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Tidak ada hasil", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Tidak ada subkategori", "@noSubcategories": {}, "noSubcategoriesAvailable": "Tidak ada subkategori tersedia", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Segarkan", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Ditolak", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Berkas telah diunggah", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index bbed74a..4de3e23 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocato", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Alloca stock", "@allocateStock": {}, "appReleaseNotes": "Mostra le note di rilascio dell'app", @@ -177,6 +185,7 @@ "confirmScan": "Conferma trasferimento", "@confirmScan": {}, "confirmScanDetail": "Conferma trasferimento dettagli stock durante scansione codici a barre", + "@confirmScanDetail": {}, "connectionRefused": "Connessione rifiutata", "@connectionRefused": {}, "count": "Quantità", @@ -189,6 +198,10 @@ }, "credits": "Riconoscimenti", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Cliente", "@customer": {}, "customers": "Clienti", @@ -227,10 +240,12 @@ }, "documentation": "Documentazione", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "File in download", "@downloading": {}, - "downloadError": "Errore download", - "@downloadError": {}, "edit": "Modifica", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Schermata Home", + "@homeScreen": {}, "homeScreenSettings": "Configura le impostazioni della schermata home", "@homeScreenSettings": {}, "homeShowPo": "Mostra Ordini di Acquisto", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Nessun risultato", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Nessuna sotto categoria", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Aggiorna", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "In aggiornamento", "@refreshing": {}, "rejected": "Respinto", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File caricato", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Viene utilizzato in", "@usedIn": {}, "usedInDetails": "Assemblaggi che richiedono questa parte", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 95d343f..a14fbcd 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "割り当て", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "在庫の割り当て", "@allocateStock": {}, "appReleaseNotes": "アプリのリリースノートを表示", @@ -177,6 +185,7 @@ "confirmScan": "送金を確認", "@confirmScan": {}, "confirmScanDetail": "バーコードをスキャンする際に在庫移動の詳細を確認する", + "@confirmScanDetail": {}, "connectionRefused": "接続を拒否しました", "@connectionRefused": {}, "count": "カウント", @@ -189,6 +198,10 @@ }, "credits": "謝辞", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "顧客", "@customer": {}, "customers": "顧客", @@ -227,10 +240,12 @@ }, "documentation": "ドキュメント", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "ファイルをダウンロード中", "@downloading": {}, - "downloadError": "ダウンロードエラー", - "@downloadError": {}, "edit": "編集", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "ホーム", - "@homeScreen": {}, + "@home": {}, "homeScreen": "ホーム画面", + "@homeScreen": {}, "homeScreenSettings": "ホーム画面の設定", "@homeScreenSettings": {}, "homeShowPo": "注文書を表示", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "一致する結果なし", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "サブカテゴリはありません", "@noSubcategories": {}, "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "更新", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "更新中", "@refreshing": {}, "rejected": "却下済み", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "アップロードされたファイル", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "使用先", "@usedIn": {}, "usedInDetails": "この部品を必要とするアセンブリ。", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 502ab59..7afb9eb 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "앱 릴리즈 노트 표시", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "결과 없음", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index dde8345..09e66ca 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 562756c..3e7b10c 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Piešķirta", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Apstiprināt pārskaitījumu", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Savienojums noraidīts", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Klients", "@customer": {}, "customers": "Klienti", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Lejupielādēt failu", "@downloading": {}, - "downloadError": "Lejupielādes kļūda", - "@downloadError": {}, "edit": "Rediģēt", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Sākums", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Galvenā Izvēlne", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index c1b3f80..dd2904c 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Toegewezen", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Voorraad Toewijzen", "@allocateStock": {}, "appReleaseNotes": "App release notities weergeven", @@ -177,6 +185,7 @@ "confirmScan": "Bevestig Overdracht", "@confirmScan": {}, "confirmScanDetail": "Bevestig voorraadoverdrachtsgegevens bij het scannen van streepjescodes", + "@confirmScanDetail": {}, "connectionRefused": "Verbinding geweigerd", "@connectionRefused": {}, "count": "Tellen", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Klant", "@customer": {}, "customers": "Klanten", @@ -227,10 +240,12 @@ }, "documentation": "Documentatie", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Bestand wordt gedownload", "@downloading": {}, - "downloadError": "Fout bij downloaden", - "@downloadError": {}, "edit": "Bewerken", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Startscherm", + "@homeScreen": {}, "homeScreenSettings": "Configureer Startscherminstellingen", "@homeScreenSettings": {}, "homeShowPo": "Inkooporders tonen", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Geen Resultaten", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Geen Subcategorieën", "@noSubcategories": {}, "noSubcategoriesAvailable": "Geen subcategorieën beschikbaar", @@ -574,9 +592,9 @@ "@partsNone": {}, "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Prijzen onderdeel", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Toon prijsinformatie onderdeel", "@pricingSettingDetail": {}, "partSettings": "Onderdeel instellingen", "@partSettings": {}, @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Vernieuwen", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Verversen…", "@refreshing": {}, "rejected": "Geweigerd", @@ -982,7 +1002,7 @@ "@suppliers": {}, "supplierReference": "Leveranciers Referentie", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Camera wisselen", "@switchCamera": {}, "takePicture": "Neem een Foto", "@takePicture": {}, @@ -1016,7 +1036,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Zaklamp aan/uit", "@toggleTorch": {}, "tokenError": "Token Fout", "@tokenError": {}, @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Bestand geüpload", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Wordt Gebruikt In", "@usedIn": {}, "usedInDetails": "Dit product heeft het volgende onderdeel nodig", @@ -1084,36 +1106,42 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, - "price": "Price", + "price": "Prijs", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Prijs bereik", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Minimale prijs overschrijving", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Maximale prijs overschrijving", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Verkoop prijs", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Verkoop geschiedenis", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Leverancier prijzen", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "BOM Kosten", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Interne kosten", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Variant kosten", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Algemene prijzen", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Prijzen overschrijvingen", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Munteenheid", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Prijsverschillen", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Geen prijzen beschikbaar", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "noPricingDataFound": "Er zijn geen prijsgegevens gevonden voor dit deel", + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 6acd23c..c7272c0 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Tildelt", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Tildel lagerbeholdning", "@allocateStock": {}, "appReleaseNotes": "Vis appens utgivelsesnotater", @@ -177,6 +185,7 @@ "confirmScan": "Bekreft overføring", "@confirmScan": {}, "confirmScanDetail": "Bekreft lageroverføringsdetaljer når du skanner strekkoder", + "@confirmScanDetail": {}, "connectionRefused": "Tilkobling avvist", "@connectionRefused": {}, "count": "Antall", @@ -189,6 +198,10 @@ }, "credits": "Krediteringer", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Kunde", "@customer": {}, "customers": "Kunder", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentasjon", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Laster ned fil", "@downloading": {}, - "downloadError": "Feil ved nedlasting", - "@downloadError": {}, "edit": "Rediger", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Hjem", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Startside", + "@homeScreen": {}, "homeScreenSettings": "Konfigurer innstillinger for startside", "@homeScreenSettings": {}, "homeShowPo": "Vis innkjøpsordrer", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Ingen resultater", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Ingen underkategorier", "@noSubcategories": {}, "noSubcategoriesAvailable": "Ingen underkategorier tilgjengelig", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Oppdater", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Oppdaterer", "@refreshing": {}, "rejected": "Avvist", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Fil lastet opp", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Brukt i", "@usedIn": {}, "usedInDetails": "Sammenstillinger som krever denne delen", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 607a5d6..4cf8d50 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Przydzielono", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Przydziel zapasy", "@allocateStock": {}, "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", @@ -177,6 +185,7 @@ "confirmScan": "Potwierdź transfer", "@confirmScan": {}, "confirmScanDetail": "Potwierdź szczegóły transferu zapasów podczas skanowania kodów kreskowych", + "@confirmScanDetail": {}, "connectionRefused": "Połączenie odrzucone", "@connectionRefused": {}, "count": "Ilość", @@ -189,6 +198,10 @@ }, "credits": "Podziękowania", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Klient", "@customer": {}, "customers": "Klienci", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentacja", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Pobieranie Pliku", "@downloading": {}, - "downloadError": "Błąd Pobierania", - "@downloadError": {}, "edit": "Edytuj", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Strona główna", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Ekran główny", + "@homeScreen": {}, "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", "@homeScreenSettings": {}, "homeShowPo": "Pokaż zamówienia zakupu", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Brak wyników", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Brak podkategorii", "@noSubcategories": {}, "noSubcategoriesAvailable": "Brak dostępnych podkategorii", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Odśwież", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Odświeżanie", "@refreshing": {}, "rejected": "Odrzucono", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Plik przesłany", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Użyte w", "@usedIn": {}, "usedInDetails": "Złożenie, które wymagają tego komponentu", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index ce240f7..fa44fc2 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Alocar", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Estoque alocado", "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", @@ -177,6 +185,7 @@ "confirmScan": "Confirmar Transferência", "@confirmScan": {}, "confirmScanDetail": "Confirmar detalhes de transferência de estoque quando escanear código de barras", + "@confirmScanDetail": {}, "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contar", @@ -189,6 +198,10 @@ }, "credits": "Créditos", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Cliente", "@customer": {}, "customers": "Clientes", @@ -227,10 +240,12 @@ }, "documentation": "Documentação", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Baixando arquivo", "@downloading": {}, - "downloadError": "Erro ao baixar", - "@downloadError": {}, "edit": "Editar", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Início", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Tela inicial", + "@homeScreen": {}, "homeScreenSettings": "Definir as configurações da tela inicial", "@homeScreenSettings": {}, "homeShowPo": "Mostrar pedidos de compra", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Nenhum Resultado", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Nenhuma subcategoria", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nenhuma subcategoria disponível", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Atualizar", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Atualizando", "@refreshing": {}, "rejected": "Rejeitado", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Arquivo adicionado com sucesso", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Usado em", "@usedIn": {}, "usedInDetails": "Item que precisa desta peca", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index aa0f361..0cc3de9 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Alocado", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Alocar estoque", "@allocateStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", @@ -177,6 +185,7 @@ "confirmScan": "Confirmar transferência", "@confirmScan": {}, "confirmScanDetail": "Confirmar a transferência de estoque ao ler códigos de barras", + "@confirmScanDetail": {}, "connectionRefused": "Conexão recusada", "@connectionRefused": {}, "count": "Contagem", @@ -189,6 +198,10 @@ }, "credits": "Créditos", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Cliente", "@customer": {}, "customers": "Clientes", @@ -227,10 +240,12 @@ }, "documentation": "Documentação", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Baixando arquivo", "@downloading": {}, - "downloadError": "Erro de download", - "@downloadError": {}, "edit": "Editar", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Início", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Ecrã inicial", + "@homeScreen": {}, "homeScreenSettings": "Definir as configurações da tela inicial", "@homeScreenSettings": {}, "homeShowPo": "Mostrar Pedido de Compras", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 0887744..f4eecda 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Alocat", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Alocare Stoc", "@allocateStock": {}, "appReleaseNotes": "Afișează notele de lansare a aplicației", @@ -177,6 +185,7 @@ "confirmScan": "Confirmă transferul", "@confirmScan": {}, "confirmScanDetail": "Confirmă detaliile transferului de stoc la scanarea codurilor de bare", + "@confirmScanDetail": {}, "connectionRefused": "Conexiune refuzată", "@connectionRefused": {}, "count": "Număr", @@ -189,6 +198,10 @@ }, "credits": "Credite", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Client", "@customer": {}, "customers": "Clienți", @@ -227,10 +240,12 @@ }, "documentation": "Documentație", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Se descarcă fișierul", "@downloading": {}, - "downloadError": "Eroare la descărcare", - "@downloadError": {}, "edit": "Editare", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Acasă", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Ecran principal", + "@homeScreen": {}, "homeScreenSettings": "Configurați setările ecranului principal", "@homeScreenSettings": {}, "homeShowPo": "Arată Comenzile de Achiziție", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Niciun rezultat", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Nu există subcategorii", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nicio subcategorie disponibilă", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 2b3c886..4b50d7a 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Выделено", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Выделить запас", "@allocateStock": {}, "appReleaseNotes": "Показать заметки о выпуске приложения", @@ -170,13 +178,14 @@ "@companyUpdated": {}, "companies": "Компании", "@companies": {}, - "completionDate": "Completion Date", + "completionDate": "Дата завершения", "@completionDate": {}, "configureServer": "Настройка параметров сервера", "@configureServer": {}, "confirmScan": "Подтвердить перенос", "@confirmScan": {}, "confirmScanDetail": "Подтвердите детали перевода по складу при сканировании штрих-кодов", + "@confirmScanDetail": {}, "connectionRefused": "Отказано в подключении", "@connectionRefused": {}, "count": "Количество", @@ -189,6 +198,10 @@ }, "credits": "Авторы", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Клиент", "@customer": {}, "customers": "Покупатели", @@ -227,10 +240,12 @@ }, "documentation": "Документация", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Загрузка файла", "@downloading": {}, - "downloadError": "Ошибка загрузки", - "@downloadError": {}, "edit": "Изменить", "@edit": { "description": "edit" @@ -279,15 +294,15 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Загружать анонимные отчеты об ошибках и журналы сбоев", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Срок годности", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Просрочен", "@expiryExpired": {}, - "expiryStale": "Stale", + "expiryStale": "Устаревшие", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Дополнительные позиции", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Дополнительные позиции", "@extraLineItems": {}, "feedback": "Обратная Связь", "@feedback": {}, @@ -344,8 +359,9 @@ "description": "history" }, "home": "Главная", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Начальный экран", + "@homeScreen": {}, "homeScreenSettings": "Настройка главной страницы", "@homeScreenSettings": {}, "homeShowPo": "Показать заказы на поставку", @@ -428,7 +444,7 @@ "@itemInLocation": {}, "itemDeleted": "Позиция была удалена", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Позиция обновлена", "@itemUpdated": {}, "keywords": "Ключевые слова", "@keywords": {}, @@ -438,7 +454,7 @@ "@labelPrintingDetail": {}, "labelTemplate": "Шаблон этикетки", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Выберите шаблон этикетки", "@labelSelectTemplate": {}, "labelSelectPrinter": "Выберите принтер этикеток", "@labelSelectPrinter": {}, @@ -484,9 +500,9 @@ "@link": {}, "lost": "Потерян", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Деталь производителя", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Редактировать деталь производителя", "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Код производителя", "@manufacturerPartNumber": {}, @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Нет результатов", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Нет подкатегории", "@noSubcategories": {}, "noSubcategoriesAvailable": "Нет доступных подкатегорий", @@ -574,9 +592,9 @@ "@partsNone": {}, "partNoResults": "Нет компонентов, соответствующих запросу", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Цены детали", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Показывать информацию о ценах", "@pricingSettingDetail": {}, "partSettings": "Настройки деталей", "@partSettings": {}, @@ -648,17 +666,17 @@ "@profileTapToCreate": {}, "projectCode": "Код проекта", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Подтвердить сканирование данных", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Подтвердите подробности при сканировании позиций", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Включить заказы на закупку", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Включить функцию заказов на закупку", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Кнопка камеры", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Включить кнопку загрузки изображений на экране заказа", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Заказ на поставку", "@purchaseOrder": {}, @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Обновить", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Обновление…", "@refreshing": {}, "rejected": "Отклонено", @@ -776,13 +796,13 @@ "@salesOrder": {}, "salesOrders": "Заказы на продажу", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Включить заказы на продажу", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Включить функцию заказов на продажу", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Кнопка камеры", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Включить кнопку загрузки изображений на экране заказов", "@salesOrderShowCameraDetail": {}, "salesOrderSettings": "Настройки заказа на продажу", "@salesOrderSettings": {}, @@ -982,7 +1002,7 @@ "@suppliers": {}, "supplierReference": "Ссылка на поставщика", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Переключить камеру", "@switchCamera": {}, "takePicture": "Сделать снимок", "@takePicture": {}, @@ -1016,7 +1036,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Фонарик", "@toggleTorch": {}, "tokenError": "Ошибка токена", "@tokenError": {}, @@ -1046,7 +1066,7 @@ "@translateHelp": {}, "unavailable": "Недоступно", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Позиция недоступна", "@unavailableDetail": {}, "unitPrice": "Цена за ед.", "@unitPrice": {}, @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Файл загружен", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Используется в", "@usedIn": {}, "usedInDetails": "Сборки, для которых требуется эта часть", @@ -1084,36 +1106,42 @@ "@viewSupplierPart": {}, "website": "Сайт", "@website": {}, - "price": "Price", + "price": "Цена", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Диапазон цен", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Переопределение минимальной цены", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Переопределение максимальной цены", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Цена продажи", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "История продаж", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Цены поставщика", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Стоимость спецификации", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Внутренняя стоимость", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Стоимость варианта", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Общая цена", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Переопределение цен", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Валюта", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Разбивка по ценам", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Нет данных о цене", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "noPricingDataFound": "Для этой детали не найдены данные о ценах", + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index bfa0e53..61646a8 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 15d9589..5e36427 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, "appReleaseNotes": "Display app release notes", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 9b11805..a3e6c69 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Alocirano", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Alociraj zalihe", "@allocateStock": {}, "appReleaseNotes": "Prikaži informacije o aplikaciji", @@ -177,6 +185,7 @@ "confirmScan": "Potvrdi prenos", "@confirmScan": {}, "confirmScanDetail": "Potvrdi detalje transfera zaliha prilikom skeniranja bar kodova", + "@confirmScanDetail": {}, "connectionRefused": "Konekcija odbijena", "@connectionRefused": {}, "count": "Broj", @@ -189,6 +198,10 @@ }, "credits": "Zasluge", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Mušterija", "@customer": {}, "customers": "Mušterije", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentacija", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Preuzimanje fajla", "@downloading": {}, - "downloadError": "Greška pri preuzimanju", - "@downloadError": {}, "edit": "Izmeni", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Nema rezultata", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Nema podkategorija", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nema dostupnih podkategorija", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 94e0132..16f377e 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Allokerad", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Allokera lager", "@allocateStock": {}, "appReleaseNotes": "Visa versionsinfo för app", @@ -177,6 +185,7 @@ "confirmScan": "Bekräfta överföring", "@confirmScan": {}, "confirmScanDetail": "Bekräfta lageröverföringsdetaljer vid skanning av streckkoder", + "@confirmScanDetail": {}, "connectionRefused": "Anslutning nekad", "@connectionRefused": {}, "count": "Antal", @@ -189,6 +198,10 @@ }, "credits": "Krediter", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Kund", "@customer": {}, "customers": "Kunder", @@ -227,10 +240,12 @@ }, "documentation": "Dokumentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Laddar ner fil", "@downloading": {}, - "downloadError": "Nedladdningsfel", - "@downloadError": {}, "edit": "Redigera", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Hem", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Startsidan", + "@homeScreen": {}, "homeScreenSettings": "Konfigurera inställningar för startskärmen", "@homeScreenSettings": {}, "homeShowPo": "Visa inköpsorder", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Inga resultat", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, "noSubcategoriesAvailable": "Inga underkategorier tillgängliga", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Uppdatera", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Uppdaterar", "@refreshing": {}, "rejected": "Avvisad", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Fil har laddats upp", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Används i", "@usedIn": {}, "usedInDetails": "Sammanställning som kräver denna artikel", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index ddd2a07..d9a6323 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "แบ่ง", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "จัดสรรคลัง", "@allocateStock": {}, "appReleaseNotes": "แสดงข้อมูลรุ่นของโปรแกรม", @@ -177,6 +185,7 @@ "confirmScan": "Confirm Transfer", "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, "count": "Count", @@ -189,6 +198,10 @@ }, "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Customer", "@customer": {}, "customers": "Customers", @@ -227,10 +240,12 @@ }, "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, "edit": "Edit", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", + "@homeScreen": {}, "homeScreenSettings": "Configure home screen settings", "@homeScreenSettings": {}, "homeShowPo": "Show Purchase Orders", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index a9a80f2..2e813b2 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Tahsis edildi", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Tahsisli stok", "@allocateStock": {}, "appReleaseNotes": "Uygulama yayınlama notlarını göster", @@ -177,6 +185,7 @@ "confirmScan": "Aktarımı Onayla", "@confirmScan": {}, "confirmScanDetail": "Barkodları tararken stok aktarım ayrıntılarını onayla", + "@confirmScanDetail": {}, "connectionRefused": "Bağlantı reddedildi", "@connectionRefused": {}, "count": "Sayım", @@ -189,6 +198,10 @@ }, "credits": "Katkıda Bulunanlar", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Müşteri", "@customer": {}, "customers": "Müşteriler", @@ -227,10 +240,12 @@ }, "documentation": "Dökümantasyon", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Dosya indiriliyor", "@downloading": {}, - "downloadError": "İndirme Hatası", - "@downloadError": {}, "edit": "Düzenle", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Ana Sayfa", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Ana Ekran", + "@homeScreen": {}, "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", "@homeScreenSettings": {}, "homeShowPo": "Satın Alma Siparişlerini Göster", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Sonuç Yok", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Alt kategori yok", "@noSubcategories": {}, "noSubcategoriesAvailable": "Uygun alt kategori yok", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Yenile", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Yenileniyor", "@refreshing": {}, "rejected": "Reddedildi", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Dosya yüklendi", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Burada Kullanıldı", "@usedIn": {}, "usedInDetails": "Bu parçayı gerektiren montajlar", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "Fiyatlandırma mevcut değil", "@noPricingAvailable": {}, "noPricingDataFound": "Bu parça için fiyatlandırma verisi bulunamadı", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index dbc813f..4892724 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Виділено", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Виділити запас", "@allocateStock": {}, "appReleaseNotes": "Показати примітки до випуску", @@ -177,6 +185,7 @@ "confirmScan": "Підтвердити переказ", "@confirmScan": {}, "confirmScanDetail": "Підтверджувати інформацію про передавання запасів під час сканування штрих-кодів", + "@confirmScanDetail": {}, "connectionRefused": "З'єднання відхилено", "@connectionRefused": {}, "count": "Кількість", @@ -189,6 +198,10 @@ }, "credits": "", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Покупець", "@customer": {}, "customers": "", @@ -227,10 +240,12 @@ }, "documentation": "Документація", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Завантаження файлу", "@downloading": {}, - "downloadError": "Помилка Завантаження", - "@downloadError": {}, "edit": "Редагувати", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Домашня сторінка", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Домашній екран", + "@homeScreen": {}, "homeScreenSettings": "Налаштування параметрів головного екрану", "@homeScreenSettings": {}, "homeShowPo": "Показати замовлення на купівлю", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Refreshing", "@refreshing": {}, "rejected": "Rejected", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Used In", "@usedIn": {}, "usedInDetails": "Assemblies which require this part", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index cbe20d5..def909c 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "Được phân bố", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "Phân kho", "@allocateStock": {}, "appReleaseNotes": "Hiển thị ghi chú phát hành ứng dụng", @@ -177,6 +185,7 @@ "confirmScan": "Xác nhận chuyển tiền", "@confirmScan": {}, "confirmScanDetail": "Xác nhận chi tiết chuyển tiền khi quét mã", + "@confirmScanDetail": {}, "connectionRefused": "Kết nối bị từ chối", "@connectionRefused": {}, "count": "Đếm", @@ -189,6 +198,10 @@ }, "credits": "Tín dụng", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "Khách hàng", "@customer": {}, "customers": "Khách hàng", @@ -227,10 +240,12 @@ }, "documentation": "Tài liệu", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "Tập tin đang tải xuống", "@downloading": {}, - "downloadError": "Tải xuống lỗi", - "@downloadError": {}, "edit": "Sửa", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "Trang chủ", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Màn hình chính", + "@homeScreen": {}, "homeScreenSettings": "Cấu hình thiết lập màn hình chính", "@homeScreenSettings": {}, "homeShowPo": "Hiển thị đơn đặt hàng mới", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "Không có kết quả", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "Không có danh mục con", "@noSubcategories": {}, "noSubcategoriesAvailable": "Không có sẵn danh mục", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "Làm mới", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "Đang làm mới", "@refreshing": {}, "rejected": "Đã từ chối", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "Tải tệp lên", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "Sử dụng trong", "@usedIn": {}, "usedInDetails": "Sự lắp ráp cần sản phẩm này", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 520795b..1bd22a5 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "已分配", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "分配库存", "@allocateStock": {}, "appReleaseNotes": "显示应用发布笔记", @@ -177,6 +185,7 @@ "confirmScan": "确认转移", "@confirmScan": {}, "confirmScanDetail": "扫描条形码时确认库存转移详情", + "@confirmScanDetail": {}, "connectionRefused": "连接被拒绝", "@connectionRefused": {}, "count": "数量", @@ -189,6 +198,10 @@ }, "credits": "致谢", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "客户", "@customer": {}, "customers": "客户信息", @@ -227,10 +240,12 @@ }, "documentation": "文档", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "下载文件中", "@downloading": {}, - "downloadError": "下载错误", - "@downloadError": {}, "edit": "编辑", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "主页", - "@homeScreen": {}, + "@home": {}, "homeScreen": "主屏幕", + "@homeScreen": {}, "homeScreenSettings": "配置主屏幕设置", "@homeScreenSettings": {}, "homeShowPo": "显示采购订单", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "无结果", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "无子类别", "@noSubcategories": {}, "noSubcategoriesAvailable": "无可用子类别", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "刷新", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "正在刷新", "@refreshing": {}, "rejected": "已拒绝", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "文件已上传", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "用途", "@usedIn": {}, "usedInDetails": "需要此零件的装配体", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 476ef29..bd7c5e1 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -36,6 +36,14 @@ "@appDetails": {}, "allocated": "已分配", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, "allocateStock": "分配庫存", "@allocateStock": {}, "appReleaseNotes": "顯示應用程式發布說明", @@ -177,6 +185,7 @@ "confirmScan": "確認轉移", "@confirmScan": {}, "confirmScanDetail": "掃描條碼時確認庫存轉移詳情", + "@confirmScanDetail": {}, "connectionRefused": "連線被拒", "@connectionRefused": {}, "count": "數量", @@ -189,6 +198,10 @@ }, "credits": "感謝", "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, "customer": "客戶", "@customer": {}, "customers": "客戶", @@ -227,10 +240,12 @@ }, "documentation": "文件", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, "downloading": "下載檔案", "@downloading": {}, - "downloadError": "下載錯誤", - "@downloadError": {}, "edit": "編輯", "@edit": { "description": "edit" @@ -344,8 +359,9 @@ "description": "history" }, "home": "首頁", - "@homeScreen": {}, + "@home": {}, "homeScreen": "主畫面", + "@homeScreen": {}, "homeScreenSettings": "伺服器設定", "@homeScreenSettings": {}, "homeShowPo": "顯示採購訂單", @@ -512,6 +528,8 @@ "@noResponse": {}, "noResults": "無結果", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, "noSubcategories": "無子類別", "@noSubcategories": {}, "noSubcategoriesAvailable": "無可用子類別", @@ -702,6 +720,8 @@ "@reference": {}, "refresh": "刷新", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, "refreshing": "正在刷新", "@refreshing": {}, "rejected": "已拒絕", @@ -1060,6 +1080,8 @@ "@uploadFailed": {}, "uploadSuccess": "文件已上傳", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, "usedIn": "用途", "@usedIn": {}, "usedInDetails": "需要此零件的裝配體", @@ -1115,5 +1137,11 @@ "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {} } \ No newline at end of file From 675f9ee1bb3ad10378916f57daeff6b01fea9a87 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 29 Jun 2025 10:46:42 +1000 Subject: [PATCH 684/746] New Crowdin updates (#667) * New translations app_en.arb (Italian) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/it_IT/app_it_IT.arb | 62 ++++++++++++++++++------------------ lib/l10n/zh_CN/app_zh_CN.arb | 58 ++++++++++++++++----------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 4de3e23..6cf3242 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Quadrato (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Alloca stock", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "Riconoscimenti", "@credits": {}, - "crop": "Crop", + "crop": "Ritaglia", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Ritaglia immagine", "@cropImage": {}, "customer": "Cliente", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Documentazione", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Download completato", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Errore nel scaricare l'immagine", "@downloadError": {}, "downloading": "File in download", "@downloading": {}, @@ -528,7 +528,7 @@ "@noResponse": {}, "noResults": "Nessun risultato", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Nessuna immagine disponibile", "@noImageAvailable": {}, "noSubcategories": "Nessuna sotto categoria", "@noSubcategories": {}, @@ -592,9 +592,9 @@ "@partsNone": {}, "partNoResults": "Nessun articolo corrispondente alla ricerca", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Prezzo Articolo", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Mostra prezzi dell'articolo", "@pricingSettingDetail": {}, "partSettings": "Impostazioni articolo", "@partSettings": {}, @@ -720,7 +720,7 @@ "@reference": {}, "refresh": "Aggiorna", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Ruota di 90° in senso orario", "@rotateClockwise": {}, "refreshing": "In aggiornamento", "@refreshing": {}, @@ -1002,7 +1002,7 @@ "@suppliers": {}, "supplierReference": "Riferimento fornitore", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Cambia visuale", "@switchCamera": {}, "takePicture": "Scatta Foto", "@takePicture": {}, @@ -1036,7 +1036,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Torcia", "@toggleTorch": {}, "tokenError": "Errore Token", "@tokenError": {}, @@ -1080,7 +1080,7 @@ "@uploadFailed": {}, "uploadSuccess": "File caricato", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Carica immagine", "@uploadImage": {}, "usedIn": "Viene utilizzato in", "@usedIn": {}, @@ -1106,42 +1106,42 @@ "@viewSupplierPart": {}, "website": "Sito Web", "@website": {}, - "price": "Price", + "price": "Prezzo", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Fascia di Prezzo", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Sovrascrivere Prezzo Minimo", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Sovrascrivi Prezzo Massimo", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Prezzo di Vendita", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Storico vendite", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Prezzo del Fornitore", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Costo BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Costo Interno", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Costo Variante", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Prezzi Complessivi", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Sovrascrittura Prezzi", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Valuta", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Divergenze di prezzo", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Nessun prezzo disponibile", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Nessun dato trovato per questo articolo", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Sei sicuro di voler eliminare questa immagine?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Elimina immagine", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Elimina immagine", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 1bd22a5..6037058 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "正方形 (1:1)", "@aspectRatioSquare": {}, "allocateStock": "分配库存", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "致谢", "@credits": {}, - "crop": "Crop", + "crop": "裁剪", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "裁剪图片", "@cropImage": {}, "customer": "客户", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "文档", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "下载完成", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "下载图片时出错", "@downloadError": {}, "downloading": "下载文件中", "@downloading": {}, @@ -528,7 +528,7 @@ "@noResponse": {}, "noResults": "无结果", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "没有可用的图片", "@noImageAvailable": {}, "noSubcategories": "无子类别", "@noSubcategories": {}, @@ -592,9 +592,9 @@ "@partsNone": {}, "partNoResults": "没有匹配查询的零件", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "零件价格", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "显示零件价格信息", "@pricingSettingDetail": {}, "partSettings": "零件设置", "@partSettings": {}, @@ -720,7 +720,7 @@ "@reference": {}, "refresh": "刷新", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "顺时针旋转 90°", "@rotateClockwise": {}, "refreshing": "正在刷新", "@refreshing": {}, @@ -1002,7 +1002,7 @@ "@suppliers": {}, "supplierReference": "供应商参考", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "切换摄像头", "@switchCamera": {}, "takePicture": "拍照", "@takePicture": {}, @@ -1036,7 +1036,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "切换手电筒", "@toggleTorch": {}, "tokenError": "令牌错误", "@tokenError": {}, @@ -1080,7 +1080,7 @@ "@uploadFailed": {}, "uploadSuccess": "文件已上传", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "上传图片", "@uploadImage": {}, "usedIn": "用途", "@usedIn": {}, @@ -1106,42 +1106,42 @@ "@viewSupplierPart": {}, "website": "网站", "@website": {}, - "price": "Price", + "price": "价格", "@price": {}, - "priceRange": "Price Range", + "priceRange": "价格范围", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "销售价格", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "销售历史", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "供应商价格", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "物料清单成本", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "内部成本", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "变体成本", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "总定价", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "价格覆盖", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "币种", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "批发价", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "无可用价格", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "未找到此零件的定价数据", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "您确认要删除此图片吗?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "删除图片", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "删除图片", "@deleteImage": {} } \ No newline at end of file From 5bd5d34b24c530551b25f9e5e4488832c4d668b2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 29 Jun 2025 16:57:31 +1000 Subject: [PATCH 685/746] Tweak for ios build (#669) --- ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 36 +++++++++- .../xcshareddata/WorkspaceSettings.xcsettings | 5 ++ .../xcshareddata/swiftpm/Package.resolved | 69 ------------------- .../xcshareddata/xcschemes/Runner.xcscheme | 2 + .../xcshareddata/swiftpm/Package.resolved | 69 ------------------- 6 files changed, 42 insertions(+), 141 deletions(-) create mode 100644 ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/ios/Podfile b/ios/Podfile index 1c05085..b68e1f5 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your projects -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0e0897d..55a50c0 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -278,15 +278,47 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", + "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", + "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/audioplayers_darwin/audioplayers_darwin.framework", - "${BUILT_PRODUCTS_DIR}/flutter_zxing/flutter_zxing.framework", + "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", + "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", + "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", + "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", + "${BUILT_PRODUCTS_DIR}/mobile_scanner/mobile_scanner.framework", "${BUILT_PRODUCTS_DIR}/open_filex/open_filex.framework", + "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", + "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", + "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", + "${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework", + "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", + "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers_darwin.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_zxing.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mobile_scanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_filex.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 819c57b..0000000 --- a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,69 +0,0 @@ -{ - "originHash" : "820af3cc63f10647eb1a29c6d280a54dd695478a4b5abdddf411bf17c43695a0", - "pins" : [ - { - "identity" : "dkcamera", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKCamera", - "state" : { - "branch" : "master", - "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" - } - }, - { - "identity" : "dkimagepickercontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKImagePickerController", - "state" : { - "branch" : "4.3.9", - "revision" : "0bdfeacefa308545adde07bef86e349186335915" - } - }, - { - "identity" : "dkphotogallery", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKPhotoGallery", - "state" : { - "branch" : "master", - "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" - } - }, - { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage", - "state" : { - "revision" : "cac9a55a3ae92478a2c95042dcc8d9695d2129ca", - "version" : "5.21.0" - } - }, - { - "identity" : "sentry-cocoa", - "kind" : "remoteSourceControl", - "location" : "https://github.com/getsentry/sentry-cocoa", - "state" : { - "revision" : "491c87a32af58414bd03825b3029526640d3e73d", - "version" : "8.50.0" - } - }, - { - "identity" : "swiftygif", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kirualex/SwiftyGif.git", - "state" : { - "revision" : "4430cbc148baa3907651d40562d96325426f409a", - "version" : "5.4.5" - } - }, - { - "identity" : "tocropviewcontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TimOliver/TOCropViewController", - "state" : { - "revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b", - "version" : "2.7.4" - } - } - ], - "version" : 3 -} diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 128d576..5db441f 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -44,6 +44,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> Date: Tue, 1 Jul 2025 08:34:17 +0200 Subject: [PATCH 686/746] Use raw value of UTF-8 encoded barcodes (#670) --- lib/barcode/camera_controller.dart | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 9e2fe50..ba73b10 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -1,5 +1,4 @@ import "dart:math"; -import "dart:typed_data"; import "package:camera/camera.dart"; import "package:flutter/material.dart"; @@ -126,24 +125,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { }); } - Uint8List rawData = result.barcodes.first.rawBytes ?? Uint8List(0); - - String barcode; - - if (rawData.isNotEmpty) { - final buffer = StringBuffer(); - - for (int ii = 0; ii < rawData.length; ii++) { - buffer.writeCharCode(rawData[ii]); - } - - barcode = buffer.toString(); - - print(barcode); - } else { - // Fall back to text value - barcode = result.barcodes.first.rawValue ?? ""; - } + String barcode = result.barcodes.first.rawValue ?? ""; if (barcode.isEmpty) { // TODO: Error message "empty barcode" From 1374bb5db11f994fff1a5c6df68e18f6a4291be3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 1 Jul 2025 16:35:54 +1000 Subject: [PATCH 687/746] Change ios project settings (#671) --- ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index b68e1f5..a2be4c0 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your projects -platform :ios, '13.0' +platform :ios, '15.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 55a50c0..81f65ca 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -192,7 +192,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -430,7 +430,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -575,7 +575,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -608,7 +608,7 @@ ); INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = InvenTree; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -650,7 +650,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; From c30f1a19d16f62fc56d07b9be8bce8f946d3f3a6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 1 Jul 2025 16:42:45 +1000 Subject: [PATCH 688/746] Update version info and release notes (#672) --- assets/release_notes.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 0d68aa0..4b85e85 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,7 @@ +### 0.19.1 - July 2025 +--- +- Fixes bug related to barcode scanning with certain devices + ### 0.19.0 - June 2025 --- - Replace barcode scanning library for better performance diff --git a/pubspec.yaml b/pubspec.yaml index 91f5b16..33a1047 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.19.0+99 +version: 0.19.1+100 environment: sdk: ^3.8.1 From 2adf8e3430abe7e0f8d43ff0dbbc28ebf1f47d67 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 4 Jul 2025 21:16:04 +1000 Subject: [PATCH 689/746] Link icons (#677) * Add LinkIcon component * Visual UI updates - Refactor some components - Clearer text display - Add obvious chevron icon when a "tile" will take the user somewhere else * dart format * Adjust release notes * Add visual separator * Cleanup unused imports --- assets/release_notes.md | 5 ++ lib/inventree/company.dart | 9 +++ lib/l10n/app_en.arb | 6 ++ lib/widget/company/company_detail.dart | 30 ++++++--- lib/widget/company/supplier_part_detail.dart | 22 +++---- lib/widget/company/supplier_part_list.dart | 8 +-- lib/widget/link_icon.dart | 44 +++++++++++++ lib/widget/order/extra_line_detail.dart | 19 ++++-- lib/widget/order/po_extra_line_list.dart | 3 +- lib/widget/order/po_line_detail.dart | 20 ++---- lib/widget/order/po_line_list.dart | 7 +- lib/widget/order/purchase_order_detail.dart | 42 ++++++------ lib/widget/order/purchase_order_list.dart | 7 +- lib/widget/order/sales_order_detail.dart | 69 ++++++++++---------- lib/widget/order/sales_order_list.dart | 7 +- lib/widget/order/so_extra_line_list.dart | 3 +- lib/widget/order/so_line_detail.dart | 17 ++--- lib/widget/order/so_line_list.dart | 7 +- lib/widget/order/so_shipment_list.dart | 5 +- lib/widget/part/category_display.dart | 2 + lib/widget/part/category_list.dart | 3 +- lib/widget/part/part_detail.dart | 38 ++++++----- lib/widget/part/part_list.dart | 6 +- lib/widget/refreshable_state.dart | 2 +- lib/widget/stock/location_display.dart | 2 + lib/widget/stock/location_list.dart | 3 +- lib/widget/stock/stock_detail.dart | 55 +++++++--------- lib/widget/stock/stock_list.dart | 15 ++--- 28 files changed, 261 insertions(+), 195 deletions(-) create mode 100644 lib/widget/link_icon.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 4b85e85..3aab9fb 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### TBD - ??? +--- + +- Improved UX across the entire app + ### 0.19.1 - July 2025 --- - Fixes bug related to barcode scanning with certain devices diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 43f7d51..f9f6b42 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -5,6 +5,7 @@ import "package:inventree/api.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/company/company_detail.dart"; +import "package:inventree/widget/company/supplier_part_detail.dart"; /* * The InvenTreeCompany class represents the Company model in the InvenTree database. @@ -152,6 +153,14 @@ class InvenTreeSupplierPart extends InvenTreeModel { @override List get rolesRequired => ["part", "purchase_order"]; + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => SupplierPartDetailWidget(this)), + ); + } + @override Map> formFields() { Map> fields = { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ff6fa80..7e02053 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -391,6 +391,9 @@ "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Enter password", "@enterPassword": {}, @@ -924,6 +927,9 @@ "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "printLabel": "Print Label", "@printLabel": {}, diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 076a1e6..64356d7 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -10,6 +10,7 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/order/sales_order_list.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -240,8 +241,10 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.website.isNotEmpty) { tiles.add( ListTile( - title: Text("${widget.company.website}"), + title: Text(L10().website), + subtitle: Text("${widget.company.website}"), leading: Icon(TablerIcons.globe, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () async { openLink(widget.company.website); }, @@ -254,8 +257,10 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.email.isNotEmpty) { tiles.add( ListTile( - title: Text("${widget.company.email}"), + title: Text(L10().email), + subtitle: Text("${widget.company.email}"), leading: Icon(TablerIcons.at, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () async { openLink("mailto:${widget.company.email}"); }, @@ -268,8 +273,10 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.phone.isNotEmpty) { tiles.add( ListTile( - title: Text("${widget.company.phone}"), + title: Text(L10().phone), + subtitle: Text("${widget.company.phone}"), leading: Icon(TablerIcons.phone, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { openLink("tel:${widget.company.phone}"); }, @@ -283,8 +290,10 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.link.isNotEmpty) { tiles.add( ListTile( - title: Text("${widget.company.link}"), + title: Text(L10().link), + subtitle: Text("${widget.company.link}"), leading: Icon(TablerIcons.link, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { widget.company.openLink(); }, @@ -304,7 +313,7 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().supplierParts), leading: Icon(TablerIcons.building, color: COLOR_ACTION), - trailing: Text(supplierPartCount.toString()), + trailing: LinkIcon(text: supplierPartCount.toString()), onTap: () { Navigator.push( context, @@ -323,7 +332,7 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().purchaseOrders), leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), - trailing: Text("${outstandingPurchaseOrders}"), + trailing: LinkIcon(text: "${outstandingPurchaseOrders}"), onTap: () { Navigator.push( context, @@ -343,7 +352,7 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().suppliedParts), leading: Icon(TablerIcons.box), - trailing: Text("${company.partSuppliedCount}"), + trailing: LargeText("${company.partSuppliedCount}"), ) ); */ @@ -358,7 +367,7 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().salesOrders), leading: Icon(TablerIcons.truck, color: COLOR_ACTION), - trailing: Text("${outstandingSalesOrders}"), + trailing: LinkIcon(text: "${outstandingSalesOrders}"), onTap: () { Navigator.push( context, @@ -377,6 +386,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), + subtitle: Text(widget.company.notes), leading: Icon(TablerIcons.note), onTap: null, ), @@ -387,7 +397,9 @@ class _CompanyDetailState extends RefreshableState { ListTile( title: Text(L10().attachments), leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), onTap: () { Navigator.push( context, diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index df00b2f..92cf2de 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -1,9 +1,9 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:url_launcher/url_launcher.dart"; -import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; @@ -117,7 +117,7 @@ class _SupplierPartDisplayState title: Text(L10().internalPart), subtitle: Text(widget.supplierPart.partName), leading: Icon(TablerIcons.box, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail(widget.supplierPart.partImage), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); final part = await InvenTreePart().get(widget.supplierPart.partId); @@ -149,9 +149,7 @@ class _SupplierPartDisplayState title: Text(L10().supplier), subtitle: Text(widget.supplierPart.supplierName), leading: Icon(TablerIcons.building, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail( - widget.supplierPart.supplierImage, - ), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); var supplier = await InvenTreeCompany().get( @@ -182,9 +180,7 @@ class _SupplierPartDisplayState title: Text(L10().manufacturer), subtitle: Text(widget.supplierPart.manufacturerName), leading: Icon(TablerIcons.building_factory_2, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail( - widget.supplierPart.manufacturerImage, - ), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); var supplier = await InvenTreeCompany().get( @@ -204,6 +200,7 @@ class _SupplierPartDisplayState title: Text(L10().manufacturerPartNumber), subtitle: Text(widget.supplierPart.MPN), leading: Icon(TablerIcons.hash, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); var manufacturerPart = await InvenTreeManufacturerPart().get( @@ -236,7 +233,7 @@ class _SupplierPartDisplayState : null, leading: Icon(TablerIcons.package), trailing: widget.supplierPart.pack_quantity.isNotEmpty - ? Text(widget.supplierPart.pack_quantity) + ? LargeText(widget.supplierPart.pack_quantity) : null, ), ); @@ -245,8 +242,10 @@ class _SupplierPartDisplayState if (widget.supplierPart.link.isNotEmpty) { tiles.add( ListTile( - title: Text(widget.supplierPart.link), + title: Text(L10().link), + subtitle: Text(widget.supplierPart.link), leading: Icon(TablerIcons.link, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () async { var uri = Uri.tryParse(widget.supplierPart.link); if (uri != null && await canLaunchUrl(uri)) { @@ -260,7 +259,8 @@ class _SupplierPartDisplayState if (widget.supplierPart.note.isNotEmpty) { tiles.add( ListTile( - title: Text(widget.supplierPart.note), + title: Text(L10().notes), + subtitle: Text(widget.supplierPart.note), leading: Icon(TablerIcons.pencil), ), ); diff --git a/lib/widget/company/supplier_part_list.dart b/lib/widget/company/supplier_part_list.dart index 6576974..c820a67 100644 --- a/lib/widget/company/supplier_part_list.dart +++ b/lib/widget/company/supplier_part_list.dart @@ -8,7 +8,6 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/company/supplier_part_detail.dart"; /* * Widget for displaying a list of Supplier Part instances @@ -93,12 +92,7 @@ class _PaginatedSupplierPartListState leading: InvenTreeAPI().getThumbnail(supplierPart.supplierImage), trailing: InvenTreeAPI().getThumbnail(supplierPart.partImage), onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(supplierPart), - ), - ); + supplierPart.goToDetailPage(context); }, ); } diff --git a/lib/widget/link_icon.dart b/lib/widget/link_icon.dart new file mode 100644 index 0000000..4a835eb --- /dev/null +++ b/lib/widget/link_icon.dart @@ -0,0 +1,44 @@ +/* + * An icon component to indicate that pressing on an item will change the page. + */ + +import "package:cached_network_image/cached_network_image.dart"; +import "package:flutter/cupertino.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/app_colors.dart"; + +Widget LargeText( + String text, { + double size = 14.0, + bool bold = false, + Color? color, +}) { + // Return a large text widget with specified text + return Text( + text, + style: TextStyle( + fontSize: size, + fontWeight: bold ? FontWeight.bold : FontWeight.normal, + color: color, + ), + ); +} + +Widget LinkIcon({ + bool external = false, + String? text, + CachedNetworkImage? image, +}) { + // Return a row of items with an icon and text + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (text != null) ...[LargeText(text)], + if (image != null) ...[image], + Icon( + external ? TablerIcons.external_link : TablerIcons.chevron_right, + color: COLOR_ACTION, + ), + ], + ); +} diff --git a/lib/widget/order/extra_line_detail.dart b/lib/widget/order/extra_line_detail.dart index 055a58e..490f833 100644 --- a/lib/widget/order/extra_line_detail.dart +++ b/lib/widget/order/extra_line_detail.dart @@ -3,6 +3,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/helpers.dart"; import "package:inventree/l10.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; @@ -70,36 +71,44 @@ class _ExtraLineDetailWidgetState tiles.add( ListTile( title: Text(L10().reference), - trailing: Text(widget.item.reference), + subtitle: Text(widget.item.reference), + leading: Icon(TablerIcons.hash), ), ); tiles.add( ListTile( title: Text(L10().description), - trailing: Text(widget.item.description), + subtitle: Text(widget.item.description), + leading: Icon(TablerIcons.info_circle), ), ); tiles.add( ListTile( title: Text(L10().quantity), - trailing: Text(widget.item.quantity.toString()), + trailing: LargeText(widget.item.quantity.toString()), + leading: Icon(TablerIcons.progress), ), ); tiles.add( ListTile( title: Text(L10().unitPrice), - trailing: Text( + trailing: LargeText( renderCurrency(widget.item.price, widget.item.priceCurrency), ), + leading: Icon(TablerIcons.currency_dollar), ), ); if (widget.item.notes.isNotEmpty) { tiles.add( - ListTile(title: Text(L10().notes), subtitle: Text(widget.item.notes)), + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.item.notes), + leading: Icon(TablerIcons.note), + ), ); } diff --git a/lib/widget/order/po_extra_line_list.dart b/lib/widget/order/po_extra_line_list.dart index 3ede508..b9d953f 100644 --- a/lib/widget/order/po_extra_line_list.dart +++ b/lib/widget/order/po_extra_line_list.dart @@ -5,6 +5,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; @@ -110,7 +111,7 @@ class _PaginatedPOExtraLineListState return ListTile( title: Text(line.reference), subtitle: Text(line.description), - trailing: Text(line.quantity.toString()), + trailing: LargeText(line.quantity.toString(), size: 14), onTap: () { line.goToDetailPage(context).then((_) { refresh(); diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index cb0c855..7faf497 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -11,11 +11,11 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/widget/company/supplier_part_detail.dart"; /* * Widget for displaying detail view of a single PurchaseOrderLineItem @@ -145,7 +145,7 @@ class _POLineDetailWidgetState extends RefreshableState { title: Text(L10().internalPart), subtitle: Text(widget.item.partName), leading: Icon(TablerIcons.box, color: COLOR_ACTION), - trailing: api.getThumbnail(widget.item.partImage), + trailing: LinkIcon(image: api.getThumbnail(widget.item.partImage)), onTap: () async { showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); @@ -164,6 +164,7 @@ class _POLineDetailWidgetState extends RefreshableState { title: Text(L10().supplierPart), subtitle: Text(widget.item.SKU), leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); var part = await InvenTreeSupplierPart().get( @@ -172,12 +173,7 @@ class _POLineDetailWidgetState extends RefreshableState { hideLoadingOverlay(); if (part is InvenTreeSupplierPart) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(part), - ), - ); + part.goToDetailPage(context); } }, ), @@ -200,11 +196,9 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().received), subtitle: ProgressBar(widget.item.progressRatio), - trailing: Text( + trailing: LargeText( widget.item.progressString, - style: TextStyle( - color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, - ), + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), leading: Icon(TablerIcons.progress), ), @@ -226,7 +220,7 @@ class _POLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().unitPrice), leading: Icon(TablerIcons.currency_dollar), - trailing: Text( + trailing: LargeText( renderCurrency( widget.item.purchasePrice, widget.item.purchasePriceCurrency, diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart index 45a2702..2de44c4 100644 --- a/lib/widget/order/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -7,6 +7,7 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/purchase_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/order/po_line_detail.dart"; @@ -80,11 +81,9 @@ class _PaginatedPOLineListState return ListTile( title: Text(supplierPart.SKU), subtitle: Text(item.partName), - trailing: Text( + trailing: LargeText( item.progressString, - style: TextStyle( - color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, - ), + color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), leading: InvenTreeAPI().getThumbnail(supplierPart.partImage), onTap: () async { diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index f515cf8..4799317 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -14,8 +14,8 @@ import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/po_extra_line_list.dart"; -import "package:inventree/widget/stock/location_display.dart"; import "package:inventree/widget/order/po_line_list.dart"; import "package:inventree/widget/attachment_widget.dart"; @@ -347,11 +347,9 @@ class _PurchaseOrderDetailState title: Text(widget.order.reference), subtitle: Text(widget.order.description), leading: supplier == null ? null : api.getThumbnail(supplier.thumbnail), - trailing: Text( + trailing: LargeText( api.PurchaseOrderStatus.label(widget.order.status), - style: TextStyle( - color: api.PurchaseOrderStatus.color(widget.order.status), - ), + color: api.PurchaseOrderStatus.color(widget.order.status), ), ), ); @@ -382,6 +380,7 @@ class _PurchaseOrderDetailState title: Text(L10().supplier), subtitle: Text(supplier.name), leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { supplier.goToDetailPage(context); }, @@ -406,14 +405,8 @@ class _PurchaseOrderDetailState title: Text(L10().destination), subtitle: Text(destination!.name), leading: Icon(TablerIcons.map_pin, color: COLOR_ACTION), - onTap: () => { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LocationDisplayWidget(destination), - ), - ), - }, + trailing: LinkIcon(), + onTap: () => {destination!.goToDetailPage(context)}, ), ); } @@ -430,9 +423,9 @@ class _PurchaseOrderDetailState maximum: widget.order.lineItemCount.toDouble(), ), leading: Icon(TablerIcons.clipboard_check), - trailing: Text( + trailing: LargeText( "${completedLines} / ${widget.order.lineItemCount}", - style: TextStyle(color: lineColor), + color: lineColor, ), ), ); @@ -442,7 +435,7 @@ class _PurchaseOrderDetailState ListTile( title: Text(L10().extraLineItems), leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), - trailing: Text(extraLineCount.toString()), + trailing: LinkIcon(text: extraLineCount.toString()), onTap: () => { Navigator.push( context, @@ -461,7 +454,7 @@ class _PurchaseOrderDetailState ListTile( title: Text(L10().totalPrice), leading: Icon(TablerIcons.currency_dollar), - trailing: Text( + trailing: LargeText( renderCurrency( widget.order.totalPrice, widget.order.totalPriceCurrency, @@ -474,7 +467,7 @@ class _PurchaseOrderDetailState tiles.add( ListTile( title: Text(L10().issueDate), - trailing: Text(widget.order.issueDate), + trailing: LargeText(widget.order.issueDate), leading: Icon(TablerIcons.calendar), ), ); @@ -484,7 +477,7 @@ class _PurchaseOrderDetailState tiles.add( ListTile( title: Text(L10().startDate), - trailing: Text(widget.order.startDate), + trailing: LargeText(widget.order.startDate), leading: Icon(TablerIcons.calendar), ), ); @@ -494,7 +487,7 @@ class _PurchaseOrderDetailState tiles.add( ListTile( title: Text(L10().targetDate), - trailing: Text(widget.order.targetDate), + trailing: LargeText(widget.order.targetDate), leading: Icon(TablerIcons.calendar), ), ); @@ -504,7 +497,7 @@ class _PurchaseOrderDetailState tiles.add( ListTile( title: Text(L10().completionDate), - trailing: Text(widget.order.completionDate), + trailing: LargeText(widget.order.completionDate), leading: Icon(TablerIcons.calendar), ), ); @@ -521,7 +514,7 @@ class _PurchaseOrderDetailState ? TablerIcons.users : TablerIcons.user, ), - trailing: Text(widget.order.responsibleName), + trailing: LargeText(widget.order.responsibleName), ), ); } @@ -531,6 +524,7 @@ class _PurchaseOrderDetailState ListTile( title: Text(L10().notes), leading: Icon(TablerIcons.note, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -545,7 +539,9 @@ class _PurchaseOrderDetailState ListTile( title: Text(L10().attachments), leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), onTap: () { Navigator.push( context, diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart index 033e306..4c1b363 100644 --- a/lib/widget/order/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -4,6 +4,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; @@ -173,11 +174,9 @@ class _PaginatedPurchaseOrderListState leading: supplier == null ? null : InvenTreeAPI().getThumbnail(supplier.thumbnail), - trailing: Text( + trailing: LargeText( InvenTreeAPI().PurchaseOrderStatus.label(order.status), - style: TextStyle( - color: InvenTreeAPI().PurchaseOrderStatus.color(order.status), - ), + color: InvenTreeAPI().PurchaseOrderStatus.color(order.status), ), onTap: () async { order.goToDetailPage(context); diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 6318419..bc23961 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -6,6 +6,7 @@ import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/so_extra_line_list.dart"; import "package:inventree/widget/order/so_line_list.dart"; import "package:inventree/widget/order/so_shipment_list.dart"; @@ -323,11 +324,9 @@ class _SalesOrderDetailState extends RefreshableState { title: Text(widget.order.reference), subtitle: Text(widget.order.description), leading: customer == null ? null : api.getThumbnail(customer.thumbnail), - trailing: Text( + trailing: LargeText( api.SalesOrderStatus.label(widget.order.status), - style: TextStyle( - color: api.SalesOrderStatus.color(widget.order.status), - ), + color: api.SalesOrderStatus.color(widget.order.status), ), ), ); @@ -356,6 +355,7 @@ class _SalesOrderDetailState extends RefreshableState { title: Text(L10().customer), subtitle: Text(customer.name), leading: Icon(TablerIcons.user, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { customer.goToDetailPage(context); }, @@ -367,7 +367,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().customerReference), - trailing: Text(widget.order.customerReference), + trailing: LargeText(widget.order.customerReference), leading: Icon(TablerIcons.hash), ), ); @@ -375,6 +375,24 @@ class _SalesOrderDetailState extends RefreshableState { Color lineColor = widget.order.complete ? COLOR_SUCCESS : COLOR_WARNING; + // Shipment progress + if (widget.order.shipmentCount > 0) { + tiles.add( + ListTile( + title: Text(L10().shipments), + subtitle: ProgressBar( + widget.order.completedShipmentCount.toDouble(), + maximum: widget.order.shipmentCount.toDouble(), + ), + leading: Icon(TablerIcons.truck_delivery), + trailing: LargeText( + "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", + color: lineColor, + ), + ), + ); + } + tiles.add( ListTile( title: Text(L10().lineItems), @@ -383,9 +401,9 @@ class _SalesOrderDetailState extends RefreshableState { maximum: widget.order.lineItemCount.toDouble(), ), leading: Icon(TablerIcons.clipboard_check), - trailing: Text( + trailing: LargeText( "${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", - style: TextStyle(color: lineColor), + color: lineColor, ), ), ); @@ -395,7 +413,7 @@ class _SalesOrderDetailState extends RefreshableState { ListTile( title: Text(L10().extraLineItems), leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), - trailing: Text(extraLineCount.toString()), + trailing: LinkIcon(text: extraLineCount.toString()), onTap: () => { Navigator.push( context, @@ -410,31 +428,13 @@ class _SalesOrderDetailState extends RefreshableState { ), ); - // Shipment progress - if (widget.order.shipmentCount > 0) { - tiles.add( - ListTile( - title: Text(L10().shipments), - subtitle: ProgressBar( - widget.order.completedShipmentCount.toDouble(), - maximum: widget.order.shipmentCount.toDouble(), - ), - leading: Icon(TablerIcons.truck_delivery), - trailing: Text( - "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", - style: TextStyle(color: lineColor), - ), - ), - ); - } - // TODO: total price if (widget.order.startDate.isNotEmpty) { tiles.add( ListTile( title: Text(L10().startDate), - trailing: Text(widget.order.startDate), + trailing: LargeText(widget.order.startDate), leading: Icon(TablerIcons.calendar), ), ); @@ -444,7 +444,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().targetDate), - trailing: Text(widget.order.targetDate), + trailing: LargeText(widget.order.targetDate), leading: Icon(TablerIcons.calendar), ), ); @@ -454,7 +454,7 @@ class _SalesOrderDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().completionDate), - trailing: Text(widget.order.shipmentDate), + trailing: LargeText(widget.order.shipmentDate), leading: Icon(TablerIcons.calendar), ), ); @@ -471,7 +471,7 @@ class _SalesOrderDetailState extends RefreshableState { ? TablerIcons.users : TablerIcons.user, ), - trailing: Text(widget.order.responsibleName), + trailing: LargeText(widget.order.responsibleName), ), ); } @@ -481,6 +481,7 @@ class _SalesOrderDetailState extends RefreshableState { ListTile( title: Text(L10().notes), leading: Icon(TablerIcons.note, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -495,7 +496,9 @@ class _SalesOrderDetailState extends RefreshableState { ListTile( title: Text(L10().attachments), leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), onTap: () { Navigator.push( context, @@ -519,8 +522,8 @@ class _SalesOrderDetailState extends RefreshableState { List getTabIcons(BuildContext context) { return [ Tab(text: L10().details), - Tab(text: L10().lineItems), Tab(text: L10().shipments), + Tab(text: L10().lineItems), ]; } @@ -528,8 +531,8 @@ class _SalesOrderDetailState extends RefreshableState { List getTabs(BuildContext context) { return [ ListView(children: orderTiles(context)), - PaginatedSOLineList({"order": widget.order.pk.toString()}), PaginatedSOShipmentList({"order": widget.order.pk.toString()}), + PaginatedSOLineList({"order": widget.order.pk.toString()}), ]; } } diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart index 089363e..2c0ff4a 100644 --- a/lib/widget/order/sales_order_list.dart +++ b/lib/widget/order/sales_order_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -155,11 +156,9 @@ class _PaginatedSalesOrderListState leading: customer == null ? null : InvenTreeAPI().getThumbnail(customer.thumbnail), - trailing: Text( + trailing: LargeText( InvenTreeAPI().SalesOrderStatus.label(order.status), - style: TextStyle( - color: InvenTreeAPI().SalesOrderStatus.color(order.status), - ), + color: InvenTreeAPI().SalesOrderStatus.color(order.status), ), onTap: () async { order.goToDetailPage(context); diff --git a/lib/widget/order/so_extra_line_list.dart b/lib/widget/order/so_extra_line_list.dart index 0ed13a5..06521e6 100644 --- a/lib/widget/order/so_extra_line_list.dart +++ b/lib/widget/order/so_extra_line_list.dart @@ -6,6 +6,7 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -112,7 +113,7 @@ class _PaginatedSOExtraLineListState return ListTile( title: Text(line.reference), subtitle: Text(line.description), - trailing: Text(line.quantity.toString()), + trailing: LargeText(line.quantity.toString()), onTap: () { line.goToDetailPage(context).then((_) { refresh(); diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index f2f61ad..ae0d302 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -10,6 +10,7 @@ import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/progress.dart"; @@ -172,7 +173,7 @@ class _SOLineDetailWidgetState extends RefreshableState { title: Text(L10().part), subtitle: Text(widget.item.partName), leading: Icon(TablerIcons.box, color: COLOR_ACTION), - trailing: api.getThumbnail(widget.item.partImage), + trailing: LinkIcon(image: api.getThumbnail(widget.item.partImage)), onTap: () async { showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); @@ -190,7 +191,7 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().availableStock), leading: Icon(TablerIcons.packages), - trailing: Text(simpleNumberString(widget.item.availableStock)), + trailing: LargeText(simpleNumberString(widget.item.availableStock)), ), ); @@ -200,11 +201,9 @@ class _SOLineDetailWidgetState extends RefreshableState { leading: Icon(TablerIcons.clipboard_check), title: Text(L10().allocated), subtitle: ProgressBar(widget.item.allocatedRatio), - trailing: Text( + trailing: LargeText( widget.item.allocatedString, - style: TextStyle( - color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING, - ), + color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING, ), ), ); @@ -214,11 +213,9 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().shipped), subtitle: ProgressBar(widget.item.progressRatio), - trailing: Text( + trailing: LargeText( widget.item.progressString, - style: TextStyle( - color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, - ), + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), leading: Icon(TablerIcons.truck), ), diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart index 2530d3e..acadfeb 100644 --- a/lib/widget/order/so_line_list.dart +++ b/lib/widget/order/so_line_list.dart @@ -1,5 +1,6 @@ import "package:flutter/material.dart"; import "package:inventree/l10.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/so_line_detail.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/inventree/model.dart"; @@ -67,11 +68,9 @@ class _PaginatedSOLineListState title: Text(part.name), subtitle: Text(part.description), leading: InvenTreeAPI().getThumbnail(part.thumbnail), - trailing: Text( + trailing: LargeText( item.progressString, - style: TextStyle( - color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, - ), + color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), onTap: () async { showLoadingOverlay(); diff --git a/lib/widget/order/so_shipment_list.dart b/lib/widget/order/so_shipment_list.dart index a6c1472..126e247 100644 --- a/lib/widget/order/so_shipment_list.dart +++ b/lib/widget/order/so_shipment_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/inventree/model.dart"; @@ -56,7 +57,9 @@ class _PaginatedSOShipmentListState leading: shipment.shipped ? Icon(TablerIcons.calendar_check, color: COLOR_SUCCESS) : Icon(TablerIcons.calendar_cancel, color: COLOR_WARNING), - trailing: shipment.shipped ? Text(shipment.shipment_date ?? "") : null, + trailing: shipment.shipped + ? LargeText(shipment.shipment_date ?? "") + : null, ); } } diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart index 19138c9..bb9464b 100644 --- a/lib/widget/part/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -6,6 +6,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/part/category_list.dart"; import "package:inventree/widget/part/part_list.dart"; @@ -144,6 +145,7 @@ class _CategoryDisplayState extends RefreshableState { title: Text(L10().parentCategory), subtitle: Text("${widget.category?.parentPathString}"), leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { int parentId = widget.category?.parentId ?? -1; diff --git a/lib/widget/part/category_list.dart b/lib/widget/part/category_list.dart index 41442d9..ced2783 100644 --- a/lib/widget/part/category_list.dart +++ b/lib/widget/part/category_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -96,7 +97,7 @@ class _PaginatedPartCategoryListState return ListTile( title: Text(category.name), subtitle: Text(category.pathstring), - trailing: Text("${category.partcount}"), + trailing: LargeText("${category.partcount}", size: 14), leading: category.customIcon == null ? null : Icon(category.customIcon), onTap: () { category.goToDetailPage(context); diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index fa8e450..5d59aed 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -14,6 +14,7 @@ import "package:inventree/labels.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/part/bom_list.dart"; import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/notes_widget.dart"; @@ -334,6 +335,7 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().templatePart), subtitle: Text(parentPart!.fullname), leading: api.getImage(parentPart!.thumbnail, width: 32, height: 32), + trailing: LinkIcon(), onTap: () { parentPart?.goToDetailPage(context); }, @@ -348,6 +350,7 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().partCategory), subtitle: Text("${part.categoryName}"), leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { if (part.categoryId > 0) { showLoadingOverlay(); @@ -385,7 +388,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().variants), leading: Icon(TablerIcons.versions, color: COLOR_ACTION), - trailing: Text(variantCount.toString()), + trailing: LinkIcon(text: variantCount.toString()), onTap: () { Navigator.push( context, @@ -405,10 +408,7 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), leading: Icon(TablerIcons.packages), - trailing: Text( - part.stockString(), - style: TextStyle(fontWeight: FontWeight.bold), - ), + trailing: LargeText(part.stockString()), ), ); @@ -422,11 +422,11 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().partPricing), - leading: Icon(TablerIcons.currency_dollar, color: COLOR_ACTION), - trailing: Text( + subtitle: Text( pricing.isNotEmpty ? pricing : L10().noPricingAvailable, - style: TextStyle(fontWeight: FontWeight.bold), ), + leading: Icon(TablerIcons.currency_dollar, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -448,7 +448,7 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().onOrder), subtitle: Text(L10().onOrderDetails), leading: Icon(TablerIcons.shopping_cart), - trailing: Text("${part.onOrderString}"), + trailing: LargeText("${part.onOrderString}"), onTap: () { // TODO - Order views }, @@ -463,7 +463,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().billOfMaterials), leading: Icon(TablerIcons.list_tree, color: COLOR_ACTION), - trailing: Text(bomCount.toString()), + trailing: LinkIcon(text: bomCount.toString()), onTap: () { Navigator.push( context, @@ -482,9 +482,9 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().building), leading: Icon(TablerIcons.tools), - trailing: Text("${simpleNumberString(part.building)}"), + trailing: LargeText("${simpleNumberString(part.building)}"), onTap: () { - // TODO + // TODO: List of active build orders? }, ), ); @@ -498,7 +498,7 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().usedIn), subtitle: Text(L10().usedInDetails), leading: Icon(TablerIcons.stack_2, color: COLOR_ACTION), - trailing: Text(usedInCount.toString()), + trailing: LinkIcon(text: usedInCount.toString()), onTap: () { Navigator.push( context, @@ -543,9 +543,9 @@ class _PartDisplayState extends RefreshableState { title: Text(L10().usedIn), subtitle: Text(L10().usedInDetails), leading: Icon(TablerIcons.sitemap), - trailing: Text("${part.usedInCount}"), + trailing: LargeText("${part.usedInCount}"), onTap: () { - // TODO + // TODO: Show assemblies which use this part }, ), ); @@ -557,7 +557,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().suppliers), leading: Icon(TablerIcons.building_factory, color: COLOR_ACTION), - trailing: Text("${part.supplierCount}"), + trailing: LinkIcon(text: "${part.supplierCount}"), onTap: () { Navigator.push( context, @@ -577,7 +577,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().notes), leading: Icon(TablerIcons.note, color: COLOR_ACTION), - trailing: Text(""), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -591,7 +591,9 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().attachments), leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), onTap: () { Navigator.push( context, diff --git a/lib/widget/part/part_list.dart b/lib/widget/part/part_list.dart index e454522..3f219b5 100644 --- a/lib/widget/part/part_list.dart +++ b/lib/widget/part/part_list.dart @@ -5,6 +5,7 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -121,10 +122,7 @@ class _PaginatedPartListState extends PaginatedSearchState { return ListTile( title: Text(part.fullname), subtitle: Text(part.description), - trailing: Text( - part.stockString(), - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), + trailing: LargeText(part.stockString()), leading: InvenTreeAPI().getThumbnail(part.thumbnail), onTap: () { part.goToDetailPage(context); diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index cd53b82..d9c5ad5 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -42,7 +42,7 @@ mixin BaseWidgetProperties { // Override getTiles to replace the internal context return ListView( physics: AlwaysScrollableScrollPhysics(), - children: getTiles(context), + children: [Divider(), ...getTiles(context)], ); } diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 8c1a681..7719724 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -10,6 +10,7 @@ import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/preferences.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/stock/location_list.dart"; import "package:inventree/widget/progress.dart"; @@ -341,6 +342,7 @@ class _LocationDisplayState extends RefreshableState { title: Text(L10().parentLocation), subtitle: Text("${location!.parentPathString}"), leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { int parentId = location?.parentId ?? -1; diff --git a/lib/widget/stock/location_list.dart b/lib/widget/stock/location_list.dart index 1fc8032..a27182d 100644 --- a/lib/widget/stock/location_list.dart +++ b/lib/widget/stock/location_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -86,7 +87,7 @@ class _PaginatedStockLocationListState return ListTile( title: Text(location.name), subtitle: Text(location.pathstring), - trailing: Text("${location.itemcount}"), + trailing: LargeText("${location.itemcount}", size: 14), leading: location.customIcon == null ? null : Icon(location.customIcon), onTap: () { location.goToDetailPage(context); diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index c6996bc..e91bd98 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -18,9 +18,9 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/part.dart"; -import "package:inventree/widget/company/supplier_part_detail.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; @@ -490,14 +490,11 @@ class _StockItemDisplayState extends RefreshableState { Widget? trailing; if (!widget.item.isInStock) { - trailing = Text(L10().unavailable, style: TextStyle(color: COLOR_DANGER)); + trailing = LargeText(L10().unavailable, color: COLOR_DANGER); } else if (!widget.item.isSerialized()) { - trailing = Text( + trailing = LargeText( widget.item.quantityString(), - style: TextStyle( - fontSize: 20, - color: api.StockStatus.color(widget.item.status), - ), + color: api.StockStatus.color(widget.item.status), ); } @@ -518,7 +515,7 @@ class _StockItemDisplayState extends RefreshableState { } } }, - //trailing: Text(item.serialOrQuantityDisplay()), + //trailing: LargeText(item.serialOrQuantityDisplay()), ), ); } @@ -546,6 +543,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().stockLocation), subtitle: Text("${widget.item.locationPathString}"), leading: Icon(TablerIcons.location, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () async { if (widget.item.locationId > 0) { showLoadingOverlay(); @@ -587,7 +585,7 @@ class _StockItemDisplayState extends RefreshableState { ? Text(L10().quantityAvailable) : Text(L10().quantity), leading: Icon(TablerIcons.packages), - trailing: Text("${widget.item.quantityString()}"), + trailing: LargeText("${widget.item.quantityString()}"), ), ); } @@ -613,9 +611,9 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().status), leading: Icon(TablerIcons.help_circle), - trailing: Text( + trailing: LargeText( api.StockStatus.label(widget.item.status), - style: TextStyle(color: api.StockStatus.color(widget.item.status)), + color: api.StockStatus.color(widget.item.status), ), ), ); @@ -627,10 +625,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), leading: Icon(TablerIcons.building, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail( - widget.item.supplierImage, - hideIfNull: true, - ), + trailing: LinkIcon(), onTap: () async { showLoadingOverlay(); var sp = await InvenTreeSupplierPart().get( @@ -638,12 +633,7 @@ class _StockItemDisplayState extends RefreshableState { ); hideLoadingOverlay(); if (sp is InvenTreeSupplierPart) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(sp), - ), - ); + sp.goToDetailPage(context); } }, ), @@ -667,9 +657,11 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().salesOrder), - subtitle: Text(salesOrder?.description ?? ""), + subtitle: Text( + salesOrder?.reference ?? salesOrder?.description ?? "", + ), leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), - trailing: Text(salesOrder?.reference ?? ""), + trailing: LinkIcon(), onTap: () { salesOrder?.goToDetailPage(context); }, @@ -681,9 +673,9 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().customer), - subtitle: Text(customer?.description ?? ""), + subtitle: Text("${customer?.name} - ${customer?.description}"), leading: Icon(TablerIcons.building_store, color: COLOR_ACTION), - trailing: Text(customer?.name ?? ""), + trailing: LinkIcon(), onTap: () { customer?.goToDetailPage(context); }, @@ -741,7 +733,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().lastUpdated), - subtitle: Text(widget.item.updatedDateString), + trailing: LargeText(widget.item.updatedDateString), leading: Icon(TablerIcons.calendar), ), ); @@ -775,7 +767,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().testResults), leading: Icon(TablerIcons.list_check, color: COLOR_ACTION), - trailing: Text("${widget.item.testResultCount}"), + trailing: LinkIcon(text: "${widget.item.testResultCount}"), onTap: () { Navigator.push( context, @@ -795,7 +787,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().purchasePrice), leading: Icon(TablerIcons.currency_dollar), - trailing: Text( + trailing: LargeText( renderCurrency( widget.item.purchasePrice, widget.item.purchasePriceCurrency, @@ -812,7 +804,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().history), leading: Icon(TablerIcons.history, color: COLOR_ACTION), - trailing: Text("${widget.item.trackingItemCount}"), + trailing: LinkIcon(text: "${widget.item.trackingItemCount}"), onTap: () { Navigator.push( context, @@ -832,6 +824,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().notes), leading: Icon(TablerIcons.note, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -845,7 +838,9 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().attachments), leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), onTap: () { Navigator.push( context, diff --git a/lib/widget/stock/stock_list.dart b/lib/widget/stock/stock_list.dart index e65f7ab..8e6e89d 100644 --- a/lib/widget/stock/stock_list.dart +++ b/lib/widget/stock/stock_list.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/stock.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; @@ -130,16 +131,10 @@ class _PaginatedStockItemListState title: Text("${item.partName}"), subtitle: Text(item.locationPathString), leading: InvenTreeAPI().getThumbnail(item.partThumbnail), - trailing: SizedBox( - width: 48, - child: Text( - "${item.displayQuantity}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: InvenTreeAPI().StockStatus.color(item.status), - ), - ), + trailing: LargeText( + item.displayQuantity, + size: 14, + color: InvenTreeAPI().StockStatus.color(item.status), ), onTap: () { item.goToDetailPage(context); From a2e27e7a8aab294cf9d3f01c248cc77aff54d795 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 5 Jul 2025 09:27:37 +1000 Subject: [PATCH 690/746] New Crowdin updates (#678) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++++ lib/l10n/da_DK/app_da_DK.arb | 4 ++++ lib/l10n/de_DE/app_de_DE.arb | 4 ++++ lib/l10n/el_GR/app_el_GR.arb | 4 ++++ lib/l10n/es_ES/app_es_ES.arb | 4 ++++ lib/l10n/es_MX/app_es_MX.arb | 4 ++++ lib/l10n/et_EE/app_et_EE.arb | 4 ++++ lib/l10n/fa_IR/app_fa_IR.arb | 4 ++++ lib/l10n/fi_FI/app_fi_FI.arb | 4 ++++ lib/l10n/fr_FR/app_fr_FR.arb | 4 ++++ lib/l10n/he_IL/app_he_IL.arb | 4 ++++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++++ lib/l10n/id_ID/app_id_ID.arb | 4 ++++ lib/l10n/it_IT/app_it_IT.arb | 4 ++++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++++ lib/l10n/nl_NL/app_nl_NL.arb | 4 ++++ lib/l10n/no_NO/app_no_NO.arb | 4 ++++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++++ lib/l10n/pt_PT/app_pt_PT.arb | 4 ++++ lib/l10n/ro_RO/app_ro_RO.arb | 4 ++++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++++ lib/l10n/th_TH/app_th_TH.arb | 4 ++++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++++ lib/l10n/zh_CN/app_zh_CN.arb | 4 ++++ lib/l10n/zh_TW/app_zh_TW.arb | 4 ++++ 38 files changed, 152 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 7b507d1..ae54712 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "أدخل كلمة المرور", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index fce6456..94f4a3c 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 08611b5..159e3f6 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Upravit položku", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Zadejte heslo", "@enterPassword": {}, "enterUsername": "Zadejte uživatelské jméno", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Vyžadováno oprávnění", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Tisk štítků", "@printLabel": {}, "plugin": "Zásuvný modul", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 6ea4439..ee25a22 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Rediger Linjeelement", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Indtast adgangskode", "@enterPassword": {}, "enterUsername": "Indtast brugernavn", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 21cefe5..5ba7dd1 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Position bearbeiten", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Passwort eingeben", "@enterPassword": {}, "enterUsername": "Benutzername eingeben", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Berechtigung erforderlich", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Label drucken", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 2aaba50..f06a960 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 7901bd3..a110be4 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Editar Ítem de Línea", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Introduzca contraseña", "@enterPassword": {}, "enterUsername": "Introduzca su nombre de usuario", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Se requiere autorización", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Imprimir etiqueta", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 2a70f57..8efb8a7 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Editar artículo de línea", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Introducir contraseña", "@enterPassword": {}, "enterUsername": "Introducir usuario", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Se requiere autorización", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Imprimir etiqueta", "@printLabel": {}, "plugin": "Complemento", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index f151102..0449a7f 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Sisesta parool", "@enterPassword": {}, "enterUsername": "Sisesta kasutajanimi", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Prindi silt", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 1b2b7f4..d14c414 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "ویرایش ایتم خط", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "رمز عبور را وارد کنید", "@enterPassword": {}, "enterUsername": "نام کاربری را وارد کنید", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "نیازمند مجوز", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "پرینت برچسب", "@printLabel": {}, "plugin": "افزونه", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index e01e387..2f06b86 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Muokkaa listan riviä", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Syötä salasana", "@enterPassword": {}, "enterUsername": "Syötä käyttäjätunnus", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Käyttöoikeus vaaditaan", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Laajennus", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 3b01569..aa6d9f2 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Modifier l'élément de la ligne", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Saisissez le mot de passe", "@enterPassword": {}, "enterUsername": "Saisissez le nom d'utilisateur", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Autorisation requise", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Imprimer l'étiquette", "@printLabel": {}, "plugin": "Extension", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 84f525a..26e9ff1 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "ערוך פריט", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "הזן סיסמה", "@enterPassword": {}, "enterUsername": "הזן שם משתמש", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "נדרשת הרשאה", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "הדפס תווית", "@printLabel": {}, "plugin": "תוסף", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 1dcb0e9..b30109d 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index ab5d544..c2a62f5 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Sortétel szerkesztése", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Jelszó megadása", "@enterPassword": {}, "enterUsername": "Felhasználó megadása", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Engedély szükséges", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Címke nyomtatása", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 2638e8e..84fda02 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit item baris", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Masukkan Kata Sandi", "@enterPassword": {}, "enterUsername": "Masukkan Nama Pengguna", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Izin Diperlukan", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Cetak Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 6cf3242..f46cd1d 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Modifica linea elemento", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Inserire la password", "@enterPassword": {}, "enterUsername": "Inserisci nome utente", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Autorizzazione necessaria", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Stampa Etichetta", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index a14fbcd..e2b90f7 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "ラインアイテムの編集", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "パスワードを入力してください", "@enterPassword": {}, "enterUsername": "ユーザー名を入力してください", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "権限が必要です", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "ラベルを印刷", "@printLabel": {}, "plugin": "プラグイン", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 7afb9eb..85b8106 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 09e66ca..ceff316 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 3e7b10c..2f2a3c0 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Ievadiet paroli", "@enterPassword": {}, "enterUsername": "Ievadiet lietotājvārdu", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index dd2904c..0b0a76b 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Voorraadartikel bewerken", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Wachtwoord invoeren", "@enterPassword": {}, "enterUsername": "Gebruikersnaam invoeren", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Toestemming Vereist", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index c7272c0..3bbb36c 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Rediger ordrelinje", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Skriv inn passord", "@enterPassword": {}, "enterUsername": "Skriv inn brukernavn", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Tillatelse kreves", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Skriv ut etikett", "@printLabel": {}, "plugin": "Utvidelse", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 4cf8d50..dc9bd4f 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edytuj element", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Wprowadź hasło", "@enterPassword": {}, "enterUsername": "Wprowadź nazwę użytkownika", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Wymagane uprawnienia", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Drukuj etykietę", "@printLabel": {}, "plugin": "Wtyczka", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index fa44fc2..d6e5d01 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Editar Item de Linha", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, "enterUsername": "Informe o usuário", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permissão Necessária", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Imprimir Etiqueta", "@printLabel": {}, "plugin": "Extensões", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 0cc3de9..19f0b14 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Editar item de linha", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, "enterUsername": "Inserir usuário", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index f4eecda..3041b6d 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Editare element rând", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Introdu parola", "@enterPassword": {}, "enterUsername": "Introdu numele de utilizator", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permisiune necesară", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Printati Eticheta", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 4b50d7a..494c92c 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Изменить позицию", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Введите пароль", "@enterPassword": {}, "enterUsername": "Введите имя пользователя", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Требуется разрешение", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Печать этикетки", "@printLabel": {}, "plugin": "Плагин", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 61646a8..9ec2d50 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 5e36427..e3b2c50 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index a3e6c69..d4f8215 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Izmeni stavku porudžbine", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Unesi lozinku", "@enterPassword": {}, "enterUsername": "Unesi korisničko ime", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 16f377e..ca1b2a4 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Redigera radobjekt", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Ange lösenord", "@enterPassword": {}, "enterUsername": "Ange användarnamn", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Särskilda behörigheter krävs", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Skriv ut etikett", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index d9a6323..9f8f01b 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Edit Line Item", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Enter password", "@enterPassword": {}, "enterUsername": "Enter username", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 2e813b2..9023d19 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Satır Ögesini Düzenle", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Şifrenizi girin", "@enterPassword": {}, "enterUsername": "Kullanıcı adını girin", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "İzin Gerekli", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Etiket Yazdır", "@printLabel": {}, "plugin": "Eklenti", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 4892724..85cf8c2 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Редагувати рядок", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Введіть пароль", "@enterPassword": {}, "enterUsername": "Введіть ім'я користувача", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Потрібен дозвіл", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "Друк ярлика", "@printLabel": {}, "plugin": "Модуль", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index def909c..0dd51ae 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "Sửa dòng sản phẩm", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "Nhập mật khẩu", "@enterPassword": {}, "enterUsername": "Nhập tên người dùng", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "Yêu cầu quyền truy cập", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "In nhãn tem", "@printLabel": {}, "plugin": "Plugin", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 6037058..e1cf2b9 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "编辑行项目", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "输入密码", "@enterPassword": {}, "enterUsername": "输入用户名", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "需要授权:", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "打印标签", "@printLabel": {}, "plugin": "插件", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index bd7c5e1..58954c0 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -268,6 +268,8 @@ "@editItem": {}, "editLineItem": "編輯行項目", "@editLineItem": {}, + "email": "Email", + "@email": {}, "enterPassword": "輸入密碼", "@enterPassword": {}, "enterUsername": "輸入使用者名稱", @@ -626,6 +628,8 @@ "@permissionAccountDenied": {}, "permissionRequired": "需要授權:", "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, "printLabel": "打印標籤", "@printLabel": {}, "plugin": "插件", From fe30b4ee16f0687ea9f8a020486be6d2bc51c05d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 5 Jul 2025 09:59:31 +1000 Subject: [PATCH 691/746] Add icons for settings views (#679) --- lib/settings/about.dart | 6 ++++++ lib/settings/settings.dart | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/settings/about.dart b/lib/settings/about.dart index ce5ef69..bc8c345 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -5,6 +5,7 @@ import "package:inventree/settings/release.dart"; import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/l10.dart"; @@ -182,6 +183,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { _releaseNotes(context); }, @@ -193,6 +195,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().credits), subtitle: Text(L10().appCredits), leading: Icon(TablerIcons.balloon, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { _credits(context); }, @@ -204,6 +207,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().documentation), subtitle: Text(DOCS_URL), leading: Icon(TablerIcons.book, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { _openDocs(); }, @@ -215,6 +219,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().translate), subtitle: Text(L10().translateHelp), leading: Icon(TablerIcons.language, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { _translate(); }, @@ -226,6 +231,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().reportBug), subtitle: Text(L10().reportBugDescription), leading: Icon(TablerIcons.bug, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { _reportBug(context); }, diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 12b51af..3815127 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -14,6 +14,8 @@ import "package:inventree/settings/part_settings.dart"; import "package:inventree/settings/purchase_order_settings.dart"; import "package:inventree/settings/sales_order_settings.dart"; +import "package:inventree/widget/link_icon.dart"; + // InvenTree settings view class InvenTreeSettingsWidget extends StatefulWidget { @override @@ -50,6 +52,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().server), subtitle: Text(L10().configureServer), leading: Icon(TablerIcons.server, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -64,6 +67,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), leading: Icon(TablerIcons.settings, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -77,6 +81,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), leading: Icon(TablerIcons.home, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -90,6 +95,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().barcodes), subtitle: Text(L10().barcodeSettings), leading: Icon(TablerIcons.barcode, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -103,6 +109,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().part), subtitle: Text(L10().partSettings), leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -116,6 +123,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().purchaseOrder), subtitle: Text(L10().purchaseOrderSettings), leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -130,6 +138,7 @@ class _InvenTreeSettingsState extends State { title: Text(L10().salesOrder), subtitle: Text(L10().salesOrderSettings), leading: Icon(TablerIcons.truck, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { Navigator.push( context, @@ -143,6 +152,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().about), leading: Icon(TablerIcons.info_circle, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: _about, ), ], From 7ad10fea608dc48243cbf76ce57e28606eb79cea Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 8 Jul 2025 08:37:47 +1000 Subject: [PATCH 692/746] New translations app_en.arb (Italian) (#680) --- lib/l10n/it_IT/app_it_IT.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index f46cd1d..4e47bfd 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Autorizzazione necessaria", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefono", "@phone": {}, "printLabel": "Stampa Etichetta", "@printLabel": {}, From 292e96b799973f8cf9064c2b04788ed90a919bc2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 27 Jul 2025 13:49:36 +1000 Subject: [PATCH 693/746] New Crowdin updates (#681) * New translations app_en.arb (Turkish) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Hungarian) * New translations app_en.arb (German) * New translations app_en.arb (Turkish) * New translations app_en.arb (Thai) * New translations app_en.arb (Spanish) --- lib/l10n/de_DE/app_de_DE.arb | 28 +++++++------- lib/l10n/es_ES/app_es_ES.arb | 72 ++++++++++++++++++------------------ lib/l10n/hu_HU/app_hu_HU.arb | 48 ++++++++++++------------ lib/l10n/th_TH/app_th_TH.arb | 2 +- lib/l10n/tr_TR/app_tr_TR.arb | 34 ++++++++--------- 5 files changed, 92 insertions(+), 92 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 5ba7dd1..5c63555 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Quadratisch (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Bestand zuweisen", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "Danksagungen", "@credits": {}, - "crop": "Crop", + "crop": "Zuschneiden", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Bild zuschneiden", "@cropImage": {}, "customer": "Kunde", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Dokumentation", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Download abgeschlossen", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Fehler beim Herunterladen des Bildes", "@downloadError": {}, "downloading": "Datei wird heruntergeladen", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Position bearbeiten", "@editLineItem": {}, - "email": "Email", + "email": "E-Mail", "@email": {}, "enterPassword": "Passwort eingeben", "@enterPassword": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Keine Ergebnisse", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Kein Bild verfügbar", "@noImageAvailable": {}, "noSubcategories": "Keine Unter-Kategorien", "@noSubcategories": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Berechtigung erforderlich", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, "printLabel": "Label drucken", "@printLabel": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Neu laden", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "90° im Uhrzeigersinn drehen", "@rotateClockwise": {}, "refreshing": "Aktualisiere", "@refreshing": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Datei hochgeladen", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Bild hochladen", "@uploadImage": {}, "usedIn": "Verwendet in", "@usedIn": {}, @@ -1110,7 +1110,7 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, - "price": "Price", + "price": "Preis", "@price": {}, "priceRange": "Price Range", "@priceRange": {}, @@ -1134,7 +1134,7 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Währung", "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {}, @@ -1144,8 +1144,8 @@ "@noPricingDataFound": {}, "deleteImageConfirmation": "Are you sure you want to delete this image?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Bild löschen", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Bild löschen", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index a110be4..102ee6f 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Cuadrado (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Asignar stock", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "Créditos", "@credits": {}, - "crop": "Crop", + "crop": "Recortar", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Recortar la imagen", "@cropImage": {}, "customer": "Cliente", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Documentación", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Descarga completa", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Error al descargar la imagen", "@downloadError": {}, "downloading": "Descargando archivo", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Editar Ítem de Línea", "@editLineItem": {}, - "email": "Email", + "email": "Correo electrónico", "@email": {}, "enterPassword": "Introduzca contraseña", "@enterPassword": {}, @@ -302,9 +302,9 @@ "@expiryExpired": {}, "expiryStale": "Obsoleto", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Elemento extra de línea", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Elementos extra de línea", "@extraLineItems": {}, "feedback": "Comentarios", "@feedback": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Sin resultados", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "No hay imagen disponible", "@noImageAvailable": {}, "noSubcategories": "No hay subcategorías", "@noSubcategories": {}, @@ -594,9 +594,9 @@ "@partsNone": {}, "partNoResults": "No hay piezas que coincidan", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Precio de parte", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Mostrar información de precios de parte", "@pricingSettingDetail": {}, "partSettings": "Configuración de partes", "@partSettings": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Se requiere autorización", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Teléfono", "@phone": {}, "printLabel": "Imprimir etiqueta", "@printLabel": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Refrescar", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Girar 90° en sentido horario", "@rotateClockwise": {}, "refreshing": "Actualizando", "@refreshing": {}, @@ -916,7 +916,7 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Reproducir tono audible en error del servidor", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Fecha de inicio", "@startDate": {}, "status": "Estado", "@status": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Referencia del proveedor", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Cambiar Cámara", "@switchCamera": {}, "takePicture": "Hacer una foto", "@takePicture": {}, @@ -1040,7 +1040,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Linterna", "@toggleTorch": {}, "tokenError": "Error de Token", "@tokenError": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Archivo subido", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Subir Imagen", "@uploadImage": {}, "usedIn": "Usado En", "@usedIn": {}, @@ -1110,42 +1110,42 @@ "@viewSupplierPart": {}, "website": "Sitio Web", "@website": {}, - "price": "Price", + "price": "Precio", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Rango de precios", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Reemplazo del precio mínimo", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Reemplazo del precio máximo", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Precio de Venta", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Historial de ventas", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Precio del Proveedor", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Coste BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Coste Interno", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Coste de variante", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Precio global", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Anulaciones de precios", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Divisa", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Diferenciales de precios", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "No hay precios disponibles", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "No se encontraron datos de precios para esta parte", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "¿Estas seguro de eliminar esta imagen?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Eliminar imagen", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Eliminar imagen", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index c2a62f5..7abe54a 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Négyzetes (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Készlet foglalása", "@allocateStock": {}, @@ -178,7 +178,7 @@ "@companyUpdated": {}, "companies": "Cégek", "@companies": {}, - "completionDate": "Completion Date", + "completionDate": "Befejezés dátuma", "@completionDate": {}, "configureServer": "Kiszolgáló beállítások konfigurálása", "@configureServer": {}, @@ -198,9 +198,9 @@ }, "credits": "Közreműködők", "@credits": {}, - "crop": "Crop", + "crop": "Körbevágás", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Kép körbevágása", "@cropImage": {}, "customer": "Vevő", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Dokumentáció", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Letöltés befejezve", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Hiba a kép letöltése közben", "@downloadError": {}, "downloading": "Fájl letöltése", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Sortétel szerkesztése", "@editLineItem": {}, - "email": "Email", + "email": "E-mail", "@email": {}, "enterPassword": "Jelszó megadása", "@enterPassword": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Engedély szükséges", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefonszám", "@phone": {}, "printLabel": "Címke nyomtatása", "@printLabel": {}, @@ -678,7 +678,7 @@ "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Enable purchase order functionality", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Kamera gyorsbillentyű", "@purchaseOrderShowCamera": {}, "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", "@purchaseOrderShowCameraDetail": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Frissítés", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Forgatás 90 fokkal óramutató járásával megegyező irányban", "@rotateClockwise": {}, "refreshing": "Frissítés...", "@refreshing": {}, @@ -800,7 +800,7 @@ "@salesOrder": {}, "salesOrders": "Vevői rendelések", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Vevői rendelések engedélyezése", "@salesOrderEnable": {}, "salesOrderEnableDetail": "Enable sales order functionality", "@salesOrderEnableDetail": {}, @@ -916,7 +916,7 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Kezdő dátum", "@startDate": {}, "status": "Állapot", "@status": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Beszállítói azonosító", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Kamera váltása", "@switchCamera": {}, "takePicture": "Fotó készítése", "@takePicture": {}, @@ -1040,7 +1040,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Zseblámpa", "@toggleTorch": {}, "tokenError": "Token hiba", "@tokenError": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Fájl feltöltve", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Kép feltöltése", "@uploadImage": {}, "usedIn": "Felhasználva ebben", "@usedIn": {}, @@ -1110,21 +1110,21 @@ "@viewSupplierPart": {}, "website": "Weboldal", "@website": {}, - "price": "Price", + "price": "Ár", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Ártartomány", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Eladási ár", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Eladási előzmények", "@saleHistory": {}, "supplierPricing": "Supplier Pricing", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Alkatrészjegyzék költség", "@bomCost": {}, "internalCost": "Internal Cost", "@internalCost": {}, @@ -1134,9 +1134,9 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Pénznem", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Ársávok", "@priceBreaks": {}, "noPricingAvailable": "No pricing available", "@noPricingAvailable": {}, @@ -1144,8 +1144,8 @@ "@noPricingDataFound": {}, "deleteImageConfirmation": "Are you sure you want to delete this image?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Kép törlése", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Kép törlése", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 9f8f01b..d69c076 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -156,7 +156,7 @@ "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "", "@cancelOrder": {}, "category": "Category", "@category": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 9023d19..f205182 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Kare (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Tahsisli stok", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "Katkıda Bulunanlar", "@credits": {}, - "crop": "Crop", + "crop": "Kırp", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Resmi Kırp", "@cropImage": {}, "customer": "Müşteri", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Dökümantasyon", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "İndirme Tamamlandı", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Görsel indirme hatası", "@downloadError": {}, "downloading": "Dosya indiriliyor", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Satır Ögesini Düzenle", "@editLineItem": {}, - "email": "Email", + "email": "E-posta", "@email": {}, "enterPassword": "Şifrenizi girin", "@enterPassword": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Sonuç Yok", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Kullanılabilir resim yok", "@noImageAvailable": {}, "noSubcategories": "Alt kategori yok", "@noSubcategories": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "İzin Gerekli", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon Numarası", "@phone": {}, "printLabel": "Etiket Yazdır", "@printLabel": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Yenile", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Saat yönünde 90° Döndür", "@rotateClockwise": {}, "refreshing": "Yenileniyor", "@refreshing": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Dosya yüklendi", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Resim Yükleyin", "@uploadImage": {}, "usedIn": "Burada Kullanıldı", "@usedIn": {}, @@ -1114,9 +1114,9 @@ "@price": {}, "priceRange": "Fiyat Aralığı", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Minimum Fiyat Geçersiz Kılma", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Maksimum Fiyat Geçersiz Kılma", "@priceOverrideMax": {}, "salePrice": "Satış Fiyatı", "@salePrice": {}, @@ -1132,20 +1132,20 @@ "@variantCost": {}, "overallPricing": "Genel Fiyatlandırma", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Fiyatlandırma Genel Bakış", "@pricingOverrides": {}, "currency": "Para Birimi", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Fiyat Aralığı", "@priceBreaks": {}, "noPricingAvailable": "Fiyatlandırma mevcut değil", "@noPricingAvailable": {}, "noPricingDataFound": "Bu parça için fiyatlandırma verisi bulunamadı", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Bu resmi silmek istediğinizden emin misiniz?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Görüntüyü Sil", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Resmi sil", "@deleteImage": {} } \ No newline at end of file From bda9a9befbdd46d1e904a429a301bc1583275252 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 3 Aug 2025 09:45:21 +1000 Subject: [PATCH 694/746] New Crowdin updates (#682) * New translations app_en.arb (Polish) * New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 +- lib/l10n/pl_PL/app_pl_PL.arb | 44 ++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 5c63555..c4aecfd 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -594,7 +594,7 @@ "@partsNone": {}, "partNoResults": "Keine Teile entsprechen der Anfrage", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Teilbepreisung", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index dc9bd4f..3248207 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -36,7 +36,7 @@ "@appDetails": {}, "allocated": "Przydzielono", "@allocated": {}, - "aspectRatio16x9": "16:9", + "aspectRatio16x9": "", "@aspectRatio16x9": {}, "aspectRatio3x2": "3:2", "@aspectRatio3x2": {}, @@ -146,7 +146,7 @@ "@build": {}, "building": "Budowanie", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Nie można otworzyć kamery", "@cameraCreationError": {}, "cameraInternal": "Kamera wewnętrzna", "@cameraInternal": {}, @@ -168,7 +168,7 @@ "@categoryUpdated": {}, "company": "Firma", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Dodaj firmę", "@companyAdd": {}, "companyEdit": "Edytuj Firmę", "@companyEdit": {}, @@ -178,7 +178,7 @@ "@companyUpdated": {}, "companies": "Firmy", "@companies": {}, - "completionDate": "Completion Date", + "completionDate": "Data ukończenia", "@completionDate": {}, "configureServer": "Konfiguruj ustawienia serwera", "@configureServer": {}, @@ -198,9 +198,9 @@ }, "credits": "Podziękowania", "@credits": {}, - "crop": "Crop", + "crop": "Wytnij", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Przytnij obraz", "@cropImage": {}, "customer": "Klient", "@customer": {}, @@ -230,7 +230,7 @@ "@deleteSuccess": {}, "description": "Opis", "@description": {}, - "destination": "Destination", + "destination": "Cel:", "@destination": {}, "destroyed": "Zniszczony", "@destroyed": {}, @@ -240,9 +240,9 @@ }, "documentation": "Dokumentacja", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Pobieranie ukończone", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Błąd podczas pobierania obrazu", "@downloadError": {}, "downloading": "Pobieranie Pliku", "@downloading": {}, @@ -250,7 +250,7 @@ "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Edytuj załącznik", "@editAttachment": {}, "editCategory": "Edytuj kategorię", "@editCategory": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Edytuj element", "@editLineItem": {}, - "email": "Email", + "email": "E-mail", "@email": {}, "enterPassword": "Wprowadź hasło", "@enterPassword": {}, @@ -296,9 +296,9 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Prześlij anonimowe raporty o błędach i dzienniki awarii", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Data ważności", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Termin minął", "@expiryExpired": {}, "expiryStale": "Stale", "@expiryStale": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Brak wyników", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Brak dostępnych obrazów", "@noImageAvailable": {}, "noSubcategories": "Brak podkategorii", "@noSubcategories": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Wymagane uprawnienia", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, "printLabel": "Drukuj etykietę", "@printLabel": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Identyfikator Dostawcy", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Przełącz aparat", "@switchCamera": {}, "takePicture": "Zrób zdjęcie", "@takePicture": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Plik przesłany", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Załaduj obraz", "@uploadImage": {}, "usedIn": "Użyte w", "@usedIn": {}, @@ -1110,17 +1110,17 @@ "@viewSupplierPart": {}, "website": "Strona WWW", "@website": {}, - "price": "Price", + "price": "Cena", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Zakres cen", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Cena sprzedaży", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Historia cen", "@saleHistory": {}, "supplierPricing": "Supplier Pricing", "@supplierPricing": {}, @@ -1146,6 +1146,6 @@ "@deleteImageConfirmation": {}, "deleteImageTooltip": "Delete Image", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Usuń obraz", "@deleteImage": {} } \ No newline at end of file From b7a9062e0be68df9e031887ba33e58cd74981d6a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 Aug 2025 21:16:04 +1000 Subject: [PATCH 695/746] New Crowdin updates (#683) * New translations app_en.arb (Hungarian) * New translations app_en.arb (German) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Czech) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 72 ++++++++++++++++++------------------ lib/l10n/de_DE/app_de_DE.arb | 26 ++++++------- lib/l10n/hu_HU/app_hu_HU.arb | 14 +++---- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 159e3f6..a651f02 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Čtverec (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Přidělit zásoby", "@allocateStock": {}, @@ -198,9 +198,9 @@ }, "credits": "Poděkování", "@credits": {}, - "crop": "Crop", + "crop": "Oříznout", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Oříznout obrázek", "@cropImage": {}, "customer": "Zákazník", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Dokumentace", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Stahování dokončeno", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Chyba při stahování obrázku", "@downloadError": {}, "downloading": "Stahování souboru", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Upravit položku", "@editLineItem": {}, - "email": "Email", + "email": "Mail", "@email": {}, "enterPassword": "Zadejte heslo", "@enterPassword": {}, @@ -302,9 +302,9 @@ "@expiryExpired": {}, "expiryStale": "Zastaralé", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Položka navíc", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Položky navíc", "@extraLineItems": {}, "feedback": "Komentář", "@feedback": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Žádné výsledky", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Obrázek není k dispozici", "@noImageAvailable": {}, "noSubcategories": "Žádná podkategorie", "@noSubcategories": {}, @@ -594,9 +594,9 @@ "@partsNone": {}, "partNoResults": "Žádné díly neodpovídají dotazu", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Cena dílu", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Zobrazit cenové informace dílu", "@pricingSettingDetail": {}, "partSettings": "Nastavení dílu", "@partSettings": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Vyžadováno oprávnění", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, "printLabel": "Tisk štítků", "@printLabel": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Obnovit", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Otočit o 90° po směru hodinových ručiček", "@rotateClockwise": {}, "refreshing": "Obnovuji", "@refreshing": {}, @@ -916,7 +916,7 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Přehrát zvuk při chybě serveru", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Počáteční datum", "@startDate": {}, "status": "Stav", "@status": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Kód dodavatele", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Přepnout kameru", "@switchCamera": {}, "takePicture": "Pořídit snímek", "@takePicture": {}, @@ -1040,7 +1040,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Rozsvítit baterku", "@toggleTorch": {}, "tokenError": "Chyba tokenu", "@tokenError": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Soubor nahrán", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Nahrát obrázek", "@uploadImage": {}, "usedIn": "Použito v", "@usedIn": {}, @@ -1110,42 +1110,42 @@ "@viewSupplierPart": {}, "website": "Webová stránka", "@website": {}, - "price": "Price", + "price": "Cena", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Cenový rozsah", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Přepsání minimální ceny", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Přepsání maximální ceny", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Prodejní cena", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Historie prodeje", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Cena dodavatele", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Náklady na BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Interní cena", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Náklad varianty", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Celková cena", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Cenový přehled", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Měna", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Cena sleva", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Žádné ceny nejsou k dispozici", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Pro tuto komponentu nebyly nalezeny žádné cenové údaje", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Opravdu chcete odstranit tento obrázek?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Smazat obrázek", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Smazat obrázek", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index c4aecfd..0a885a0 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -596,7 +596,7 @@ "@partNoResults": {}, "partPricing": "Teilbepreisung", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Zeige Zeitplanung für Teile", "@pricingSettingDetail": {}, "partSettings": "Teil-Einstellungen", "@partSettings": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Lieferanten-Referenz", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Kamera wechseln", "@switchCamera": {}, "takePicture": "Foto aufnehmen", "@takePicture": {}, @@ -1112,25 +1112,25 @@ "@website": {}, "price": "Preis", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Preisspanne", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Verkaufspreis", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Verkaufshistorie", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Zulieferer-Preise", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Stücklistenkosten", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Interne Kosten", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Variantenkosten", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Gesamt Preise", "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, @@ -1138,11 +1138,11 @@ "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Keine Preisinformation verfügbar", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Keine Preisdaten für diesen Teil gefunden", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Möchten Sie dieses Bild wirklich löschen?", "@deleteImageConfirmation": {}, "deleteImageTooltip": "Bild löschen", "@deleteImageTooltip": {}, diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 7abe54a..626d4e3 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -594,7 +594,7 @@ "@partsNone": {}, "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Alkatrész árazása", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, @@ -688,7 +688,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Beszerzési rendelés beállításai", "@purchaseOrderSettings": {}, "purchaseOrders": "Beszerzési rendelések", "@purchaseOrders": {}, @@ -802,13 +802,13 @@ "@salesOrders": {}, "salesOrderEnable": "Vevői rendelések engedélyezése", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Értékesítési rendés funkció aktiválása", "@salesOrderEnableDetail": {}, "salesOrderShowCamera": "Kamera gyorsbillentyű", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Képfeltöltés shortcut engedélyezése az értékesítési rendelés oldalon", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Értékesítési rendelés beállításai", "@salesOrderSettings": {}, "salesOrderCreate": "Új vevői rendelés", "@saleOrderCreate": {}, @@ -1126,9 +1126,9 @@ "@supplierPricing": {}, "bomCost": "Alkatrészjegyzék költség", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Belső költség", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Variáns költsége", "@variantCost": {}, "overallPricing": "Overall Pricing", "@overallPricing": {}, From 28701359da4871c6c3ee45fca01e33efa7dccc6e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 19 Aug 2025 11:14:07 +1000 Subject: [PATCH 696/746] New Crowdin updates (#684) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Ukrainian) --- lib/l10n/pl_PL/app_pl_PL.arb | 2 +- lib/l10n/pt_BR/app_pt_BR.arb | 98 ++++++++++++++++++------------------ lib/l10n/uk_UA/app_uk_UA.arb | 68 ++++++++++++------------- 3 files changed, 84 insertions(+), 84 deletions(-) diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 3248207..3bf7757 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -54,7 +54,7 @@ "@appSettingsDetails": {}, "assignedToMe": "", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Pokaż zlecenia, które zostały do mnie przypisane", "@assignedToMeDetail": {}, "attachments": "Załączniki", "@attachments": {}, diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index d6e5d01..62bc779 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Quadrado (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Estoque alocado", "@allocateStock": {}, @@ -52,9 +52,9 @@ "@appSettings": {}, "appSettingsDetails": "Configurar os parâmetros do App do InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Atribuído a mim", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Mostrar pedidos atribuídos a mim", "@assignedToMeDetail": {}, "attachments": "Anexos", "@attachments": {}, @@ -146,7 +146,7 @@ "@build": {}, "building": "Produzindo", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Não foi possível abrir o controle da câmera", "@cameraCreationError": {}, "cameraInternal": "Câmera Interna", "@cameraInternal": {}, @@ -168,7 +168,7 @@ "@categoryUpdated": {}, "company": "Companhia", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Adicionar Empresa", "@companyAdd": {}, "companyEdit": "Editar Empresa", "@companyEdit": {}, @@ -198,9 +198,9 @@ }, "credits": "Créditos", "@credits": {}, - "crop": "Crop", + "crop": "Recortar", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Cortar Imagem", "@cropImage": {}, "customer": "Cliente", "@customer": {}, @@ -210,9 +210,9 @@ "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Esquema de cores", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Selecionar esquema de cores", "@colorSchemeDetail": {}, "darkMode": "Modo Escuro", "@darkMode": {}, @@ -230,7 +230,7 @@ "@deleteSuccess": {}, "description": "Descrição", "@description": {}, - "destination": "Destination", + "destination": "Destino", "@destination": {}, "destroyed": "Destruído", "@destroyed": {}, @@ -240,9 +240,9 @@ }, "documentation": "Documentação", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Download concluído", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Erro ao baixar a imagem", "@downloadError": {}, "downloading": "Baixando arquivo", "@downloading": {}, @@ -250,7 +250,7 @@ "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Editar Anexo", "@editAttachment": {}, "editCategory": "Editar categoria", "@editCategory": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Editar Item de Linha", "@editLineItem": {}, - "email": "Email", + "email": "E-mail", "@email": {}, "enterPassword": "Digite a senha", "@enterPassword": {}, @@ -296,9 +296,9 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Enviar relatórios de erros anônimos e logs de falhas", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Data de validade", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Vencido", "@expiryExpired": {}, "expiryStale": "Stale", "@expiryStale": {}, @@ -446,7 +446,7 @@ "@itemInLocation": {}, "itemDeleted": "O item foi removido", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Item atualizado", "@itemUpdated": {}, "keywords": "Palavras chave", "@keywords": {}, @@ -456,9 +456,9 @@ "@labelPrintingDetail": {}, "labelTemplate": "Modelo de descricao", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Selecione o Modelo de Etiqueta", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Selecione a impressora de etiqueta", "@labelSelectPrinter": {}, "language": "Idioma", "@language": {}, @@ -502,9 +502,9 @@ "@link": {}, "lost": "Perdido", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Fabricante da peça", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Editar Fabricante de Peça", "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Número de Peça do Fabricante", "@manufacturerPartNumber": {}, @@ -530,7 +530,7 @@ "@noResponse": {}, "noResults": "Nenhum Resultado", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Nenhuma imagem disponível", "@noImageAvailable": {}, "noSubcategories": "Nenhuma subcategoria", "@noSubcategories": {}, @@ -594,7 +594,7 @@ "@partsNone": {}, "partNoResults": "Nenhuma peça corresponde a consulta", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Preço de Peça", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, @@ -628,7 +628,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Permissão Necessária", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefone", "@phone": {}, "printLabel": "Imprimir Etiqueta", "@printLabel": {}, @@ -674,13 +674,13 @@ "@purchaseOrderConfirmScan": {}, "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Habilitar Pedidos de Compra", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Habilitar funcionalidade de pedido de compra", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Atalho da Câmera", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Habilitar atalho para upload de imagem na tela de ordem de compra", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Ordem de Compra", "@purchaseOrder": {}, @@ -688,7 +688,7 @@ "@purchaseOrderCreate": {}, "purchaseOrderEdit": "Editar ordem de compra", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Configurações do Pedido de Compra", "@purchaseOrderSettings": {}, "purchaseOrders": "Ordens de compras", "@purchaseOrders": {}, @@ -724,7 +724,7 @@ "@reference": {}, "refresh": "Atualizar", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Girar 90° no sentido horário", "@rotateClockwise": {}, "refreshing": "Atualizando", "@refreshing": {}, @@ -744,7 +744,7 @@ "@reportBug": {}, "reportBugDescription": "Adicionar reporte de erro (conta no github)", "@reportBugDescription": {}, - "responsible": "Responsible", + "responsible": "Responsável", "@responsible": {}, "results": "Resultado", "@results": {}, @@ -800,15 +800,15 @@ "@salesOrder": {}, "salesOrders": "Pedido de vendas", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Habilitar Pedidos de Vendas", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Habilitar funcionalidade de ordem de venda", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Atalho da Câmera", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Habilitar atalho para upload de imagem na tela de ordem de venda", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Configurações do Pedido de Venda", "@salesOrderSettings": {}, "salesOrderCreate": "Novo Pedido de Venda", "@saleOrderCreate": {}, @@ -916,7 +916,7 @@ "@soundOnBarcodeAction": {}, "soundOnServerError": "Tocar tom audível no erro do servidor", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Data Inicial", "@startDate": {}, "status": "Estado", "@status": {}, @@ -1006,7 +1006,7 @@ "@suppliers": {}, "supplierReference": "Referencia do fornecedor", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Mudar Câmera", "@switchCamera": {}, "takePicture": "Tirar foto", "@takePicture": {}, @@ -1068,9 +1068,9 @@ "@translate": {}, "translateHelp": "Ajude a traduzir", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Indisponível", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Item não está disponível", "@unavailableDetail": {}, "unitPrice": "Preço unitário", "@unitPrice": {}, @@ -1084,7 +1084,7 @@ "@uploadFailed": {}, "uploadSuccess": "Arquivo adicionado com sucesso", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Enviar imagem", "@uploadImage": {}, "usedIn": "Usado em", "@usedIn": {}, @@ -1110,17 +1110,17 @@ "@viewSupplierPart": {}, "website": "Página Web", "@website": {}, - "price": "Price", + "price": "Preço", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Faixa de Preço", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Preço de Venda", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Histórico de Vendas", "@saleHistory": {}, "supplierPricing": "Supplier Pricing", "@supplierPricing": {}, @@ -1134,7 +1134,7 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Moeda", "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {}, @@ -1142,10 +1142,10 @@ "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Tem certeza de que deseja excluir essa imagem?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Excluir Imagem", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Excluir Imagem", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 85cf8c2..39666bb 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -30,7 +30,7 @@ "@address": {}, "appAbout": "Про InvenTree", "@appAbout": {}, - "appCredits": "Additional app credits", + "appCredits": "Додаткові кредити застосунку", "@appCredits": {}, "appDetails": "Про додаток", "@appDetails": {}, @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Квадрат (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Виділити запас", "@allocateStock": {}, @@ -128,7 +128,7 @@ "@barcodeScanIntoLocationFailure": {}, "barcodeScanItem": "Просканувати запас товару", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Штрих-коди", "@barcodeTones": {}, "barcodeUnassign": "Скасувати призначення штрих-коду", "@barcodeUnassign": {}, @@ -198,9 +198,9 @@ }, "credits": "", "@credits": {}, - "crop": "Crop", + "crop": "Обрізати", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Обрізати зображення", "@cropImage": {}, "customer": "Покупець", "@customer": {}, @@ -240,9 +240,9 @@ }, "documentation": "Документація", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Завантаження завершено", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Помилка завантаження зображення", "@downloadError": {}, "downloading": "Завантаження файлу", "@downloading": {}, @@ -268,7 +268,7 @@ "@editItem": {}, "editLineItem": "Редагувати рядок", "@editLineItem": {}, - "email": "Email", + "email": "Ел. пошта", "@email": {}, "enterPassword": "Введіть пароль", "@enterPassword": {}, @@ -460,17 +460,17 @@ "@labelSelectTemplate": {}, "labelSelectPrinter": "Select Label Printer", "@labelSelectPrinter": {}, - "language": "Language", + "language": "Мова", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Типова мова системи", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Вибір мови", "@languageSelect": {}, "lastStocktake": "Last Stocktake", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "Останнє оновлення", "@lastUpdated": {}, - "level": "Level", + "level": "Рівень", "@level": {}, "lineItemAdd": "Add Line Item", "@lineItemAdd": {}, @@ -480,25 +480,25 @@ "@lineItems": {}, "lineItemUpdated": "Line item updated", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Знайти елемент запасів", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Знайти розташування запасів", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Нове розташування", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "Створити нове розташування на складі", "@locationCreateDetail": {}, - "locationNotSet": "No location specified", + "locationNotSet": "Розташування не вказано", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "Розташування запасів оновлено", "@locationUpdated": {}, - "login": "Login", + "login": "Увійти", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Введіть дані для входу", "@loginEnter": {}, "loginEnterDetails": "Ім'я користувача та пароль не зберігаються локально", "@loginEnterDetails": {}, - "link": "Link", + "link": "Посилання", "@link": {}, "lost": "Lost", "@lost": {}, @@ -506,31 +506,31 @@ "@manufacturerPart": {}, "manufacturerPartEdit": "Edit Manufacturer Part", "@manufacturerPartEdit": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Номер позиції виробника", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Виробник", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "Виробники", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Відсутні дані", "@missingData": {}, - "name": "Name", + "name": "Назва", "@name": {}, - "notConnected": "Not Connected", + "notConnected": "Не під’єднано", "@notConnected": {}, - "notes": "Notes", + "notes": "Нотатки", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Сповіщення", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Непрочитані сповіщення відсутні", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Немає відповіді від сервера", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Нічого не знайдено", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Немає доступного зображення", "@noImageAvailable": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, From 7d32bd6d88c459713bf354406da07cce1a45b095 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 19 Aug 2025 11:37:27 +1000 Subject: [PATCH 697/746] bug fix: PO Lines (#685) * bug fix: PO Lines - Correctly display part images for purchase order line items * Refactor * Code formatting --- assets/release_notes.md | 1 + lib/api.dart | 1 - lib/inventree/model.dart | 2 ++ lib/inventree/orders.dart | 10 +++++++++- lib/widget/order/po_line_list.dart | 4 ++-- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3aab9fb..4eb7f29 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Improved UX across the entire app +- Fix bug which prevented display of part images for purchase order line items ### 0.19.1 - July 2025 --- diff --git a/lib/api.dart b/lib/api.dart index d8639f3..a63f1cc 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -118,7 +118,6 @@ class InvenTreeFileService extends FileService { if (_client != null) { _client!.badCertificateCallback = (cert, host, port) { - print("BAD CERTIFICATE CALLBACK FOR IMAGE REQUEST"); return !strictHttps; }; } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index c3fc8b6..532d1c2 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -732,6 +732,8 @@ class InvenTreeModel { var response = await api.get(URL, params: params); + print("paginated: ${URL}: ${params}"); + if (!response.isValid()) { return null; } diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart index a558092..8ffc478 100644 --- a/lib/inventree/orders.dart +++ b/lib/inventree/orders.dart @@ -114,7 +114,15 @@ class InvenTreeOrderLine extends InvenTreeModel { String get partName => getString("name", subKey: "part_detail"); - String get partImage => getString("thumbnail", subKey: "part_detail"); + String get partImage { + String img = getString("thumbnail", subKey: "part_detail"); + + if (img.isEmpty) { + img = getString("image", subKey: "part_detail"); + } + + return img; + } String get targetDate => getDateString("target_date"); } diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart index 2de44c4..7dbafd5 100644 --- a/lib/widget/order/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -67,7 +67,7 @@ class _PaginatedPOLineListState final page = await InvenTreePOLineItem().listPaginated( limit, offset, - filters: params, + filters: {...params}, ); return page; } @@ -85,7 +85,7 @@ class _PaginatedPOLineListState item.progressString, color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), - leading: InvenTreeAPI().getThumbnail(supplierPart.partImage), + leading: InvenTreeAPI().getThumbnail(item.partImage), onTap: () async { showLoadingOverlay(); await item.reload(); From a0b8795b27256152a80bd406ea20fbdb3ff2b791 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 19 Aug 2025 11:37:37 +1000 Subject: [PATCH 698/746] Allow purchase orders to be completed directly from the app (#686) * Allow purchase orders to be completed directly from the app * Code formatting --- CONTRIBUTING.md | 2 +- assets/release_notes.md | 1 + lib/l10n/app_en.arb | 6 ++++ lib/widget/order/purchase_order_detail.dart | 31 +++++++++++++++++++++ tasks.py | 5 ++++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 248d20c..859ab60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ We enforce consistent code formatting using Dart's built-in formatter. Before su 1. Fork the repository and create a feature branch 2. Make your changes 3. Ensure your code passes all tests and linting -4. Format your code using `fvm dart format` +4. Format your code using `invoke format` 5. Submit a pull request with a clear description of the changes 6. Address any review comments diff --git a/assets/release_notes.md b/assets/release_notes.md index 4eb7f29..e6319b3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### TBD - ??? --- +- Allow purchase orders to be completed - Improved UX across the entire app - Fix bug which prevented display of part images for purchase order line items diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7e02053..fbac909 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -261,6 +261,12 @@ "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", "@completionDate": {}, diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 4799317..4201cd3 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; @@ -122,6 +123,18 @@ class _PurchaseOrderDetailState ); } + if (widget.order.isOpen && !widget.order.isPending) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_check, color: Colors.green), + label: L10().completeOrder, + onTap: () async { + _completeOrder(context); + }, + ), + ); + } + if (widget.order.isOpen) { actions.add( SpeedDialChild( @@ -182,6 +195,24 @@ class _PurchaseOrderDetailState ); } + /// Complete this order + Future _completeOrder(BuildContext context) async { + Map> fields = {"accept_incomplete": {}}; + + String URL = "order/po/${widget.order.pk}/complete/"; + + launchApiForm( + context, + L10().completeOrder, + URL, + fields, + method: "POST", + onSuccess: (data) async { + refresh(context); + }, + ); + } + /// Cancel this order Future _cancelOrder(BuildContext context) async { confirmationDialog( diff --git a/tasks.py b/tasks.py index a34d035..9c75e5a 100644 --- a/tasks.py +++ b/tasks.py @@ -5,6 +5,11 @@ import sys from invoke import task +@task +def format(c): + """Code formatting using dart format.""" + c.run("fvm dart format lib") + @task def clean(c): """Clean flutter build.""" From 8efae776a64cb28a912e4af73487952fe77bc944 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 19 Aug 2025 11:39:15 +1000 Subject: [PATCH 699/746] Update version (#687) --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e6319b3..de12516 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,4 +1,4 @@ -### TBD - ??? +### 0.19.2 - August 2025 --- - Allow purchase orders to be completed diff --git a/pubspec.yaml b/pubspec.yaml index 33a1047..e1629a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.19.1+100 +version: 0.19.2+101 environment: sdk: ^3.8.1 From 3739c88e932898de93eebc5d0c828956968e83af Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 26 Aug 2025 18:12:09 +1000 Subject: [PATCH 700/746] New Crowdin updates (#688) * New translations app_en.arb (Polish) * New translations app_en.arb (German) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Czech) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Danish) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Spanish) * New translations app_en.arb (French) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++ lib/l10n/da_DK/app_da_DK.arb | 4 ++ lib/l10n/de_DE/app_de_DE.arb | 4 ++ lib/l10n/el_GR/app_el_GR.arb | 4 ++ lib/l10n/es_ES/app_es_ES.arb | 4 ++ lib/l10n/es_MX/app_es_MX.arb | 4 ++ lib/l10n/et_EE/app_et_EE.arb | 4 ++ lib/l10n/fa_IR/app_fa_IR.arb | 4 ++ lib/l10n/fi_FI/app_fi_FI.arb | 4 ++ lib/l10n/fr_FR/app_fr_FR.arb | 34 ++++++----- lib/l10n/he_IL/app_he_IL.arb | 4 ++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++ lib/l10n/id_ID/app_id_ID.arb | 4 ++ lib/l10n/it_IT/app_it_IT.arb | 4 ++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++ lib/l10n/nl_NL/app_nl_NL.arb | 30 ++++++---- lib/l10n/no_NO/app_no_NO.arb | 4 ++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++ lib/l10n/pt_PT/app_pt_PT.arb | 112 ++++++++++++++++++----------------- lib/l10n/ro_RO/app_ro_RO.arb | 4 ++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++ lib/l10n/th_TH/app_th_TH.arb | 4 ++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++ lib/l10n/zh_CN/app_zh_CN.arb | 6 +- lib/l10n/zh_TW/app_zh_TW.arb | 4 ++ 38 files changed, 235 insertions(+), 83 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index ae54712..b66d8f8 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 94f4a3c..26b3b50 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index a651f02..3258bc7 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Společnosti", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Datum dokončení", "@completionDate": {}, "configureServer": "Konfigurace nastavení serveru", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index ee25a22..9f58398 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 0a885a0..319e888 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Firmen", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Abgeschlossen am", "@completionDate": {}, "configureServer": "Server-Einstellungen konfigurieren", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index f06a960..7decd92 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 102ee6f..db35685 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Empresas", "@companies": {}, + "complete": "Completado", + "@complete": {}, + "completeOrder": "Completar Pedido", + "@completeOrder": {}, "completionDate": "Fecha de Finalización", "@completionDate": {}, "configureServer": "Configure las opciones de su servidor", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 8efb8a7..0b06fc2 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Empresas", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Fecha de finalización", "@completionDate": {}, "configureServer": "Configurar ajustes del servidor", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 0449a7f..83ed875 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Ettevõtted", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Seadista serveri seadeid", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index d14c414..c0ac3e4 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "شرکت‌ها", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "تاریخ تکمیل", "@completionDate": {}, "configureServer": "تنظیم شمخصات سرور", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 2f06b86..cc6cf50 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Yritykset", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Määritä palvelimen asetukset", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index aa6d9f2..1c71f6e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Carré (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Allouer un stock", "@allocateStock": {}, @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Sociétés", "@companies": {}, + "complete": "Terminé", + "@complete": {}, + "completeOrder": "Finir l'achat", + "@completeOrder": {}, "completionDate": "Date d'achèvement", "@completionDate": {}, "configureServer": "Configurer les paramètres serveur", @@ -198,9 +202,9 @@ }, "credits": "Crédits", "@credits": {}, - "crop": "Crop", + "crop": "Rogner", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Rogner l'image", "@cropImage": {}, "customer": "Client", "@customer": {}, @@ -240,9 +244,9 @@ }, "documentation": "Documentation", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Téléchargement terminé", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Impossible de télécharger l'image", "@downloadError": {}, "downloading": "Téléchargement du fichier", "@downloading": {}, @@ -302,9 +306,9 @@ "@expiryExpired": {}, "expiryStale": "Périmé", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Ligne supplémentaire", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Lignes supplémentaires", "@extraLineItems": {}, "feedback": "Donner votre avis", "@feedback": {}, @@ -530,7 +534,7 @@ "@noResponse": {}, "noResults": "Aucun résultat", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Pas d'image disponible", "@noImageAvailable": {}, "noSubcategories": "Pas de sous-catégorie", "@noSubcategories": {}, @@ -628,7 +632,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Autorisation requise", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Téléphone", "@phone": {}, "printLabel": "Imprimer l'étiquette", "@printLabel": {}, @@ -724,7 +728,7 @@ "@reference": {}, "refresh": "Actualiser", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Rotation à 90° dans le sens horaire", "@rotateClockwise": {}, "refreshing": "Actualisation en cours", "@refreshing": {}, @@ -1084,7 +1088,7 @@ "@uploadFailed": {}, "uploadSuccess": "Fichier transféré", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Envoyer une image", "@uploadImage": {}, "usedIn": "Utilisé dans", "@usedIn": {}, @@ -1132,7 +1136,7 @@ "@variantCost": {}, "overallPricing": "Cout Global", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Remplacement des prix", "@pricingOverrides": {}, "currency": "Devise", "@currency": {}, @@ -1142,10 +1146,10 @@ "@noPricingAvailable": {}, "noPricingDataFound": "Aucune donnée de tarification disponible pour cette pièce", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Êtes-vous sûr de vouloir supprimer cette image ?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Supprimer l'image", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Supprimer l'image", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 26e9ff1..b7ca5b3 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "חברות", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "קבע את הגדרות השרת", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index b30109d..5d4fb5b 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 626d4e3..8b36a56 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Cégek", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Befejezés dátuma", "@completionDate": {}, "configureServer": "Kiszolgáló beállítások konfigurálása", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 84fda02..db93ff0 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Perusahaan", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Konfigurasikan pengaturan server", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 4e47bfd..f918e7a 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Aziende", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Data di completamento", "@completionDate": {}, "configureServer": "Configurare le impostazioni del server", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index e2b90f7..73b1732 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "会社", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "完了日", "@completionDate": {}, "configureServer": "サーバー設定", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 85b8106..0b93e85 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index ceff316..202a20e 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 2f2a3c0..c65369a 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Uzņēmumi", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 0b0a76b..b039e03 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Vierkant (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Voorraad Toewijzen", "@allocateStock": {}, @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Bedrijven", "@companies": {}, + "complete": "Gereed", + "@complete": {}, + "completeOrder": "Order Voltooien", + "@completeOrder": {}, "completionDate": "Datum van afronding", "@completionDate": {}, "configureServer": "Configureer server instellingen", @@ -198,9 +202,9 @@ }, "credits": "Credits", "@credits": {}, - "crop": "Crop", + "crop": "Bijsnijden", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Afbeelding bijsnijden", "@cropImage": {}, "customer": "Klant", "@customer": {}, @@ -240,9 +244,9 @@ }, "documentation": "Documentatie", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Download voltooid", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Fout bij downloaden afbeelding", "@downloadError": {}, "downloading": "Bestand wordt gedownload", "@downloading": {}, @@ -268,7 +272,7 @@ "@editItem": {}, "editLineItem": "Voorraadartikel bewerken", "@editLineItem": {}, - "email": "Email", + "email": "E-mailadres", "@email": {}, "enterPassword": "Wachtwoord invoeren", "@enterPassword": {}, @@ -530,7 +534,7 @@ "@noResponse": {}, "noResults": "Geen Resultaten", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Geen afbeelding beschikbaar", "@noImageAvailable": {}, "noSubcategories": "Geen Subcategorieën", "@noSubcategories": {}, @@ -628,7 +632,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Toestemming Vereist", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefoon", "@phone": {}, "printLabel": "Print Label", "@printLabel": {}, @@ -724,7 +728,7 @@ "@reference": {}, "refresh": "Vernieuwen", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "90° rechtsom draaien", "@rotateClockwise": {}, "refreshing": "Verversen…", "@refreshing": {}, @@ -1084,7 +1088,7 @@ "@uploadFailed": {}, "uploadSuccess": "Bestand geüpload", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Afbeelding Uploaden", "@uploadImage": {}, "usedIn": "Wordt Gebruikt In", "@usedIn": {}, @@ -1142,10 +1146,10 @@ "@noPricingAvailable": {}, "noPricingDataFound": "Er zijn geen prijsgegevens gevonden voor dit deel", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Weet u zeker dat u deze afbeelding wilt verwijderen?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Afbeelding verwijderen", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Afbeelding verwijderen", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 3bbb36c..d454fd4 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Firma", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Fullført dato", "@completionDate": {}, "configureServer": "Konfigurer serverinnstillinger", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 3bf7757..68648a7 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Firmy", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Data ukończenia", "@completionDate": {}, "configureServer": "Konfiguruj ustawienia serwera", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 62bc779..4d4cd09 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Empresas", "@companies": {}, + "complete": "Concluído", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Definir as configurações do servidor", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 19f0b14..4c9478b 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Quadrado (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Alocar estoque", "@allocateStock": {}, @@ -52,9 +52,9 @@ "@appSettings": {}, "appSettingsDetails": "Configurar os parâmetros do InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Atribuído a Mim", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Mostrar pedidos atribuídos a mim", "@assignedToMeDetail": {}, "attachments": "Anexos", "@attachments": {}, @@ -146,7 +146,7 @@ "@build": {}, "building": "Compilando", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Não foi possível aceder ao controlo da câmara", "@cameraCreationError": {}, "cameraInternal": "Câmera Interna", "@cameraInternal": {}, @@ -168,7 +168,7 @@ "@categoryUpdated": {}, "company": "Empresa", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Adicionar Empresa", "@companyAdd": {}, "companyEdit": "Editar empresa", "@companyEdit": {}, @@ -178,7 +178,11 @@ "@companyUpdated": {}, "companies": "Empresas", "@companies": {}, - "completionDate": "Completion Date", + "complete": "Finalizar", + "@complete": {}, + "completeOrder": "Finalizar Encomenda", + "@completeOrder": {}, + "completionDate": "Data de conclusão", "@completionDate": {}, "configureServer": "Configurar os parâmetros do servidor de email", "@configureServer": {}, @@ -198,9 +202,9 @@ }, "credits": "Créditos", "@credits": {}, - "crop": "Crop", + "crop": "Cortar", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Recortar Imagem", "@cropImage": {}, "customer": "Cliente", "@customer": {}, @@ -210,9 +214,9 @@ "@customerReference": {}, "damaged": "Danificado", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Esquema de cores", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Seleccione o esquema de cores", "@colorSchemeDetail": {}, "darkMode": "Modo Noturno", "@darkMode": {}, @@ -230,7 +234,7 @@ "@deleteSuccess": {}, "description": "Descrição", "@description": {}, - "destination": "Destination", + "destination": "Destino", "@destination": {}, "destroyed": "Destruído", "@destroyed": {}, @@ -240,9 +244,9 @@ }, "documentation": "Documentação", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Transferência concluída", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Erro ao transferir imagem", "@downloadError": {}, "downloading": "Baixando arquivo", "@downloading": {}, @@ -250,7 +254,7 @@ "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Editar Anexo", "@editAttachment": {}, "editCategory": "Editar categoria", "@editCategory": {}, @@ -296,15 +300,15 @@ "@errorReportUpload": {}, "errorReportUploadDetails": "Enviar relatórios de erros e registos anónimos", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Data de Validade", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Expirado", "@expiryExpired": {}, - "expiryStale": "Stale", + "expiryStale": "Inativo", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Adicionar Linha de Artigos Extra", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Adicionar Linhas de Artigos Extra", "@extraLineItems": {}, "feedback": "Comentários", "@feedback": {}, @@ -426,59 +430,59 @@ "@invalidHostDetails": {}, "invalidPart": "Peça Inválida", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "Categoria de Peças Inválida", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "Localização de Estoque Inválida", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "Artigo de Estoque Inválido", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Peça de fornecedor inválida", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "O nome de utilizador ou a palavra-passe não estão corretos", "@invalidUsernamePassword": {}, - "issue": "Issue", + "issue": "Erro", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Data de emissão", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Emitir encomenda", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "O artigo já está no local", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "O artigo foi removido", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "O artigo foi atualizado", "@itemUpdated": {}, - "keywords": "Keywords", + "keywords": "Palavras-chave", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Impressão de etiqueta", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Ativar impressão de etiquetas", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Modelo de Etiqueta", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Selecione o modelo de etiqueta", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Selecionar impressora de etiqueta", "@labelSelectPrinter": {}, - "language": "Language", + "language": "Idioma", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Idioma de sistema predefinido", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Selecionar Idioma", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Último Balanço de Estoque", "@lastStocktake": {}, "lastUpdated": "Ultima atualização", "@lastUpdated": {}, - "level": "Level", + "level": "Nível", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Adicionar linha", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Linha", "@lineItem": {}, "lineItems": "Itens de linha", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Linha atualizada", "@lineItemUpdated": {}, "locateItem": "Locate stock item", "@locateItem": {}, @@ -610,27 +614,27 @@ "@partCategory": {}, "partCategoryTopLevel": "Top level part category", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "Categorias de Peça", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Detalhes da Peça", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Notas da Peça", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Estoque da Peça", "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "Palavra-passe", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "A palavra-passe não pode estar vazia", "@passwordEmpty": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "A sua conta não tem as permissões necessárias para executar esta ação", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Permissão necessária", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefone", "@phone": {}, - "printLabel": "Print Label", + "printLabel": "Imprimir Etiqueta", "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 3041b6d..e3c54e9 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companii", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configurare setări server", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 494c92c..7437e27 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Компании", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Дата завершения", "@completionDate": {}, "configureServer": "Настройка параметров сервера", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 9ec2d50..5e98aa3 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index e3b2c50..e82b80f 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index d4f8215..856048e 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Kompanije", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Konfiguriši podešavanja servera", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index ca1b2a4..502ab65 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Företag", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Datum slutfört", "@completionDate": {}, "configureServer": "Konfigurera serverinställningar", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index d69c076..c97b24c 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Companies", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Configure server settings", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index f205182..39cc2d7 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Şirketler", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Tamamlanma Tarihi", "@completionDate": {}, "configureServer": "Sunucu ayarlarınızı yapılandırın", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 39666bb..5fc2911 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Компанії", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Дата завершення", "@completionDate": {}, "configureServer": "Налаштування сервера", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 0dd51ae..f43a6d5 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "Doanh nghiệp", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "Cấu hình thiết lập máy chủ", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index e1cf2b9..2f45187 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "公司", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "完成日期", "@completionDate": {}, "configureServer": "配置服务器的设置", @@ -1114,7 +1118,7 @@ "@price": {}, "priceRange": "价格范围", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "最低价格覆盖", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 58954c0..8a0a327 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -178,6 +178,10 @@ "@companyUpdated": {}, "companies": "公司", "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, "completionDate": "Completion Date", "@completionDate": {}, "configureServer": "伺服器設定", From 449f4a4ce5be085080e636a83cb17e28b460c2b9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 30 Aug 2025 21:56:57 +1000 Subject: [PATCH 701/746] New Crowdin updates (#689) * New translations app_en.arb (Italian) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/it_IT/app_it_IT.arb | 4 ++-- lib/l10n/zh_CN/app_zh_CN.arb | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index f918e7a..b26869e 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Aziende", "@companies": {}, - "complete": "Complete", + "complete": "Completato", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Ordine completo", "@completeOrder": {}, "completionDate": "Data di completamento", "@completionDate": {}, diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 2f45187..c2eaff8 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "公司", "@companies": {}, - "complete": "Complete", + "complete": "完成", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "完成订单", "@completeOrder": {}, "completionDate": "完成日期", "@completionDate": {}, @@ -272,7 +272,7 @@ "@editItem": {}, "editLineItem": "编辑行项目", "@editLineItem": {}, - "email": "Email", + "email": "电子邮件", "@email": {}, "enterPassword": "输入密码", "@enterPassword": {}, @@ -632,7 +632,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "需要授权:", "@permissionRequired": {}, - "phone": "Phone", + "phone": "电话", "@phone": {}, "printLabel": "打印标签", "@printLabel": {}, @@ -1120,7 +1120,7 @@ "@priceRange": {}, "priceOverrideMin": "最低价格覆盖", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "最高自定义价格", "@priceOverrideMax": {}, "salePrice": "销售价格", "@salePrice": {}, From d237a0e076593833c9edeaece7a2e1d65afa7661 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 4 Sep 2025 11:33:00 +1000 Subject: [PATCH 702/746] New Crowdin updates (#690) * New translations app_en.arb (Turkish) * New translations app_en.arb (Hindi) * New translations app_en.arb (German) * New translations app_en.arb (Chinese Simplified) --- lib/l10n/de_DE/app_de_DE.arb | 2 +- lib/l10n/hi_IN/app_hi_IN.arb | 4 ++-- lib/l10n/tr_TR/app_tr_TR.arb | 4 ++-- lib/l10n/zh_CN/app_zh_CN.arb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 319e888..3bb7820 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -178,7 +178,7 @@ "@companyUpdated": {}, "companies": "Firmen", "@companies": {}, - "complete": "Complete", + "complete": "", "@complete": {}, "completeOrder": "Complete Order", "@completeOrder": {}, diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 5d4fb5b..859bb73 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -26,7 +26,7 @@ "@addStock": { "description": "add stock" }, - "address": "Address", + "address": "", "@address": {}, "appAbout": "About InvenTree", "@appAbout": {}, @@ -112,7 +112,7 @@ "@barcodeScanDelay": {}, "barcodeScanDelayDetail": "Delay between barcode scans", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "InvenTree बारकोड स्कैन करें", "@barcodeScanGeneral": {}, "barcodeScanInItems": "Scan stock items into this location", "@barcodeScanInItems": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 39cc2d7..8430f4c 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Şirketler", "@companies": {}, - "complete": "Complete", + "complete": "Tamamlandı", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Siparişi Tamamla", "@completeOrder": {}, "completionDate": "Tamamlanma Tarihi", "@completionDate": {}, diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index c2eaff8..84422dd 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -286,7 +286,7 @@ "@errorCreate": {}, "errorDelete": "删除数据库条目时出错", "@errorDelete": {}, - "errorDetails": "c w错误详情", + "errorDetails": "错误详情", "@errorDetails": {}, "errorFetch": "从服务器获取数据时出错", "@errorFetch": {}, From bdc55733119ae875b2d01dbdd07f880d87a0a678 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 28 Sep 2025 13:34:22 +1000 Subject: [PATCH 703/746] Re-order barcode scanning priority (#693) * Re-order barcode scanning priority - Closes https://github.com/inventree/inventree-app/issues/692 * dart format * Try with removed line * Try without pythonscript * just pub get * try with fvm * Remove fvm * set working dir * try just pub get * Install python first * Updates * Use fvm * Adjust CI --- .github/workflows/ci.yaml | 23 +++++++++++++---------- assets/release_notes.md | 5 +++++ find_dart_files.py | 2 ++ lib/barcode/barcode.dart | 6 +++--- pubspec.yaml | 2 +- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b61677d..2ecf506 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -30,6 +30,11 @@ jobs: with: submodules: recursive + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + - name: Setup Java uses: actions/setup-java@v3 with: @@ -53,20 +58,18 @@ jobs: - name: Collect Translation Files run: | cd lib/l10n - python3 collect_translations.py + python collect_translations.py - name: Static Analysis Tests + working-directory: . run: | - python3 find_dart_files.py - flutter pub get - flutter analyze + python ./find_dart_files.py + dart pub global activate fvm + fvm install + fvm flutter pub get + fvm flutter analyze dart format --output=none --set-exit-if-changed . - - name: Install Python - uses: actions/setup-python@v4 - with: - python-version: 3.9 - - name: Start InvenTree Server run: | sudo apt-get install python3-dev python3-pip python3-venv python3-wheel g++ @@ -82,7 +85,7 @@ jobs: - name: Unit Tests run: | - flutter test --coverage + fvm flutter test --coverage - name: Coveralls uses: coverallsapp/github-action@master diff --git a/assets/release_notes.md b/assets/release_notes.md index de12516..7869603 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.19.3 - September 2025 +--- + +- Fixes incorrect priority of barcode scanner results + ### 0.19.2 - August 2025 --- diff --git a/find_dart_files.py b/find_dart_files.py index dbb1479..80fba3a 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -13,6 +13,8 @@ from pathlib import Path if __name__ == "__main__": dart_files = Path("lib").rglob("*.dart") + print("Discovering dart files..."); + with open("test/coverage_helper_test.dart", "w") as f: f.write("// ignore_for_file: unused_import\n\n") f.write("// dart format off\n\n") diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index ddbb319..8fe50ca 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -250,12 +250,12 @@ class BarcodeScanHandler extends BarcodeHandler { // The following model types can be matched with barcodes List validModels = [ - InvenTreePart.MODEL_TYPE, - InvenTreeCompany.MODEL_TYPE, InvenTreeStockItem.MODEL_TYPE, - InvenTreeStockLocation.MODEL_TYPE, InvenTreeSupplierPart.MODEL_TYPE, InvenTreeManufacturerPart.MODEL_TYPE, + InvenTreePart.MODEL_TYPE, + InvenTreeStockLocation.MODEL_TYPE, + InvenTreeCompany.MODEL_TYPE, ]; if (InvenTreeAPI().supportsOrderBarcodes) { diff --git a/pubspec.yaml b/pubspec.yaml index e1629a5..0b9b3d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.19.2+101 +version: 0.19.3+102 environment: sdk: ^3.8.1 From 1407d8bc37710af51c8a7adbd34acd5362239c3d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 28 Sep 2025 16:47:39 +1000 Subject: [PATCH 704/746] Use fvm for building workflows (#694) --- .github/workflows/android.yaml | 6 ++++-- .github/workflows/ios.yaml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 117c9a8..9f30b48 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -50,5 +50,7 @@ jobs: - name: Build for Android run: | - flutter pub get - flutter build apk --debug + dart pub global activate fvm + fvm install + fvm flutter pub get + fvm flutter build apk --debug diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 53e8a30..724fa57 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -46,9 +46,11 @@ jobs: - name: Build for iOS run: | - flutter pub get + dart pub global activate fvm + fvm install + fvm flutter pub get cd ios pod repo update pod install cd .. - flutter build ios --release --no-codesign --no-tree-shake-icons + fvm flutter build ios --release --no-codesign --no-tree-shake-icons From 790abb4c7dcae80c207698dd70677c87d6a5be32 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 11 Oct 2025 12:07:58 +1100 Subject: [PATCH 705/746] New Crowdin updates (#695) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Swedish) * New translations app_en.arb (Polish) * New translations app_en.arb (Russian) * New translations app_en.arb (Portuguese, Brazilian) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 6 ++--- lib/l10n/hu_HU/app_hu_HU.arb | 46 ++++++++++++++++++------------------ lib/l10n/pl_PL/app_pl_PL.arb | 28 +++++++++++----------- lib/l10n/pt_BR/app_pt_BR.arb | 38 ++++++++++++++--------------- lib/l10n/ru_RU/app_ru_RU.arb | 16 ++++++------- lib/l10n/sv_SE/app_sv_SE.arb | 16 ++++++------- 6 files changed, 75 insertions(+), 75 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 3258bc7..ecd7afe 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Společnosti", "@companies": {}, - "complete": "Complete", + "complete": "Dokončit", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Dokončit objednávku", "@completeOrder": {}, "completionDate": "Datum dokončení", "@completionDate": {}, @@ -272,7 +272,7 @@ "@editItem": {}, "editLineItem": "Upravit položku", "@editLineItem": {}, - "email": "Mail", + "email": "E-mail", "@email": {}, "enterPassword": "Zadejte heslo", "@enterPassword": {}, diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 8b36a56..31121be 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -54,7 +54,7 @@ "@appSettingsDetails": {}, "assignedToMe": "Hozzámrendelt", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Mutasd az én rendeléseim", "@assignedToMeDetail": {}, "attachments": "Mellékletek", "@attachments": {}, @@ -146,7 +146,7 @@ "@build": {}, "building": "Gyártásban", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Nem sikerült a kameravezérlőt megnyitni", "@cameraCreationError": {}, "cameraInternal": "Belső kamera", "@cameraInternal": {}, @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Cégek", "@companies": {}, - "complete": "Complete", + "complete": "Kész", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Rendelés teljesítése", "@completeOrder": {}, "completionDate": "Befejezés dátuma", "@completionDate": {}, @@ -306,9 +306,9 @@ "@expiryExpired": {}, "expiryStale": "Elavult", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Egyéb tétel", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Egyéb tételek", "@extraLineItems": {}, "feedback": "Visszajelzés", "@feedback": {}, @@ -534,7 +534,7 @@ "@noResponse": {}, "noResults": "Nincs találat", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Nincs elérhető kép", "@noImageAvailable": {}, "noSubcategories": "Nincsenek alkategóriák", "@noSubcategories": {}, @@ -600,7 +600,7 @@ "@partNoResults": {}, "partPricing": "Alkatrész árazása", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Alkatrész árazási információk megjelenítése", "@pricingSettingDetail": {}, "partSettings": "Alkatrész beállítások", "@partSettings": {}, @@ -674,17 +674,17 @@ "@profileTapToCreate": {}, "projectCode": "Projektszám", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Beolvasott adatok jóváhagyása", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Tételek részleteinek jóváhagyása beolvasás közben", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Beszerzési rendelések engedélyezése", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Értékesítési rendelés funkció aktiválása", "@purchaseOrderEnableDetail": {}, "purchaseOrderShowCamera": "Kamera gyorsbillentyű", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Képfeltöltés shortcut engedélyezése az beszerzési rendelés oldalon", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Beszerzési rendelés", "@purchaseOrder": {}, @@ -806,7 +806,7 @@ "@salesOrders": {}, "salesOrderEnable": "Vevői rendelések engedélyezése", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Értékesítési rendés funkció aktiválása", + "salesOrderEnableDetail": "Értékesítési rendelés funkció aktiválása", "@salesOrderEnableDetail": {}, "salesOrderShowCamera": "Kamera gyorsbillentyű", "@salesOrderShowCamera": {}, @@ -1074,7 +1074,7 @@ "@translateHelp": {}, "unavailable": "Nem elérhető", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Tétel nem elérhető", "@unavailableDetail": {}, "unitPrice": "Egységár", "@unitPrice": {}, @@ -1118,15 +1118,15 @@ "@price": {}, "priceRange": "Ártartomány", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Minimális Ár Felülbírálás", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Maximumális Ár Felülbírálás", "@priceOverrideMax": {}, "salePrice": "Eladási ár", "@salePrice": {}, "saleHistory": "Eladási előzmények", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Beszállítói árazás", "@supplierPricing": {}, "bomCost": "Alkatrészjegyzék költség", "@bomCost": {}, @@ -1134,19 +1134,19 @@ "@internalCost": {}, "variantCost": "Variáns költsége", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Általános árazás", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Árazás felülbírálások", "@pricingOverrides": {}, "currency": "Pénznem", "@currency": {}, "priceBreaks": "Ársávok", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Árazás nem elérhető", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Nincs árazási információ ehhez az alkatrészhez", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Biztosan törli a képet?", "@deleteImageConfirmation": {}, "deleteImageTooltip": "Kép törlése", "@deleteImageTooltip": {}, diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 68648a7..72c5c7f 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -36,13 +36,13 @@ "@appDetails": {}, "allocated": "Przydzielono", "@allocated": {}, - "aspectRatio16x9": "", + "aspectRatio16x9": "16:9", "@aspectRatio16x9": {}, "aspectRatio3x2": "3:2", "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Kwadrat (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Przydziel zapasy", "@allocateStock": {}, @@ -52,7 +52,7 @@ "@appSettings": {}, "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "", + "assignedToMe": "Przypisane do mnie", "@assignedToMe": {}, "assignedToMeDetail": "Pokaż zlecenia, które zostały do mnie przypisane", "@assignedToMeDetail": {}, @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Firmy", "@companies": {}, - "complete": "Complete", + "complete": "Zakończono", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Zakończ zamówienie", "@completeOrder": {}, "completionDate": "Data ukończenia", "@completionDate": {}, @@ -450,7 +450,7 @@ "@itemInLocation": {}, "itemDeleted": "Element został usunięty", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Element został zaktualizowany.", "@itemUpdated": {}, "keywords": "Słowa kluczowe", "@keywords": {}, @@ -748,7 +748,7 @@ "@reportBug": {}, "reportBugDescription": "Prześlij raport o błędzie (wymaga konta GitHub)", "@reportBugDescription": {}, - "responsible": "Responsible", + "responsible": "Odpowiedzialny", "@responsible": {}, "results": "Wyniki", "@results": {}, @@ -1128,9 +1128,9 @@ "@saleHistory": {}, "supplierPricing": "Supplier Pricing", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Koszt BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Koszt wewnętrzny", "@internalCost": {}, "variantCost": "Variant Cost", "@variantCost": {}, @@ -1138,17 +1138,17 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Waluta", "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Cena nie jest dostępna", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Nie znaleziono danych dotyczących cen dla tej części", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Czy na pewno chcesz usunąć ten obraz?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Usuń obraz", "@deleteImageTooltip": {}, "deleteImage": "Usuń obraz", "@deleteImage": {} diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 4d4cd09..7f67a03 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -180,9 +180,9 @@ "@companies": {}, "complete": "Concluído", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Finalizar pedido", "@completeOrder": {}, - "completionDate": "Completion Date", + "completionDate": "Data de conclusão", "@completionDate": {}, "configureServer": "Definir as configurações do servidor", "@configureServer": {}, @@ -304,11 +304,11 @@ "@expiryDate": {}, "expiryExpired": "Vencido", "@expiryExpired": {}, - "expiryStale": "Stale", + "expiryStale": "Inativo", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Item de Linha extra", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Itens de linha extra", "@extraLineItems": {}, "feedback": "Feedback", "@feedback": {}, @@ -600,7 +600,7 @@ "@partNoResults": {}, "partPricing": "Preço de Peça", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Exibir informações de preço de parte", "@pricingSettingDetail": {}, "partSettings": "Configurações de Peça", "@partSettings": {}, @@ -674,9 +674,9 @@ "@profileTapToCreate": {}, "projectCode": "Código do projeto", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Confirmar dados de varredura", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Confirmar detalhes ao escanear itens", "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Habilitar Pedidos de Compra", "@purchaseOrderEnable": {}, @@ -1044,7 +1044,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Lig/Desl. lanterna", "@toggleTorch": {}, "tokenError": "Error de token", "@tokenError": {}, @@ -1118,31 +1118,31 @@ "@price": {}, "priceRange": "Faixa de Preço", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Substituição de preço mínimo", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Substituição de preço máximo", "@priceOverrideMax": {}, "salePrice": "Preço de Venda", "@salePrice": {}, "saleHistory": "Histórico de Vendas", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Preço do fornecedor", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Custo de LDM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Custo Interno", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Custo Variante", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Precificação Geral", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Sobrescrever Preço", "@pricingOverrides": {}, "currency": "Moeda", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Quebra de Preço", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Nenhum preço disponível", "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", "@noPricingDataFound": {}, diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 7437e27..35294d1 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -178,7 +178,7 @@ "@companyUpdated": {}, "companies": "Компании", "@companies": {}, - "complete": "Complete", + "complete": "Завершить", "@complete": {}, "completeOrder": "Complete Order", "@completeOrder": {}, @@ -202,9 +202,9 @@ }, "credits": "Авторы", "@credits": {}, - "crop": "Crop", + "crop": "Обрезать", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Обрезать изображение", "@cropImage": {}, "customer": "Клиент", "@customer": {}, @@ -244,7 +244,7 @@ }, "documentation": "Документация", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Загрузка завершена", "@downloadComplete": {}, "downloadError": "Error downloading image", "@downloadError": {}, @@ -632,7 +632,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Требуется разрешение", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Телефон", "@phone": {}, "printLabel": "Печать этикетки", "@printLabel": {}, @@ -728,7 +728,7 @@ "@reference": {}, "refresh": "Обновить", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Повернуть на 90° по часовой стрелке", "@rotateClockwise": {}, "refreshing": "Обновление…", "@refreshing": {}, @@ -1088,7 +1088,7 @@ "@uploadFailed": {}, "uploadSuccess": "Файл загружен", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Загрузить изображение", "@uploadImage": {}, "usedIn": "Используется в", "@usedIn": {}, @@ -1146,7 +1146,7 @@ "@noPricingAvailable": {}, "noPricingDataFound": "Для этой детали не найдены данные о ценах", "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Вы уверены, что хотите удалить изображение?", "@deleteImageConfirmation": {}, "deleteImageTooltip": "Delete Image", "@deleteImageTooltip": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 502ab65..14b3b90 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Företag", "@companies": {}, - "complete": "Complete", + "complete": "Slutförd", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Slutför Order", "@completeOrder": {}, "completionDate": "Datum slutfört", "@completionDate": {}, @@ -202,9 +202,9 @@ }, "credits": "Krediter", "@credits": {}, - "crop": "Crop", + "crop": "Beskär", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Beskär Bild", "@cropImage": {}, "customer": "Kund", "@customer": {}, @@ -244,9 +244,9 @@ }, "documentation": "Dokumentation", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Nedladdning klar", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Fel vid nedladdning av bild", "@downloadError": {}, "downloading": "Laddar ner fil", "@downloading": {}, @@ -272,7 +272,7 @@ "@editItem": {}, "editLineItem": "Redigera radobjekt", "@editLineItem": {}, - "email": "Email", + "email": "E-post", "@email": {}, "enterPassword": "Ange lösenord", "@enterPassword": {}, @@ -534,7 +534,7 @@ "@noResponse": {}, "noResults": "Inga resultat", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Ingen bild tillgänglig", "@noImageAvailable": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, From 6b67cc9e50b2c98c0b8c93c3ca31b5ab007cd0d1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 21 Oct 2025 16:28:53 +1100 Subject: [PATCH 706/746] New Crowdin updates (#696) * New translations app_en.arb (Russian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Vietnamese) --- lib/l10n/id_ID/app_id_ID.arb | 20 ++-- lib/l10n/ru_RU/app_ru_RU.arb | 20 ++-- lib/l10n/uk_UA/app_uk_UA.arb | 186 +++++++++++++++++------------------ lib/l10n/vi_VN/app_vi_VN.arb | 2 +- 4 files changed, 114 insertions(+), 114 deletions(-) diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index db93ff0..f89f8bf 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Persegi (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Alokasikan Stok", "@allocateStock": {}, @@ -52,9 +52,9 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurasikan pengaturan aplikasi InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Ditugaskan kepada Saya", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Tampilkan pesanan yang ditugaskan kepada saya", "@assignedToMeDetail": {}, "attachments": "Lampiran", "@attachments": {}, @@ -146,7 +146,7 @@ "@build": {}, "building": "Bangunan", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Tidak dapat membuka pengontrol kamera", "@cameraCreationError": {}, "cameraInternal": "Kamera Internal", "@cameraInternal": {}, @@ -168,7 +168,7 @@ "@categoryUpdated": {}, "company": "Perusahaan", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Tambahkan Perusahaan", "@companyAdd": {}, "companyEdit": "Rubah Perusahaan", "@companyEdit": {}, @@ -178,11 +178,11 @@ "@companyUpdated": {}, "companies": "Perusahaan", "@companies": {}, - "complete": "Complete", + "complete": "Selesai", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Lengkapi Pesanan", "@completeOrder": {}, - "completionDate": "Completion Date", + "completionDate": "Tanggal Selesai", "@completionDate": {}, "configureServer": "Konfigurasikan pengaturan server", "@configureServer": {}, @@ -202,9 +202,9 @@ }, "credits": "Kredit", "@credits": {}, - "crop": "Crop", + "crop": "Pangkas", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Pangkas Gambar", "@cropImage": {}, "customer": "Pelanggan", "@customer": {}, diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 35294d1..bbc7cc5 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Квадрат (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Выделить запас", "@allocateStock": {}, @@ -180,11 +180,11 @@ "@companies": {}, "complete": "Завершить", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Завершить заказ", "@completeOrder": {}, "completionDate": "Дата завершения", "@completionDate": {}, - "configureServer": "Настройка параметров сервера", + "configureServer": "Изменить параметры сервера", "@configureServer": {}, "confirmScan": "Подтвердить перенос", "@confirmScan": {}, @@ -246,7 +246,7 @@ "@documentation": {}, "downloadComplete": "Загрузка завершена", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Ошибка загрузки изображения", "@downloadError": {}, "downloading": "Загрузка файла", "@downloading": {}, @@ -272,7 +272,7 @@ "@editItem": {}, "editLineItem": "Изменить позицию", "@editLineItem": {}, - "email": "Email", + "email": "Электронная почта", "@email": {}, "enterPassword": "Введите пароль", "@enterPassword": {}, @@ -326,11 +326,11 @@ "@filterAssemblyDetail": {}, "filterComponent": "Компонент", "@filterComponent": {}, - "filterComponentDetail": "Показывать части компонента", + "filterComponentDetail": "Показать части компонента", "@filterComponentDetail": {}, "filterExternal": "Внешний", "@filterExternal": {}, - "filterExternalDetail": "Показывать запасы во внешних местах", + "filterExternalDetail": "Показать запасы во внешних местах", "@filterExternalDetail": {}, "filterInStock": "В наличии", "@filterInStock": {}, @@ -534,7 +534,7 @@ "@noResponse": {}, "noResults": "Нет результатов", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Нет доступного изображения", "@noImageAvailable": {}, "noSubcategories": "Нет подкатегории", "@noSubcategories": {}, @@ -1148,8 +1148,8 @@ "@noPricingDataFound": {}, "deleteImageConfirmation": "Вы уверены, что хотите удалить изображение?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Удалить изображение", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Удалить изображение", "@deleteImage": {} } \ No newline at end of file diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 5fc2911..94a669f 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -178,9 +178,9 @@ "@companyUpdated": {}, "companies": "Компанії", "@companies": {}, - "complete": "Complete", + "complete": "Завершити", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Завершити замовлення", "@completeOrder": {}, "completionDate": "Дата завершення", "@completionDate": {}, @@ -504,11 +504,11 @@ "@loginEnterDetails": {}, "link": "Посилання", "@link": {}, - "lost": "Lost", + "lost": "Втрачено", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Виробник деталі", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Редагувати виробника деталі", "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Номер позиції виробника", "@manufacturerPartNumber": {}, @@ -540,25 +540,25 @@ "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Некоректний номер", "@numberInvalid": {}, "onOrder": "On Order", "@onOrder": {}, "onOrderDetails": "Items currently on order", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Орієнтація екрана", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Орієнтація екрана (потребує перезапуску)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Альбомна орієнтація", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Портретна орієнтація екрану", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Орієнтація задана системою", "@orientationSystem": {}, "outstanding": "Відмінно", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Показати незавершені замовлення", "@outstandingOrderDetail": {}, "overdue": "Протерміновані", "@overdue": {}, @@ -598,7 +598,7 @@ "@partsNone": {}, "partNoResults": "Немає позицій відповідних запиту", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Ціна деталі", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, @@ -632,7 +632,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Потрібен дозвіл", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Телефон", "@phone": {}, "printLabel": "Друк ярлика", "@printLabel": {}, @@ -700,23 +700,23 @@ "@purchaseOrderUpdated": {}, "purchasePrice": "Purchase Price", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Кількість", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Доступна кількість", "@quantityAvailable": {}, "quantityEmpty": "Quantity is empty", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Некоректна кількість", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Кількість мусить бути позитивною", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Що шукати?", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "Нічого не знайдено", "@queryNoResults": {}, - "received": "Received", + "received": "Отримано", "@received": {}, "receivedFilterDetail": "Show received items", "@receivedFilterDetail": {}, @@ -726,17 +726,17 @@ "@receivedItem": {}, "reference": "Reference", "@reference": {}, - "refresh": "Refresh", + "refresh": "Оновити", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Повернути на 90° за годинниковою стрілкою", "@rotateClockwise": {}, - "refreshing": "Refreshing", + "refreshing": "Оновлення", "@refreshing": {}, "rejected": "Rejected", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "Замітки до випуску", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Видалити", "@remove": { "description": "remove" }, @@ -744,47 +744,47 @@ "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Зголосити помилку", "@reportBug": {}, "reportBugDescription": "Відправити звіт про помилку (потрібен обліковий запис GitHub)", "@reportBugDescription": {}, - "responsible": "Responsible", + "responsible": "Відповідальний", "@responsible": {}, - "results": "Results", + "results": "Результати", "@results": {}, - "request": "Request", + "request": "Запит", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "Запит завершився помилкою", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "Успішний запит", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "Запит даних", "@requestingData": {}, "required": "Required", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "Некоректний запит", "@response400": {}, - "response401": "Unauthorized", + "response401": "Потрібна авторизація", "@response401": {}, - "response403": "Permission Denied", + "response403": "Доступ заборонено", "@response403": {}, - "response404": "Resource Not Found", + "response404": "Ресурс не знайдено", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "Цей метод заборонений", "@response405": {}, - "response429": "Too Many Requests", + "response429": "Занадто багато запитів", "@response429": {}, - "response500": "Internal Server Error", + "response500": "Внутрішня помилка сервера", "@response500": {}, - "response501": "Not Implemented", + "response501": "Не реалізовано", "@response501": {}, - "response502": "Bad Gateway", + "response502": "Поганий шлюз", "@response502": {}, - "response503": "Service Unavailable", + "response503": "Сервіс недоступний", "@response503": {}, - "response504": "Gateway Timeout", + "response504": "Шлю не відповідає", "@response504": {}, "response505": "Версія HTTP не підтримується", "@response505": {}, @@ -832,17 +832,17 @@ "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scan this item into location", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Зовнішній сканер", "@scannerExternal": {}, "scannerExternalDetail": "Використовувати зовнішній сканер для читання штрих-кодів (wedge режим)", "@scannerExternalDetail": {}, "scanReceivedParts": "Scan Received Parts", "@scanReceivedParts": {}, - "search": "Search", + "search": "Пошук", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Триває пошук", "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, @@ -850,81 +850,81 @@ "@searchParts": {}, "searchStock": "Search Stock", "@searchStock": {}, - "select": "Select", + "select": "Вибрати", "@select": {}, - "selectFile": "Select File", + "selectFile": "Вибрати файл", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Виберіть зображення", "@selectImage": {}, "selectLocation": "Select a location", "@selectLocation": {}, - "send": "Send", + "send": "Відправити", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Серійний номер", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Серійні номери", "@serialNumbers": {}, - "server": "Server", + "server": "Сервер", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Адреса сервера", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Вимагана версія API", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Версія API сервера", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Помилка аутентифікації", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Помилка сертифіката", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Помилка HTTPS сертифікату сервера", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Підключений до сервера", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Триває підключення до сервера", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Неможливо під'єднатися до сервера", "@serverCouldNotConnect": {}, "serverEmpty": "Server cannot be empty", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Помилка сервера", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Інформація про сервер", "@serverDetails": {}, "serverMissingData": "На сервері відсутні обов'язкові поля для відповіді", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Стара версія сервера", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Налаштування сервера", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Адреса сервера мусить починатися з http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Налаштування", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Екземпляр сервера", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Відсутнє з'єднання з сервером", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Сервер не вибраний", "@serverNotSelected": {}, "shipments": "Shipments", "@shipments": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, - "shipped": "Shipped", + "shipped": "Відправлено", "@shipped": {}, "sku": "SKU", "@sku": {}, - "sounds": "Sounds", + "sounds": "Звуки", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Відтворити звук при скануванні", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Відтворити звук при помилці сервера", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Дата початку", "@startDate": {}, - "status": "Status", + "status": "Статус", "@status": {}, - "statusCode": "Status Code", + "statusCode": "Код статусу", "@statusCode": {}, "stock": "Stock", "@stock": { @@ -994,7 +994,7 @@ "@submitFeedback": {}, "suppliedParts": "Supplied Parts", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "Постачальник", "@supplier": {}, "supplierPart": "Supplier Part", "@supplierPart": {}, @@ -1006,47 +1006,47 @@ "@supplierPartUpdated": {}, "supplierParts": "Supplier Parts", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "Постачальники", "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, "switchCamera": "Switch Camera", "@switchCamera": {}, - "takePicture": "Take Picture", + "takePicture": "Зробити фото", "@takePicture": {}, "targetDate": "Target Date", "@targetDate": {}, "templatePart": "Parent Template Part", "@templatePart": {}, - "testName": "Test Name", + "testName": "Назва тесту", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "Тест завершився успішно або помилкою", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "Вимаганні тести", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "Результат тесту", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Показати результати перевірки товару на складі", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "Додати результат тесту", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "Відсутні результати тесту", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "Результати тесту недоступні", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "Помилка при завантаженні результатів тесту", "@testResultUploadFail": {}, "testResultUploadPass": "Test result uploaded", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "Тайм-аут", "@timeout": { "description": "" }, "toggleTorch": "Toggle Torch", "@toggleTorch": {}, - "tokenError": "Token Error", + "tokenError": "Помилка токену", "@tokenError": {}, "tokenMissing": "Missing Token", "@tokenMissing": {}, diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index f43a6d5..cca6071 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -254,7 +254,7 @@ "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Sửa tệp đính kèm", "@editAttachment": {}, "editCategory": "Sửa Danh mục", "@editCategory": {}, From 624655ec6b0a388cd9e85de0526021d8b10e7df0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Oct 2025 13:36:10 +1100 Subject: [PATCH 707/746] SalesOrderShipment (#697) * Add detail widget for SalesOrderShipment * Support editing of shipment details * Rearrange SalesOrderDetail page * Add support for attachments against shipment model * refactoring * Add shipment details page * Add user actions for shipments: - Check / uncheck - Take photo * Placeholder action to send shipment * Send shipment from app * Display pending shipments on the home screen * Improve rending for shipments list * Add class definition for SalesOrderAllocation * Display list of items allocated against SalesOrderShipment * Bump release notse * Click through to stock item * Bump version number * dart format * cleanup * Remove unused imports --- assets/release_notes.md | 8 + lib/api.dart | 2 + lib/api_form.dart | 13 +- lib/inventree/model.dart | 2 +- lib/inventree/sales_order.dart | 156 ++++++- lib/l10n/app_en.arb | 123 ++++-- lib/preferences.dart | 1 + lib/settings/home_settings.dart | 23 ++ lib/widget/attachment_widget.dart | 8 +- lib/widget/company/company_detail.dart | 2 +- .../company/manufacturer_part_detail.dart | 8 +- lib/widget/company/supplier_part_detail.dart | 8 +- lib/widget/home.dart | 34 ++ lib/widget/order/po_line_detail.dart | 2 +- lib/widget/order/sales_order_detail.dart | 41 +- lib/widget/order/so_allocation_list.dart | 69 ++++ lib/widget/order/so_line_detail.dart | 2 +- lib/widget/order/so_shipment_detail.dart | 384 ++++++++++++++++++ lib/widget/order/so_shipment_list.dart | 45 +- lib/widget/part/part_detail.dart | 2 +- lib/widget/stock/stock_detail.dart | 2 +- pubspec.yaml | 2 +- 22 files changed, 858 insertions(+), 79 deletions(-) create mode 100644 lib/widget/order/so_allocation_list.dart create mode 100644 lib/widget/order/so_shipment_detail.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 7869603..2897761 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,11 @@ +### 0.20.0 - October 2025 +--- + +- View pending shipments from the home screen +- Display detail view for shipments +- Adds ability to ship pending outgoing shipments +- Adds ability to mark outgoing shipments as "checked" or "unchecked" + ### 0.19.3 - September 2025 --- diff --git a/lib/api.dart b/lib/api.dart index a63f1cc..5d79a22 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -279,6 +279,8 @@ class InvenTreeAPI { String get username => (userInfo["username"] ?? "") as String; + int get userId => (userInfo["pk"] ?? -1) as int; + // Map of server information Map serverInfo = {}; diff --git a/lib/api_form.dart b/lib/api_form.dart index e227289..7852c45 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -586,6 +586,8 @@ class APIFormField { return InvenTreeSupplierPart().defaultListFilters(); case InvenTreeStockItem.MODEL_TYPE: return InvenTreeStockItem().defaultListFilters(); + case InvenTreeSalesOrder.MODEL_TYPE: + return InvenTreeSalesOrder().defaultListFilters(); default: break; } @@ -727,7 +729,7 @@ class APIFormField { return ListTile( title: Text(shipment.reference), subtitle: Text(shipment.tracking_number), - trailing: shipment.shipped ? Text(shipment.shipment_date!) : null, + trailing: shipment.isShipped ? Text(shipment.shipment_date!) : null, ); case "owner": String name = (data["name"] ?? "") as String; @@ -754,6 +756,15 @@ class APIFormField { subtitle: Text(project_code.description), leading: Icon(TablerIcons.list), ); + case InvenTreeSalesOrder.MODEL_TYPE: + var so = InvenTreeSalesOrder.fromJson(data); + return ListTile( + title: Text(so.reference), + subtitle: Text(so.description), + leading: InvenTreeAPI().getThumbnail( + so.customer?.thumbnail ?? so.customer?.image ?? "", + ), + ); default: return ListTile( title: Text( diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 532d1c2..e08a053 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -601,7 +601,7 @@ class InvenTreeModel { // POST data to update the model Future update({ - Map values = const {}, + Map values = const {}, int? expectedStatusCode = 200, }) async { var url = path.join(URL, pk.toString()); diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 51412db..8b661f4 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -5,6 +5,9 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/orders.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/stock.dart"; +import "package:inventree/widget/order/so_shipment_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/order/extra_line_detail.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; @@ -269,6 +272,19 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { @override String get URL => "/order/so/shipment/"; + String get SHIP_SHIPMENT_URL => "/order/so/shipment/${pk}/ship/"; + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => SOShipmentDetailWidget(this)), + ); + } + + @override + List get rolesRequired => ["sales_order"]; + static const String MODEL_TYPE = "salesordershipment"; @override @@ -284,6 +300,18 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { return fields; } + int get orderId => getInt("order"); + + InvenTreeSalesOrder? get order { + dynamic order_detail = jsondata["order_detail"]; + + if (order_detail == null) { + return null; + } else { + return InvenTreeSalesOrder.fromJson(order_detail as Map); + } + } + String get reference => getString("reference"); String get tracking_number => getString("tracking_number"); @@ -292,7 +320,113 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { String? get shipment_date => getString("shipment_date"); - bool get shipped => shipment_date != null && shipment_date!.isNotEmpty; + String? get delivery_date => getString("delivery_date"); + + int? get checked_by_id => getInt("checked_by"); + + bool get isChecked => checked_by_id != null && checked_by_id! > 0; + + bool get isShipped => shipment_date != null && shipment_date!.isNotEmpty; + + bool get isDelivered => delivery_date != null && delivery_date!.isNotEmpty; +} + +/* + * Class representing an allocation of stock against a SalesOrderShipment + */ +class InvenTreeSalesOrderAllocation extends InvenTreeAttachment { + InvenTreeSalesOrderAllocation() : super(); + + InvenTreeSalesOrderAllocation.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => + InvenTreeSalesOrderAllocation.fromJson(json); + + @override + String get URL => "/order/so-allocation/"; + + @override + List get rolesRequired => ["sales_order"]; + + @override + Map defaultFilters() { + return { + "part_detail": "true", + "order_detail": "true", + "item_detail": "true", + "location_detail": "true", + }; + } + + static const String MODEL_TYPE = "salesorderallocation"; + + int get orderId => getInt("order"); + + InvenTreeSalesOrder? get order { + dynamic order_detail = jsondata["order_detail"]; + + if (order_detail == null) { + return null; + } else { + return InvenTreeSalesOrder.fromJson(order_detail as Map); + } + } + + int get stockItemId => getInt("item"); + + InvenTreeStockItem? get stockItem { + dynamic item_detail = jsondata["item_detail"]; + + if (item_detail == null) { + return null; + } else { + return InvenTreeStockItem.fromJson(item_detail as Map); + } + } + + int get partId => getInt("part"); + + InvenTreePart? get part { + dynamic part_detail = jsondata["part_detail"]; + + if (part_detail == null) { + return null; + } else { + return InvenTreePart.fromJson(part_detail as Map); + } + } + + int get shipmentId => getInt("shipment"); + + bool get hasShipment => shipmentId > 0; + + InvenTreeSalesOrderShipment? get shipment { + dynamic shipment_detail = jsondata["shipment_detail"]; + + if (shipment_detail == null) { + return null; + } else { + return InvenTreeSalesOrderShipment.fromJson( + shipment_detail as Map, + ); + } + } + + int get locationId => getInt("location"); + + InvenTreeStockLocation? get location { + dynamic location_detail = jsondata["location_detail"]; + + if (location_detail == null) { + return null; + } else { + return InvenTreeStockLocation.fromJson( + location_detail as Map, + ); + } + } } /* @@ -319,3 +453,23 @@ class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { ? "attachment/" : "order/so/attachment/"; } + +class InvenTreeSalesOrderShipmentAttachment extends InvenTreeAttachment { + InvenTreeSalesOrderShipmentAttachment() : super(); + + InvenTreeSalesOrderShipmentAttachment.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => + InvenTreeSalesOrderShipmentAttachment.fromJson(json); + + @override + String get REFERENCE_FIELD => "shipment"; + + @override + String get REF_MODEL_TYPE => "salesordershipment"; + + @override + String get URL => "attachment/"; +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fbac909..83fef3a 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -65,6 +65,9 @@ "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, @@ -331,6 +334,15 @@ "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + + "deleteImage": "Delete Image", + "@deleteImage": {}, + "deletePart": "Delete Part", "@deletePart": {}, @@ -340,6 +352,9 @@ "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, + "description": "Description", "@description": {}, @@ -548,6 +563,12 @@ "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, @@ -647,6 +668,12 @@ "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", "@issue": {}, @@ -769,6 +796,12 @@ "@name": { }, + "no": "No", + "@no": {}, + + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Not Connected", "@notConnected": {}, @@ -780,8 +813,8 @@ "notifications": "Notifications", "@notifications": {}, - "notificationsEmpty": "No unread notifications", - "@notificationsEmpty": {}, + "notificationsEmpty": "No unread notifications", + "@notificationsEmpty": {}, "noResponse": "No Response from Server", "@noResponse": {}, @@ -792,6 +825,12 @@ "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, + "noSubcategories": "No Subcategories", "@noSubcategories": {}, @@ -927,6 +966,9 @@ "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, @@ -1186,20 +1228,20 @@ "salesOrders": "Sales Orders", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", - "@salesOrderEnable": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", - "@salesOrderEnableDetail": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", - "@salesOrderShowCamera": {}, + "salesOrderShowCamera": "Camera Shortcut", + "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", - "@salesOrderShowCameraDetail": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, "salesOrderSettings": "Sales order settings", - "@salesOrderSettings": {}, + "@salesOrderSettings": {}, "salesOrderCreate": "New Sales Order", "@saleOrderCreate": {}, @@ -1338,12 +1380,48 @@ "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, + "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, + "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, + "shipped": "Shipped", "@shipped": {}, @@ -1555,6 +1633,9 @@ "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1642,6 +1723,9 @@ "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, + "price": "Price", "@price": {}, @@ -1682,20 +1766,5 @@ "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } diff --git a/lib/preferences.dart b/lib/preferences.dart index e10c3d9..bf0d8ae 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -10,6 +10,7 @@ import "package:path/path.dart"; const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; const String INV_HOME_SHOW_PO = "homeShowPo"; const String INV_HOME_SHOW_SO = "homeShowSo"; +const String INV_HOME_SHOW_SHIPMENTS = "homeShowShipments"; const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 58740d4..a4da9d2 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -20,6 +20,7 @@ class _HomeScreenSettingsState extends State { bool homeShowSubscribed = true; bool homeShowPo = true; bool homeShowSo = true; + bool homeShowShipments = true; bool homeShowSuppliers = true; bool homeShowManufacturers = true; bool homeShowCustomers = true; @@ -46,6 +47,11 @@ class _HomeScreenSettingsState extends State { homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; + + homeShowShipments = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SHIPMENTS, true) + as bool; + homeShowManufacturers = await InvenTreeSettingsManager().getValue( INV_HOME_SHOW_MANUFACTURERS, @@ -118,6 +124,23 @@ class _HomeScreenSettingsState extends State { }, ), ), + ListTile( + title: Text(L10().homeShowShipments), + subtitle: Text(L10().homeShowShipmentsDescription), + leading: Icon(TablerIcons.cube_send), + trailing: Switch( + value: homeShowShipments, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_HOME_SHOW_SHIPMENTS, + value, + ); + setState(() { + homeShowShipments = value; + }); + }, + ), + ), ListTile( title: Text(L10().homeShowSuppliers), subtitle: Text(L10().homeShowSuppliersDescription), diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index b4c9746..b66462f 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -3,7 +3,6 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; -import "package:url_launcher/url_launcher.dart"; import "package:inventree/api.dart"; import "package:inventree/l10.dart"; @@ -212,17 +211,14 @@ class _AttachmentWidgetState extends RefreshableState { }, ), ); - } else if (attachment.link.isNotEmpty) { + } else if (attachment.hasLink) { tiles.add( ListTile( title: Text(attachment.link), subtitle: Text(attachment.comment), leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () async { - var uri = Uri.tryParse(attachment.link.trimLeft()); - if (uri != null && await canLaunchUrl(uri)) { - await launchUrl(uri); - } + attachment.openLink(); }, onLongPress: () { showOptionsMenu(context, attachment); diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 64356d7..5d06e58 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -287,7 +287,7 @@ class _CompanyDetailState extends RefreshableState { } // External link - if (widget.company.link.isNotEmpty) { + if (widget.company.hasLink) { tiles.add( ListTile( title: Text(L10().link), diff --git a/lib/widget/company/manufacturer_part_detail.dart b/lib/widget/company/manufacturer_part_detail.dart index 5267a31..9cc6bc2 100644 --- a/lib/widget/company/manufacturer_part_detail.dart +++ b/lib/widget/company/manufacturer_part_detail.dart @@ -12,7 +12,6 @@ import "package:inventree/inventree/part.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/progress.dart"; -import "package:url_launcher/url_launcher.dart"; /* * Detail widget for viewing a single ManufacturerPart instance @@ -163,16 +162,13 @@ class _ManufacturerPartDisplayState ); } - if (widget.manufacturerPart.link.isNotEmpty) { + if (widget.manufacturerPart.hasLink) { tiles.add( ListTile( title: Text(widget.manufacturerPart.link), leading: Icon(TablerIcons.link, color: COLOR_ACTION), onTap: () async { - var uri = Uri.tryParse(widget.manufacturerPart.link); - if (uri != null && await canLaunchUrl(uri)) { - await launchUrl(uri); - } + widget.manufacturerPart.openLink(); }, ), ); diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index 92cf2de..b2a965f 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -2,7 +2,6 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/widget/link_icon.dart"; -import "package:url_launcher/url_launcher.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; @@ -239,7 +238,7 @@ class _SupplierPartDisplayState ); } - if (widget.supplierPart.link.isNotEmpty) { + if (widget.supplierPart.hasLink) { tiles.add( ListTile( title: Text(L10().link), @@ -247,10 +246,7 @@ class _SupplierPartDisplayState leading: Icon(TablerIcons.link, color: COLOR_ACTION), trailing: LinkIcon(external: true), onTap: () async { - var uri = Uri.tryParse(widget.supplierPart.link); - if (uri != null && await canLaunchUrl(uri)) { - await launchUrl(uri); - } + widget.supplierPart.openLink(); }, ), ); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 3b29d86..15c4d3f 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -14,6 +14,7 @@ import "package:inventree/preferences.dart"; import "package:inventree/l10.dart"; import "package:inventree/settings/select_server.dart"; import "package:inventree/user_profile.dart"; +import "package:inventree/widget/order/so_shipment_list.dart"; import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/drawer.dart"; @@ -55,6 +56,7 @@ class _InvenTreeHomePageState extends State bool homeShowPo = false; bool homeShowSo = false; + bool homeShowShipments = false; bool homeShowSubscribed = false; bool homeShowManufacturers = false; bool homeShowCustomers = false; @@ -112,6 +114,20 @@ class _InvenTreeHomePageState extends State ); } + void _showPendingShipments(BuildContext context) { + if (!InvenTreeAPI().checkConnection()) return; + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SOShipmentListWidget( + title: L10().shipmentsPending, + filters: {"order_outstanding": "true", "shipped": "false"}, + ), + ), + ); + } + void _showSuppliers(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; @@ -167,6 +183,11 @@ class _InvenTreeHomePageState extends State homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; + + homeShowShipments = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SHIPMENTS, true) + as bool; + homeShowManufacturers = await InvenTreeSettingsManager().getValue( INV_HOME_SHOW_MANUFACTURERS, @@ -325,6 +346,19 @@ class _InvenTreeHomePageState extends State ); } + if (homeShowShipments && InvenTreeSalesOrderShipment().canView) { + tiles.add( + _listTile( + context, + L10().shipmentsPending, + TablerIcons.cube_send, + callback: () { + _showPendingShipments(context); + }, + ), + ); + } + // Suppliers if (homeShowSuppliers && InvenTreePurchaseOrder().canView) { tiles.add( diff --git a/lib/widget/order/po_line_detail.dart b/lib/widget/order/po_line_detail.dart index 7faf497..16bac28 100644 --- a/lib/widget/order/po_line_detail.dart +++ b/lib/widget/order/po_line_detail.dart @@ -241,7 +241,7 @@ class _POLineDetailWidgetState extends RefreshableState { } // External link - if (widget.item.link.isNotEmpty) { + if (widget.item.hasLink) { tiles.add( ListTile( title: Text(L10().link), diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index bc23961..ec18561 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -375,24 +375,7 @@ class _SalesOrderDetailState extends RefreshableState { Color lineColor = widget.order.complete ? COLOR_SUCCESS : COLOR_WARNING; - // Shipment progress - if (widget.order.shipmentCount > 0) { - tiles.add( - ListTile( - title: Text(L10().shipments), - subtitle: ProgressBar( - widget.order.completedShipmentCount.toDouble(), - maximum: widget.order.shipmentCount.toDouble(), - ), - leading: Icon(TablerIcons.truck_delivery), - trailing: LargeText( - "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", - color: lineColor, - ), - ), - ); - } - + // Line items progress tiles.add( ListTile( title: Text(L10().lineItems), @@ -408,6 +391,24 @@ class _SalesOrderDetailState extends RefreshableState { ), ); + // Shipment progress + if (widget.order.shipmentCount > 0) { + tiles.add( + ListTile( + title: Text(L10().shipments), + subtitle: ProgressBar( + widget.order.completedShipmentCount.toDouble(), + maximum: widget.order.shipmentCount.toDouble(), + ), + leading: Icon(TablerIcons.cube_send), + trailing: LargeText( + "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", + color: lineColor, + ), + ), + ); + } + // Extra line items tiles.add( ListTile( @@ -522,8 +523,8 @@ class _SalesOrderDetailState extends RefreshableState { List getTabIcons(BuildContext context) { return [ Tab(text: L10().details), - Tab(text: L10().shipments), Tab(text: L10().lineItems), + Tab(text: L10().shipments), ]; } @@ -531,8 +532,8 @@ class _SalesOrderDetailState extends RefreshableState { List getTabs(BuildContext context) { return [ ListView(children: orderTiles(context)), - PaginatedSOShipmentList({"order": widget.order.pk.toString()}), PaginatedSOLineList({"order": widget.order.pk.toString()}), + PaginatedSOShipmentList({"order": widget.order.pk.toString()}), ]; } } diff --git a/lib/widget/order/so_allocation_list.dart b/lib/widget/order/so_allocation_list.dart new file mode 100644 index 0000000..5076f07 --- /dev/null +++ b/lib/widget/order/so_allocation_list.dart @@ -0,0 +1,69 @@ +import "package:flutter/material.dart"; +import "package:inventree/api.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/inventree/stock.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/link_icon.dart"; +import "package:inventree/widget/paginator.dart"; + +class PaginatedSOAllocationList extends PaginatedSearchWidget { + const PaginatedSOAllocationList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().allocatedStock; + + @override + _PaginatedSOAllocationListState createState() => + _PaginatedSOAllocationListState(); +} + +class _PaginatedSOAllocationListState + extends PaginatedSearchState { + _PaginatedSOAllocationListState() : super(); + + @override + String get prefix => "so_allocation_"; + + @override + Map get orderingOptions => {}; + + @override + Map> get filterOptions => {}; + + @override + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeSalesOrderAllocation().listPaginated( + limit, + offset, + filters: params, + ); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeSalesOrderAllocation allocation = + model as InvenTreeSalesOrderAllocation; + + InvenTreePart? part = allocation.part; + InvenTreeStockItem? stockItem = allocation.stockItem; + + return ListTile( + title: Text(part?.fullname ?? ""), + subtitle: Text(part?.description ?? ""), + onTap: () async { + stockItem?.goToDetailPage(context); + }, + leading: InvenTreeAPI().getThumbnail(allocation.part?.thumbnail ?? ""), + trailing: LargeText(stockItem?.serialOrQuantityDisplay() ?? ""), + ); + } +} diff --git a/lib/widget/order/so_line_detail.dart b/lib/widget/order/so_line_detail.dart index ae0d302..bc6fd6f 100644 --- a/lib/widget/order/so_line_detail.dart +++ b/lib/widget/order/so_line_detail.dart @@ -244,7 +244,7 @@ class _SOLineDetailWidgetState extends RefreshableState { } // External link - if (widget.item.link.isNotEmpty) { + if (widget.item.hasLink) { tiles.add( ListTile( title: Text(L10().link), diff --git a/lib/widget/order/so_shipment_detail.dart b/lib/widget/order/so_shipment_detail.dart new file mode 100644 index 0000000..9116fb7 --- /dev/null +++ b/lib/widget/order/so_shipment_detail.dart @@ -0,0 +1,384 @@ +/* + * Widget for displaying detail view of a single SalesOrderShipment + */ + +import "package:flutter/material.dart"; +import "package:flutter_speed_dial/flutter_speed_dial.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/sales_order.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; +import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/link_icon.dart"; +import "package:inventree/widget/notes_widget.dart"; +import "package:inventree/widget/order/so_allocation_list.dart"; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/snacks.dart"; + +class SOShipmentDetailWidget extends StatefulWidget { + const SOShipmentDetailWidget(this.shipment, {Key? key}) : super(key: key); + + final InvenTreeSalesOrderShipment shipment; + + @override + _SOShipmentDetailWidgetState createState() => _SOShipmentDetailWidgetState(); +} + +class _SOShipmentDetailWidgetState + extends RefreshableState { + _SOShipmentDetailWidgetState(); + + // The SalesOrder associated with this shipment + InvenTreeSalesOrder? order; + + int attachmentCount = 0; + bool showCameraShortcut = true; + + @override + String getAppBarTitle() => L10().shipment; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.shipment.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + onPressed: () { + _editShipment(context); + }, + ), + ); + } + + return actions; + } + + Future _editShipment(BuildContext context) async { + var fields = widget.shipment.formFields(); + + fields["order"]?["hidden"] = true; + + widget.shipment.editForm( + context, + L10().shipmentEdit, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().shipmentUpdated, success: true); + }, + ); + } + + @override + Future request(BuildContext context) async { + await widget.shipment.reload(); + + showCameraShortcut = await InvenTreeSettingsManager().getBool( + INV_SO_SHOW_CAMERA, + true, + ); + + final so = await InvenTreeSalesOrder().get(widget.shipment.orderId); + + if (mounted) { + setState(() { + order = (so is InvenTreeSalesOrder ? so : null); + }); + } + + InvenTreeSalesOrderShipmentAttachment() + .countAttachments(widget.shipment.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } + + /// Upload an image for this shipment + Future _uploadImage(BuildContext context) async { + InvenTreeSalesOrderShipmentAttachment() + .uploadImage(widget.shipment.pk, prefix: widget.shipment.reference) + .then((result) => refresh(context)); + } + + /// Mark this shipment as shipped + Future _sendShipment(BuildContext context) async { + Map fields = { + "shipment_date": { + "value": widget.shipment.isShipped + ? widget.shipment.shipment_date! + : DateTime.now().toIso8601String().split("T").first, + }, + "tracking_number": {"value": widget.shipment.tracking_number}, + "invoice_number": {"value": widget.shipment.invoice_number}, + }; + + launchApiForm( + context, + L10().shipmentSend, + widget.shipment.SHIP_SHIPMENT_URL, + fields, + method: "POST", + onSuccess: (data) { + refresh(context); + showSnackIcon(L10().shipmentUpdated, success: true); + }, + ); + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (!widget.shipment.canEdit) { + // Exit early if we do not have edit permissions + return actions; + } + + if (showCameraShortcut) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.camera, color: Colors.blue), + label: L10().takePicture, + onTap: () async { + _uploadImage(context); + }, + ), + ); + } + + // Check shipment + if (!widget.shipment.isChecked && !widget.shipment.isShipped) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.check, color: Colors.green), + label: L10().shipmentCheck, + onTap: () async { + widget.shipment + .update(values: {"checked_by": InvenTreeAPI().userId}) + .then((_) { + showSnackIcon(L10().shipmentUpdated, success: true); + refresh(context); + }); + }, + ), + ); + } + + // Uncheck shipment + if (widget.shipment.isChecked && !widget.shipment.isShipped) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.x, color: Colors.red), + label: L10().shipmentUncheck, + onTap: () async { + widget.shipment.update(values: {"checked_by": null}).then((_) { + showSnackIcon(L10().shipmentUpdated, success: true); + refresh(context); + }); + }, + ), + ); + } + + // Send shipment + if (!widget.shipment.isShipped) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.truck_delivery, color: Colors.green), + label: L10().shipmentSend, + onTap: () async { + _sendShipment(context); + }, + ), + ); + } + + // TODO: Cancel shipment + + return actions; + } + + List shipmentTiles(BuildContext context) { + List tiles = []; + + final bool checked = widget.shipment.isChecked; + final bool shipped = widget.shipment.isShipped; + final bool delivered = widget.shipment.isDelivered; + + // Order information + if (order != null) { + // Add SalesOrder information + + tiles.add( + Card( + child: ListTile( + title: Text(order!.reference), + subtitle: Text(order!.description), + leading: api.getThumbnail(order!.customer?.thumbnail ?? ""), + trailing: LargeText( + api.SalesOrderStatus.label(order!.status), + color: api.SalesOrderStatus.color(order!.status), + ), + onTap: () { + order!.goToDetailPage(context); + }, + ), + ), + ); + } + + // Shipment reference number + tiles.add( + ListTile( + title: Text(L10().shipmentReference), + trailing: LargeText(widget.shipment.reference), + leading: Icon(TablerIcons.hash), + ), + ); + + if (widget.shipment.invoice_number.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().invoiceNumber), + trailing: LargeText(widget.shipment.invoice_number), + leading: Icon(TablerIcons.invoice), + ), + ); + } + + // Tracking Number + if (widget.shipment.tracking_number.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().trackingNumber), + trailing: LargeText(widget.shipment.tracking_number), + leading: Icon(TablerIcons.truck_delivery), + ), + ); + } + + if (checked || !shipped) { + tiles.add( + ListTile( + title: Text(L10().shipmentChecked), + trailing: LargeText( + checked ? L10().yes : L10().no, + color: checked ? COLOR_SUCCESS : COLOR_WARNING, + ), + leading: Icon( + checked ? TablerIcons.circle_check : TablerIcons.circle_x, + color: checked ? COLOR_SUCCESS : COLOR_WARNING, + ), + ), + ); + } + + tiles.add( + ListTile( + title: Text(L10().shipmentDate), + trailing: LargeText( + shipped ? widget.shipment.shipment_date! : L10().notApplicable, + ), + leading: Icon( + shipped ? TablerIcons.calendar_check : TablerIcons.calendar_cancel, + color: shipped ? COLOR_SUCCESS : COLOR_WARNING, + ), + ), + ); + + tiles.add( + ListTile( + title: Text(L10().deliveryDate), + trailing: LargeText( + delivered ? widget.shipment.delivery_date! : L10().notApplicable, + ), + leading: Icon( + delivered ? TablerIcons.calendar_check : TablerIcons.calendar_cancel, + color: delivered ? COLOR_SUCCESS : COLOR_WARNING, + ), + ), + ); + + // External link + if (widget.shipment.hasLink) { + tiles.add( + ListTile( + title: Text(L10().link), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + widget.shipment.openLink(); + }, + ), + ); + } + + // Notes tile + tiles.add( + ListTile( + title: Text(L10().notes), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => NotesWidget(widget.shipment), + ), + ); + }, + ), + ); + + // Attachments + tiles.add( + ListTile( + title: Text(L10().attachments), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeSalesOrderShipmentAttachment(), + widget.shipment.pk, + widget.shipment.reference, + widget.shipment.canEdit, + ), + ), + ); + }, + ), + ); + + return tiles; + } + + @override + List getTabIcons(BuildContext context) { + return [Tab(text: L10().details), Tab(text: L10().allocatedStock)]; + } + + @override + List getTabs(BuildContext context) { + return [ + ListView(children: shipmentTiles(context)), + PaginatedSOAllocationList({ + "order": widget.shipment.orderId.toString(), + "shipment": widget.shipment.pk.toString(), + }), + ]; + } +} diff --git a/lib/widget/order/so_shipment_list.dart b/lib/widget/order/so_shipment_list.dart index 126e247..221d748 100644 --- a/lib/widget/order/so_shipment_list.dart +++ b/lib/widget/order/so_shipment_list.dart @@ -7,6 +7,35 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/l10.dart"; +import "package:inventree/widget/refreshable_state.dart"; + +class SOShipmentListWidget extends StatefulWidget { + const SOShipmentListWidget({ + this.title = "", + this.filters = const {}, + Key? key, + }) : super(key: key); + + final Map filters; + + final String title; + + @override + _SOShipmentListWidgetState createState() => _SOShipmentListWidgetState(); +} + +class _SOShipmentListWidgetState + extends RefreshableState { + _SOShipmentListWidgetState(); + + @override + String getAppBarTitle() => widget.title; + + @override + Widget getBody(BuildContext context) { + return PaginatedSOShipmentList(widget.filters); + } +} class PaginatedSOShipmentList extends PaginatedSearchWidget { const PaginatedSOShipmentList(Map filters) @@ -51,15 +80,21 @@ class _PaginatedSOShipmentListState Widget buildItem(BuildContext context, InvenTreeModel model) { InvenTreeSalesOrderShipment shipment = model as InvenTreeSalesOrderShipment; + InvenTreeSalesOrder? order = shipment.order; return ListTile( - title: Text(shipment.reference), - subtitle: Text(shipment.tracking_number), - leading: shipment.shipped + title: Text( + "${order?.reference ?? L10().salesOrder} - ${shipment.reference}", + ), + subtitle: Text(order?.description ?? L10().description), + onTap: () async { + shipment.goToDetailPage(context); + }, + leading: shipment.isShipped ? Icon(TablerIcons.calendar_check, color: COLOR_SUCCESS) : Icon(TablerIcons.calendar_cancel, color: COLOR_WARNING), - trailing: shipment.shipped + trailing: shipment.isShipped ? LargeText(shipment.shipment_date ?? "") - : null, + : LargeText(L10().pending), ); } } diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 5d59aed..e6c7d6e 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -524,7 +524,7 @@ class _PartDisplayState extends RefreshableState { } // External link? - if (part.link.isNotEmpty) { + if (part.hasLink) { tiles.add( ListTile( title: Text("${part.link}"), diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index e91bd98..19f1592 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -750,7 +750,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (widget.item.link.isNotEmpty) { + if (widget.item.hasLink) { tiles.add( ListTile( title: Text("${widget.item.link}"), diff --git a/pubspec.yaml b/pubspec.yaml index 0b9b3d5..92de267 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.19.3+102 +version: 0.20.0+103 environment: sdk: ^3.8.1 From a078a9d12655b4ff8a59c81eab019d645d06ef37 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Oct 2025 13:48:10 +1100 Subject: [PATCH 708/746] Update release notes (#698) --- assets/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/release_notes.md b/assets/release_notes.md index 2897761..3020661 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -5,6 +5,7 @@ - Display detail view for shipments - Adds ability to ship pending outgoing shipments - Adds ability to mark outgoing shipments as "checked" or "unchecked" +- Updated translations ### 0.19.3 - September 2025 --- From 4a094f4a773bfb940bc240b7733efc120aa6924c Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 26 Oct 2025 18:41:29 +1100 Subject: [PATCH 709/746] New Crowdin updates (#699) * New translations app_en.arb (Russian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 68 +++++++++++++++--- lib/l10n/bg_BG/app_bg_BG.arb | 68 +++++++++++++++--- lib/l10n/cs_CZ/app_cs_CZ.arb | 68 +++++++++++++++--- lib/l10n/da_DK/app_da_DK.arb | 68 +++++++++++++++--- lib/l10n/de_DE/app_de_DE.arb | 68 +++++++++++++++--- lib/l10n/el_GR/app_el_GR.arb | 68 +++++++++++++++--- lib/l10n/es_ES/app_es_ES.arb | 68 +++++++++++++++--- lib/l10n/es_MX/app_es_MX.arb | 68 +++++++++++++++--- lib/l10n/et_EE/app_et_EE.arb | 68 +++++++++++++++--- lib/l10n/fa_IR/app_fa_IR.arb | 68 +++++++++++++++--- lib/l10n/fi_FI/app_fi_FI.arb | 68 +++++++++++++++--- lib/l10n/fr_FR/app_fr_FR.arb | 68 +++++++++++++++--- lib/l10n/he_IL/app_he_IL.arb | 68 +++++++++++++++--- lib/l10n/hi_IN/app_hi_IN.arb | 68 +++++++++++++++--- lib/l10n/hu_HU/app_hu_HU.arb | 68 +++++++++++++++--- lib/l10n/id_ID/app_id_ID.arb | 68 +++++++++++++++--- lib/l10n/it_IT/app_it_IT.arb | 68 +++++++++++++++--- lib/l10n/ja_JP/app_ja_JP.arb | 68 +++++++++++++++--- lib/l10n/ko_KR/app_ko_KR.arb | 136 +++++++++++++++++++++++------------ lib/l10n/lt_LT/app_lt_LT.arb | 68 +++++++++++++++--- lib/l10n/lv_LV/app_lv_LV.arb | 68 +++++++++++++++--- lib/l10n/nl_NL/app_nl_NL.arb | 68 +++++++++++++++--- lib/l10n/no_NO/app_no_NO.arb | 68 +++++++++++++++--- lib/l10n/pl_PL/app_pl_PL.arb | 68 +++++++++++++++--- lib/l10n/pt_BR/app_pt_BR.arb | 68 +++++++++++++++--- lib/l10n/pt_PT/app_pt_PT.arb | 68 +++++++++++++++--- lib/l10n/ro_RO/app_ro_RO.arb | 68 +++++++++++++++--- lib/l10n/ru_RU/app_ru_RU.arb | 68 +++++++++++++++--- lib/l10n/sk_SK/app_sk_SK.arb | 68 +++++++++++++++--- lib/l10n/sl_SI/app_sl_SI.arb | 68 +++++++++++++++--- lib/l10n/sr_CS/app_sr_CS.arb | 68 +++++++++++++++--- lib/l10n/sv_SE/app_sv_SE.arb | 68 +++++++++++++++--- lib/l10n/th_TH/app_th_TH.arb | 70 ++++++++++++++---- lib/l10n/tr_TR/app_tr_TR.arb | 68 +++++++++++++++--- lib/l10n/uk_UA/app_uk_UA.arb | 68 +++++++++++++++--- lib/l10n/vi_VN/app_vi_VN.arb | 68 +++++++++++++++--- lib/l10n/zh_CN/app_zh_CN.arb | 68 +++++++++++++++--- lib/l10n/zh_TW/app_zh_TW.arb | 68 +++++++++++++++--- 38 files changed, 2201 insertions(+), 453 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index b66d8f8..c91a4af 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 26b3b50..aaa8f5c 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index ecd7afe..6d05582 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Přidělit zásoby", "@allocateStock": {}, + "allocatedStock": "Přidělené zásoby", + "@allocatedStock": {}, "appReleaseNotes": "Zobrazit poznámky k verzi aplikace", "@appReleaseNotes": {}, "appSettings": "Nastavení aplikace", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Odstranění se nezdařilo", "@deleteFailed": {}, + "deleteImageConfirmation": "Opravdu chcete odstranit tento obrázek?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Smazat obrázek", + "@deleteImageTooltip": {}, + "deleteImage": "Smazat obrázek", + "@deleteImage": {}, "deletePart": "Odstranit díl", "@deletePart": {}, "deletePartDetail": "Odstranit tento díl z databáze", "@deletePartDetail": {}, "deleteSuccess": "Odstránění bylo úspěšné", "@deleteSuccess": {}, + "deliveryDate": "Datum dodání", + "@deliveryDate": {}, "description": "Popis", "@description": {}, "destination": "Místo určení", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", "@homeShowPoDescription": {}, + "homeShowShipments": "Zobrazit zásilky", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Zobrazit čekající zásilky na domovské stránce", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Zobrazit prodejní objednávky", "@homeShowSo": {}, "homeShowSoDescription": "Zobrazit tlačítko pro objednávku na domovské obrazovce", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Neplatné uživatelské jméno nebo heslo.", "@invalidUsernamePassword": {}, + "invoice": "Faktura", + "@invoice": {}, + "invoiceNumber": "Číslo faktury", + "@invoiceNumber": {}, "issue": "Vystavit", "@issue": {}, "issueDate": "Datum nahlášení", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Jméno", "@name": {}, + "no": "Ne", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nepřipojeno", "@notConnected": {}, "notes": "Poznámky", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Obrázek není k dispozici", "@noImageAvailable": {}, + "noPricingAvailable": "Žádné ceny nejsou k dispozici", + "@noPricingAvailable": {}, + "noPricingDataFound": "Pro tuto komponentu nebyly nalezeny žádné cenové údaje", + "@noPricingDataFound": {}, "noSubcategories": "Žádná podkategorie", "@noSubcategories": {}, "noSubcategoriesAvailable": "Žádné podkategorie nejsou k dispozici", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Heslo nemůže být prázdné", "@passwordEmpty": {}, + "pending": "Čekající", + "@pending": {}, "permissionAccountDenied": "Váš účet nemá potřebná oprávnění k provedení této akce", "@permissionAccountDenied": {}, "permissionRequired": "Vyžadováno oprávnění", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server není vybrán", "@serverNotSelected": {}, + "shipment": "Zásilka", + "@shipment": {}, "shipments": "Dodávky", "@shipments": {}, + "shipmentsPending": "Čekající zásilky", + "@shipmentsPending": {}, "shipmentAdd": "Přidat dodávku", "@shipmentAdd": {}, + "shipmentCheck": "Zkontrolovat zásilku", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Označit tuto zásilku jako zkontrolovanou", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Zásilka zkontrolována", + "@shipmentChecked": {}, + "shipmentDate": "Datum odeslání", + "@shipmentDate": {}, + "shipmentEdit": "Upravit zásilku", + "@shipmentEdit": {}, + "shipmentReference": "Referenční číslo zásilky", + "@shipmentReference": {}, + "shipmentSend": "Odeslat zásilku", + "@shipmentSend": {}, + "shipmentUncheck": "Odznačit zásilku", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Označit tuto zásilku jako odznačenou", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Zásilka aktualizována", + "@shipmentUpdated": {}, "shipped": "Odesláno", "@shipped": {}, "sku": "Číslo zboží (SKU)", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Celková cena", "@totalPrice": {}, + "trackingNumber": "Sledovací číslo", + "@trackingNumber": {}, "transfer": "Převod", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Webová stránka", "@website": {}, + "yes": "Ano", + "@yes": {}, "price": "Cena", "@price": {}, "priceRange": "Cenový rozsah", @@ -1141,15 +1197,5 @@ "currency": "Měna", "@currency": {}, "priceBreaks": "Cena sleva", - "@priceBreaks": {}, - "noPricingAvailable": "Žádné ceny nejsou k dispozici", - "@noPricingAvailable": {}, - "noPricingDataFound": "Pro tuto komponentu nebyly nalezeny žádné cenové údaje", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Opravdu chcete odstranit tento obrázek?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Smazat obrázek", - "@deleteImageTooltip": {}, - "deleteImage": "Smazat obrázek", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 9f58398..7683b84 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Tildel lager", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Vis app-udgivelsesnoter", "@appReleaseNotes": {}, "appSettings": "Appindstillinger", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Sletning lykkedes", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Beskrivelse", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Vis indkøbsordreknap på startskærmen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ugyldigt brugernavn/adgangskode-kombination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 3bb7820..172b055 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Bestand zuweisen", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "App-Versionshinweise anzeigen", "@appReleaseNotes": {}, "appSettings": "App-Einstellungen", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Löschvorgang fehlgeschlagen", "@deleteFailed": {}, + "deleteImageConfirmation": "Möchten Sie dieses Bild wirklich löschen?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Bild löschen", + "@deleteImageTooltip": {}, + "deleteImage": "Bild löschen", + "@deleteImage": {}, "deletePart": "Teil löschen", "@deletePart": {}, "deletePartDetail": "Dieses Teil aus der Datenbank löschen", "@deletePartDetail": {}, "deleteSuccess": "Löschvorgang erfolgreich", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Beschreibung", "@description": {}, "destination": "Zielort", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Aufträge anzeigen", "@homeShowSo": {}, "homeShowSoDescription": "Verkaufsknopf auf dem Startbildschirm anzeigen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Aufgeben", "@issue": {}, "issueDate": "Ausstellungsdatum", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, "notes": "Notizen", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Kein Bild verfügbar", "@noImageAvailable": {}, + "noPricingAvailable": "Keine Preisinformation verfügbar", + "@noPricingAvailable": {}, + "noPricingDataFound": "Keine Preisdaten für diesen Teil gefunden", + "@noPricingDataFound": {}, "noSubcategories": "Keine Unter-Kategorien", "@noSubcategories": {}, "noSubcategoriesAvailable": "Keine Unter-Kategorien verfügbar", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Passwort darf nicht leer sein", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", "@permissionAccountDenied": {}, "permissionRequired": "Berechtigung erforderlich", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Lieferungen", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Lieferung hinzufügen", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Versandt", "@shipped": {}, "sku": "Bestellnummer", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Gesamtbetrag", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Verschieben", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Preis", "@price": {}, "priceRange": "Preisspanne", @@ -1141,15 +1197,5 @@ "currency": "Währung", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "Keine Preisinformation verfügbar", - "@noPricingAvailable": {}, - "noPricingDataFound": "Keine Preisdaten für diesen Teil gefunden", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Möchten Sie dieses Bild wirklich löschen?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Bild löschen", - "@deleteImageTooltip": {}, - "deleteImage": "Bild löschen", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 7decd92..a3a252b 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Κατανομή Αποθέματος", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Προβολή πληροφοριών έκδοσης εφαρμογής", "@appReleaseNotes": {}, "appSettings": "Ρυθμίσεις Εφαρμογής", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index db35685..28a808d 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Asignar stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, "appSettings": "Ajustes de aplicación", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Operación de borrado fallida", "@deleteFailed": {}, + "deleteImageConfirmation": "¿Estas seguro de eliminar esta imagen?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Eliminar imagen", + "@deleteImageTooltip": {}, + "deleteImage": "Eliminar imagen", + "@deleteImage": {}, "deletePart": "Eliminar pieza", "@deletePart": {}, "deletePartDetail": "Eliminar esta pieza de la base de datos", "@deletePartDetail": {}, "deleteSuccess": "Operación de borrado exitosa", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descripción", "@description": {}, "destination": "Destinación", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostrar Órdenes de Venta", "@homeShowSo": {}, "homeShowSoDescription": "Mostrar botón de órdenes de ventas en la pantalla de inicio", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación de nombre de usuario / contraseña no válida", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "", "@issue": {}, "issueDate": "Fecha de problema", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nombre", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "No conectado", "@notConnected": {}, "notes": "Notas", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No hay imagen disponible", "@noImageAvailable": {}, + "noPricingAvailable": "No hay precios disponibles", + "@noPricingAvailable": {}, + "noPricingDataFound": "No se encontraron datos de precios para esta parte", + "@noPricingDataFound": {}, "noSubcategories": "No hay subcategorías", "@noSubcategories": {}, "noSubcategoriesAvailable": "No hay subcategorías disponibles", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "El campo de Contraseña no puede estar vacío", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Tu usuario no cuenta con los permisos necesarios para realizar esta acción", "@permissionAccountDenied": {}, "permissionRequired": "Se requiere autorización", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Envíos", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Añadir envío", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Enviado", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Precio total", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Sitio Web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Precio", "@price": {}, "priceRange": "Rango de precios", @@ -1141,15 +1197,5 @@ "currency": "Divisa", "@currency": {}, "priceBreaks": "Diferenciales de precios", - "@priceBreaks": {}, - "noPricingAvailable": "No hay precios disponibles", - "@noPricingAvailable": {}, - "noPricingDataFound": "No se encontraron datos de precios para esta parte", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "¿Estas seguro de eliminar esta imagen?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Eliminar imagen", - "@deleteImageTooltip": {}, - "deleteImage": "Eliminar imagen", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 0b06fc2..f70e9d0 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Asignar existencias", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Mostrar notas de versión de la aplicación", "@appReleaseNotes": {}, "appSettings": "Ajustes de aplicación", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Operación de eliminación fallida", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Eliminar parte", "@deletePart": {}, "deletePartDetail": "Eliminar esta parte de la base de datos", "@deletePartDetail": {}, "deleteSuccess": "Operación de eliminación exitosa", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descripción", "@description": {}, "destination": "Destino", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botón de orden de compra en la pantalla de inicio", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostrar Órdenes de Venta", "@homeShowSo": {}, "homeShowSoDescription": "Mostrar botón de órdenes de ventas en la pantalla de inicio", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinación inválida de usuario/contraseña", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Emitir", "@issue": {}, "issueDate": "Fecha de emisión", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nombre", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "No conectado", "@notConnected": {}, "notes": "Notas", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No hay subcategorías", "@noSubcategories": {}, "noSubcategoriesAvailable": "No hay subcategorías disponibles", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "La contraseña no puede estar vacía", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Tu cuenta no cuenta con los permisos necesarios para realizar esta acción", "@permissionAccountDenied": {}, "permissionRequired": "Se requiere autorización", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor no seleccionado", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Envíos", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Añadir Envío", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Enviado", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Precio total", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Sitio web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 83ed875..2bd5e32 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Jaota laoseis", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "Rakenduse sätted", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Kustuta osa", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Kirjeldus", "@description": {}, "destination": "Sihtkoht", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nimi", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Pole ühendatud", "@notConnected": {}, "notes": "Märkmed", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Alamkategooriaid pole", "@noSubcategories": {}, "noSubcategoriesAvailable": "Ühtegi alamkategooriat pole saadaval", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Teie kontol ei ole vajalikke õigusi selle toimingu sooritamiseks", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Serverite pole valitud", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Saadetised", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Lisa saadetis", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Saadetud", "@shipped": {}, "sku": "Tootekood", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Hind kokku", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Ülekanne", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Koduleht", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index c0ac3e4..131d551 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "موجودی اختصاص داده شده", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "نمایش یادداشت های انتشار برنامه", "@appReleaseNotes": {}, "appSettings": "تنظیمات برنامه", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "عملیات حذف ناموفق بوده است", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "حذف قسمت", "@deletePart": {}, "deletePartDetail": "این قطعه را از پایگاه داده حذف کنید", "@deletePartDetail": {}, "deleteSuccess": "عملیات حذف با موفقیت انجام شد", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "توضیحات", "@description": {}, "destination": "مقصد", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "نمایش دکمه سفارش خرید در صفحه خانه", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "نمایش سفارش های فروش", "@homeShowSo": {}, "homeShowSoDescription": "نمایش دکمه سفارش فروش در صفحه خانه", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "ترکیب نام کاربری / رمز عبور نامعتبر", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "موضوع", "@issue": {}, "issueDate": "تاریخ صدور", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "نام", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "متصل نیست", "@notConnected": {}, "notes": "یادداشت ها", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "بدون زیر دسته بندی", "@noSubcategories": {}, "noSubcategoriesAvailable": "هیچ زیر دسته بندی ای در دسترس نیست", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "رمز عبور نمی تواند خالی باشد", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "حساب شما مجوزهای لازم برای انجام این عمل را ندارد", "@permissionAccountDenied": {}, "permissionRequired": "نیازمند مجوز", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "سرور انتخاب نشده است", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "محموله ها", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "افزودن محموله", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "ارسال شده", "@shipped": {}, "sku": "واحد نگهداری موجودی", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "قیمت کل", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "انتقال", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "وب سایت", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index cc6cf50..3126d75 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Näytä sovelluksen julkaisutiedot", "@appReleaseNotes": {}, "appSettings": "Sovelluksen asetukset", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Poisto epäonnistui", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Poista osa", "@deletePart": {}, "deletePartDetail": "Poista tämä osa tietokannasta", "@deletePartDetail": {}, "deleteSuccess": "Poistaminen onnistui", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Kuvaus", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Virheellinen käyttäjätunnuksen / salasanan yhdistelmä", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nimi", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Merkinnät", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Salasana ei voi olla tyhjä", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Tililläsi ei ole tarvittavia oikeuksia tämän toiminnon suorittamiseen", "@permissionAccountDenied": {}, "permissionRequired": "Käyttöoikeus vaaditaan", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Palvelinta ei ole valittu", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Siirrä", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Sivusto", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 1c71f6e..f5f55ac 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allouer un stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Afficher les notes de version de l'application", "@appReleaseNotes": {}, "appSettings": "Réglages de l'application", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "L'opération de suppression a échoué", "@deleteFailed": {}, + "deleteImageConfirmation": "Êtes-vous sûr de vouloir supprimer cette image ?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Supprimer l'image", + "@deleteImageTooltip": {}, + "deleteImage": "Supprimer l'image", + "@deleteImage": {}, "deletePart": "Supprimer la pièce", "@deletePart": {}, "deletePartDetail": "Supprimer cette pièce de la base de données", "@deletePartDetail": {}, "deleteSuccess": "Opération de suppression réussie", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Afficher le bouton de l'ordre d'achat sur l'écran d'accueil", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Afficher les commandes de vente", "@homeShowSo": {}, "homeShowSoDescription": "Afficher le bouton des commandes sur l'écran d'accueil", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nom d'utilisateur/mot de passe invalide", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Problème", "@issue": {}, "issueDate": "Date d'émission", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nom", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Non connecté", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Pas d'image disponible", "@noImageAvailable": {}, + "noPricingAvailable": "Aucune tarification disponible", + "@noPricingAvailable": {}, + "noPricingDataFound": "Aucune donnée de tarification disponible pour cette pièce", + "@noPricingDataFound": {}, "noSubcategories": "Pas de sous-catégorie", "@noSubcategories": {}, "noSubcategoriesAvailable": "Aucune sous-catégorie disponible", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Le mot de passe peut pas être vide", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", "@permissionAccountDenied": {}, "permissionRequired": "Autorisation requise", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Serveur non sélectionné", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Modes de livraison", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Ajouter un mode de livraison", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Expédié", "@shipped": {}, "sku": "UGS", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Prix Total", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfert", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Site web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Prix", "@price": {}, "priceRange": "Fourchette de prix", @@ -1141,15 +1197,5 @@ "currency": "Devise", "@currency": {}, "priceBreaks": "Ruptures de prix", - "@priceBreaks": {}, - "noPricingAvailable": "Aucune tarification disponible", - "@noPricingAvailable": {}, - "noPricingDataFound": "Aucune donnée de tarification disponible pour cette pièce", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Êtes-vous sûr de vouloir supprimer cette image ?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Supprimer l'image", - "@deleteImageTooltip": {}, - "deleteImage": "Supprimer l'image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index b7ca5b3..2099406 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "הקצאת מלאי", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": " הצג הערות פרסום של האפליקציה", "@appReleaseNotes": {}, "appSettings": "הגדרות אפליקציה", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "פעולת המחיקה נכשלה", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "מחק פריט", "@deletePart": {}, "deletePartDetail": "הסר פריט זה ממסד הנתונים", "@deletePartDetail": {}, "deleteSuccess": "פעולת המחיקה הצליחה", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "תיאור", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "הצג את לחצן הזמנת רכש במסך הבית", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "הצג הזמנות מכירה", "@homeShowSo": {}, "homeShowSoDescription": "הצג את לחצן הזמנות מכירה במסך הבית", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "שילוב שם משתמש/סיסמה לא תקין", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "להנפיק", "@issue": {}, "issueDate": "תאריך הנפקה", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "שם", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "לא מחובר", "@notConnected": {}, "notes": "הערות", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "אין קטגורית משנה", "@noSubcategories": {}, "noSubcategoriesAvailable": "אין קטכוריות משנה זמינות", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "הסיסמה לא יכולה להיות ריקה", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "לחשבון זה אין את ההרשאות לבצע פעולה זו", "@permissionAccountDenied": {}, "permissionRequired": "נדרשת הרשאה", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "השרת לא נבחר", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "משלוחים", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "מק\"ט [מספר קטלוגי] ", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "מחיר כולל", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "העבר", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "אתר", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 859bb73..1bf6e29 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 31121be..b3ba87d 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Készlet foglalása", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Kiadási közlemények", "@appReleaseNotes": {}, "appSettings": "Alkalmazásbeállítások", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Törlés sikertelen", "@deleteFailed": {}, + "deleteImageConfirmation": "Biztosan törli a képet?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Kép törlése", + "@deleteImageTooltip": {}, + "deleteImage": "Kép törlése", + "@deleteImage": {}, "deletePart": "Alkatrész törlése", "@deletePart": {}, "deletePartDetail": "Alkatrész eltávolítása az adatbázisból", "@deletePartDetail": {}, "deleteSuccess": "Törlés sikeres", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Leírás", "@description": {}, "destination": "Cél", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Vevői rendelések megmutatása", "@homeShowSo": {}, "homeShowSoDescription": "Értékesítési rendelések gomb megjelenítése a főoldalon", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Kiküldés", "@issue": {}, "issueDate": "Kiállítás dátuma", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Név", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nincs kapcsolódva", "@notConnected": {}, "notes": "Megjegyzések", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Nincs elérhető kép", "@noImageAvailable": {}, + "noPricingAvailable": "Árazás nem elérhető", + "@noPricingAvailable": {}, + "noPricingDataFound": "Nincs árazási információ ehhez az alkatrészhez", + "@noPricingDataFound": {}, "noSubcategories": "Nincsenek alkategóriák", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nincsenek alkategóriák", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Jelszó nem lehet üres", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", "@permissionAccountDenied": {}, "permissionRequired": "Engedély szükséges", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Szállítmányok", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Szállítmány hozzáadása", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Kiszállítva", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Teljes ár", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Áthelyezés", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Weboldal", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Ár", "@price": {}, "priceRange": "Ártartomány", @@ -1141,15 +1197,5 @@ "currency": "Pénznem", "@currency": {}, "priceBreaks": "Ársávok", - "@priceBreaks": {}, - "noPricingAvailable": "Árazás nem elérhető", - "@noPricingAvailable": {}, - "noPricingDataFound": "Nincs árazási információ ehhez az alkatrészhez", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Biztosan törli a képet?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Kép törlése", - "@deleteImageTooltip": {}, - "deleteImage": "Kép törlése", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index f89f8bf..9d2ae4b 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Alokasikan Stok", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Tampilkan catatan rilis aplikasi", "@appReleaseNotes": {}, "appSettings": "Pengaturan Aplikasi", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Operasi penghapusan gagal", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Hapus Part", "@deletePart": {}, "deletePartDetail": "Hapus Part ini dari database", "@deletePartDetail": {}, "deleteSuccess": "Operasi penghapusan berhasil", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Deskripsi", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Tampilkan tombol pesanan pembelian di layar beranda", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Tampilkan Pesanan Penjualan", "@homeShowSo": {}, "homeShowSoDescription": "Tampilkan tombol pesanan penjualan di layar beranda", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nama", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Tidak Tersambung", "@notConnected": {}, "notes": "Catatan", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Tidak ada subkategori", "@noSubcategories": {}, "noSubcategoriesAvailable": "Tidak ada subkategori tersedia", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Kata sandi tidak boleh kosong", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Akun Anda tidak memiliki izin yang diperlukan untuk melakukan tindakan ini", "@permissionAccountDenied": {}, "permissionRequired": "Izin Diperlukan", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server tidak dipilih", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Pengiriman", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Tambahkan Pengiriman", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Terkirim", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Harga", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Situs", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index b26869e..af8f225 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Alloca stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Mostra le note di rilascio dell'app", "@appReleaseNotes": {}, "appSettings": "Impostazioni App", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Operazione di eliminazione fallita", "@deleteFailed": {}, + "deleteImageConfirmation": "Sei sicuro di voler eliminare questa immagine?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Elimina immagine", + "@deleteImageTooltip": {}, + "deleteImage": "Elimina immagine", + "@deleteImage": {}, "deletePart": "Elimina Articolo", "@deletePart": {}, "deletePartDetail": "Rimuovi quest'articolo dal database", "@deletePartDetail": {}, "deleteSuccess": "Operazione di eliminazione riuscita", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descrizione", "@description": {}, "destination": "Destinazione", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostra ordini di vendita", "@homeShowSo": {}, "homeShowSoDescription": "Mostra bottone ordine di vendita sulla schermata principale", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinazione nome utente e password non valida", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Problema", "@issue": {}, "issueDate": "Data di emissione", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nome", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Non connesso", "@notConnected": {}, "notes": "Note", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Nessuna immagine disponibile", "@noImageAvailable": {}, + "noPricingAvailable": "Nessun prezzo disponibile", + "@noPricingAvailable": {}, + "noPricingDataFound": "Nessun dato trovato per questo articolo", + "@noPricingDataFound": {}, "noSubcategories": "Nessuna sotto categoria", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nessuna sottocategoria disponibile", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "La password non può essere vuota", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", "@permissionAccountDenied": {}, "permissionRequired": "Autorizzazione necessaria", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server non selezionato", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Spedizioni", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Aggiungi Spedizione", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Spedito", "@shipped": {}, "sku": "Codice articolo", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Prezzo Totale", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Trasferisci", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Sito Web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Prezzo", "@price": {}, "priceRange": "Fascia di Prezzo", @@ -1141,15 +1197,5 @@ "currency": "Valuta", "@currency": {}, "priceBreaks": "Divergenze di prezzo", - "@priceBreaks": {}, - "noPricingAvailable": "Nessun prezzo disponibile", - "@noPricingAvailable": {}, - "noPricingDataFound": "Nessun dato trovato per questo articolo", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Sei sicuro di voler eliminare questa immagine?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Elimina immagine", - "@deleteImageTooltip": {}, - "deleteImage": "Elimina immagine", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 73b1732..170c512 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "在庫の割り当て", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "アプリのリリースノートを表示", "@appReleaseNotes": {}, "appSettings": "アプリ設定", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "削除操作に失敗しました", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "部品を削除", "@deletePart": {}, "deletePartDetail": "データベースからこの部品を削除します", "@deletePartDetail": {}, "deleteSuccess": "操作の削除に成功しました", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "説明", "@description": {}, "destination": "保存先", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "注文ボタンをホーム画面に表示", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "注文を表示", "@homeShowSo": {}, "homeShowSoDescription": "ホーム画面に注文ボタンを表示", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "問題", "@issue": {}, "issueDate": "発行日", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "名前", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "接続されていません", "@notConnected": {}, "notes": "メモ", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "サブカテゴリはありません", "@noSubcategories": {}, "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "パスワードは空欄にできません。", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "操作を行う権限がありません", "@permissionAccountDenied": {}, "permissionRequired": "権限が必要です", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "サーバーが選択されていません", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "発送品", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "出荷を追加", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "出荷済み", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "合計金額", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "転送", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Webサイト", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 0b93e85..6241ddb 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -4,25 +4,25 @@ "@appTitle": { "description": "InvenTree application title string" }, - "ok": "OK", + "ok": "확인", "@ok": { "description": "OK" }, - "about": "About", + "about": "정보", "@about": {}, - "accountDetails": "Account Details", + "accountDetails": "계정 정보", "@accountDetails": {}, - "actions": "Actions", + "actions": "작업", "@actions": { "description": "" }, - "actionsNone": "No actions available", + "actionsNone": "실행 가능한 작업 없음", "@actionsNone": {}, "add": "추가", "@add": { "description": "add" }, - "addStock": "Add Stock", + "addStock": "재고 추가", "@addStock": { "description": "add stock" }, @@ -42,59 +42,61 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "정사각형 (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "앱 릴리즈 노트 표시", "@appReleaseNotes": {}, "appSettings": "앱 설정", "@appSettings": {}, "appSettingsDetails": "Configure InvenTree app settings", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "나에게 할당됨", "@assignedToMe": {}, "assignedToMeDetail": "Show orders which are assigned to me", "@assignedToMeDetail": {}, - "attachments": "Attachments", + "attachments": "첨부", "@attachments": {}, - "attachImage": "Attach Image", + "attachImage": "사진 첨부", "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "No attachments found", + "attachmentNone": "첨부 파일이 없음", "@attachmentNone": {}, - "attachmentNoneDetail": "No attachments found", + "attachmentNoneDetail": "첨부 파일이 없음", "@attachmentNoneDetail": {}, - "attachmentSelect": "Select attachment", + "attachmentSelect": "첨부파일 선택", "@attachmentSelect": {}, "attention": "Attention", "@attention": {}, - "available": "Available", + "available": "사용가능", "@available": {}, "availableStock": "Available Stock", "@availableStock": {}, - "barcodes": "Barcodes", + "barcodes": "바코드", "@barcodes": {}, - "barcodeSettings": "Barcode Settings", + "barcodeSettings": "바코드 설정", "@barcodeSettings": {}, - "barcodeAssign": "Assign Barcode", + "barcodeAssign": "바코드 할당", "@barcodeAssign": {}, - "barcodeAssignDetail": "Scan custom barcode to assign", + "barcodeAssignDetail": "커스텀 바코드 할당", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Barcode assigned", + "barcodeAssigned": "바코드 할당됨", "@barcodeAssigned": {}, - "barcodeError": "Barcode scan error", + "barcodeError": "바코드 스캔 오류", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "이미 바코드가 할당됨", "@barcodeInUse": {}, - "barcodeMissingHash": "Barcode hash data missing from response", + "barcodeMissingHash": "바코드 해시 데이터 응답 없음", "@barcodeMissingHash": {}, - "barcodeNoMatch": "No match for barcode", + "barcodeNoMatch": "바코드가 일치하지 않음", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Barcode not assigned", + "barcodeNotAssigned": "바코드가 할당되지 않음", "@barcodeNotAssigned": {}, - "barcodeScanPart": "Scan part barcode", + "barcodeScanPart": "스캔 파트 바코드", "@barcodeScanPart": {}, "barcodeReceivePart": "Scan barcode to receive part", "@barcodeReceivePart": {}, @@ -192,7 +194,7 @@ "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, - "count": "Count", + "count": "수량", "@count": { "description": "Count" }, @@ -202,13 +204,13 @@ }, "credits": "Credits", "@credits": {}, - "crop": "Crop", + "crop": "자르기", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "이미지 자르기", "@cropImage": {}, - "customer": "Customer", + "customer": "고객", "@customer": {}, - "customers": "Customers", + "customers": "고객", "@customers": {}, "customerReference": "Customer Reference", "@customerReference": {}, @@ -218,27 +220,35 @@ "@colorScheme": {}, "colorSchemeDetail": "Select color scheme", "@colorSchemeDetail": {}, - "darkMode": "Dark Mode", + "darkMode": "다크 모드", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "다크 모드 활성화", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "삭제", "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", "@destination": {}, "destroyed": "Destroyed", "@destroyed": {}, - "details": "Details", + "details": "상세내용", "@details": { "description": "details" }, @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "비밀번호는 비워둘 수 없습니다", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "웹사이트", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 202a20e..6e5ff34 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index c65369a..7dbe58f 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "Lietotnes iestatījumi", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Apraksts", "@description": {}, "destination": "Mērķis", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index b039e03..4e574ec 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Voorraad Toewijzen", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "App release notities weergeven", "@appReleaseNotes": {}, "appSettings": "App Instellingen", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Verwijderen mislukt", "@deleteFailed": {}, + "deleteImageConfirmation": "Weet u zeker dat u deze afbeelding wilt verwijderen?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Afbeelding verwijderen", + "@deleteImageTooltip": {}, + "deleteImage": "Afbeelding verwijderen", + "@deleteImage": {}, "deletePart": "Onderdeel Verwijderen", "@deletePart": {}, "deletePartDetail": "Verwijder dit onderdeel uit de database", "@deletePartDetail": {}, "deleteSuccess": "Succesvol verwijderd", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Omschrijving", "@description": {}, "destination": "Bestemming:", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Toon Verkooporders", "@homeShowSo": {}, "homeShowSoDescription": "Toon verkooporder knop op startscherm", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Probleem", "@issue": {}, "issueDate": "Uitgiftedatum", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Naam", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Niet verbonden", "@notConnected": {}, "notes": "Opmerkingen", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Geen afbeelding beschikbaar", "@noImageAvailable": {}, + "noPricingAvailable": "Geen prijzen beschikbaar", + "@noPricingAvailable": {}, + "noPricingDataFound": "Er zijn geen prijsgegevens gevonden voor dit deel", + "@noPricingDataFound": {}, "noSubcategories": "Geen Subcategorieën", "@noSubcategories": {}, "noSubcategoriesAvailable": "Geen subcategorieën beschikbaar", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Wachtwoord mag niet leeg zijn", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "U heeft niet de vereiste rechten om deze actie uit te voeren", "@permissionAccountDenied": {}, "permissionRequired": "Toestemming Vereist", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server niet geselecteerd", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Verzendingen", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Verzending toevoegen", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Verzonden", "@shipped": {}, "sku": "Artikelnummer", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Totaalprijs", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Verplaats", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Prijs", "@price": {}, "priceRange": "Prijs bereik", @@ -1141,15 +1197,5 @@ "currency": "Munteenheid", "@currency": {}, "priceBreaks": "Prijsverschillen", - "@priceBreaks": {}, - "noPricingAvailable": "Geen prijzen beschikbaar", - "@noPricingAvailable": {}, - "noPricingDataFound": "Er zijn geen prijsgegevens gevonden voor dit deel", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Weet u zeker dat u deze afbeelding wilt verwijderen?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Afbeelding verwijderen", - "@deleteImageTooltip": {}, - "deleteImage": "Afbeelding verwijderen", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index d454fd4..408c72b 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Tildel lagerbeholdning", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Vis appens utgivelsesnotater", "@appReleaseNotes": {}, "appSettings": "Appinnstillinger", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Slettingen mislyktes", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Slett del", "@deletePart": {}, "deletePartDetail": "Fjern denne delen fra databasen", "@deletePartDetail": {}, "deleteSuccess": "Sletting var vellykket", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Beskrivelse", "@description": {}, "destination": "Destinasjon", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Vis innkjøpsordre-knappen på startside", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Vis salgsordrer", "@homeShowSo": {}, "homeShowSoDescription": "Vis salgsordre-knappen på startside", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ugyldig brukernavn- / passordkombinasjon", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Send", "@issue": {}, "issueDate": "Sendt dato", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Navn", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Ikke tilkoblet", "@notConnected": {}, "notes": "Notater", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Ingen underkategorier", "@noSubcategories": {}, "noSubcategoriesAvailable": "Ingen underkategorier tilgjengelig", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Passordet kan ikke være tomt", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Kontoen din har ikke tillatelse til å utføre denne handlingen", "@permissionAccountDenied": {}, "permissionRequired": "Tillatelse kreves", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Forsendelser", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Legg til forsendelse", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Sendt", "@shipped": {}, "sku": "SKU-kode", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total pris", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Overfør", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Nettside", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 72c5c7f..8b8ac2a 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Przydziel zapasy", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", "@appReleaseNotes": {}, "appSettings": "Ustawienia aplikacji", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Usuwanie nie powiodło się", "@deleteFailed": {}, + "deleteImageConfirmation": "Czy na pewno chcesz usunąć ten obraz?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Usuń obraz", + "@deleteImageTooltip": {}, + "deleteImage": "Usuń obraz", + "@deleteImage": {}, "deletePart": "Usuń Komponent", "@deletePart": {}, "deletePartDetail": "Usuń ten komponent z bazy danych", "@deletePartDetail": {}, "deleteSuccess": "Usuwanie zakończone powodzeniem", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Opis", "@description": {}, "destination": "Cel:", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Pokaż przycisk zamówienia zakupu na ekranie głównym", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Pokaż zlecenia sprzedaży", "@homeShowSo": {}, "homeShowSoDescription": "Pokaż przycisk zleceń sprzedaży na ekrani głównym", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Nieprawidłowy login lub hasło", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Problem", "@issue": {}, "issueDate": "Data Wystawienia", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nazwa", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nie połączony", "@notConnected": {}, "notes": "Notatki", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Brak dostępnych obrazów", "@noImageAvailable": {}, + "noPricingAvailable": "Cena nie jest dostępna", + "@noPricingAvailable": {}, + "noPricingDataFound": "Nie znaleziono danych dotyczących cen dla tej części", + "@noPricingDataFound": {}, "noSubcategories": "Brak podkategorii", "@noSubcategories": {}, "noSubcategoriesAvailable": "Brak dostępnych podkategorii", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Hasło nie może być puste", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", "@permissionAccountDenied": {}, "permissionRequired": "Wymagane uprawnienia", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Serwer nie wybrany", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Wysyłki", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Dodaj wysyłkę", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Wysłano", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Cena całkowita", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Przenieś", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Strona WWW", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Cena", "@price": {}, "priceRange": "Zakres cen", @@ -1141,15 +1197,5 @@ "currency": "Waluta", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "Cena nie jest dostępna", - "@noPricingAvailable": {}, - "noPricingDataFound": "Nie znaleziono danych dotyczących cen dla tej części", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Czy na pewno chcesz usunąć ten obraz?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Usuń obraz", - "@deleteImageTooltip": {}, - "deleteImage": "Usuń obraz", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 7f67a03..7e715d6 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Estoque alocado", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, "appSettings": "Configurações do App", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "A operação de apagar falhou", "@deleteFailed": {}, + "deleteImageConfirmation": "Tem certeza de que deseja excluir essa imagem?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Excluir Imagem", + "@deleteImageTooltip": {}, + "deleteImage": "Excluir Imagem", + "@deleteImage": {}, "deletePart": "Deletar Peça", "@deletePart": {}, "deletePartDetail": "Remova essa peça do banco de dados", "@deletePartDetail": {}, "deleteSuccess": "Apagado com Sucesso", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descrição", "@description": {}, "destination": "Destino", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botão de ordem de compra na tela inicial", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostrar Pedidos de Venda", "@homeShowSo": {}, "homeShowSoDescription": "Mostrar Pedidos de Venda na tela inicial", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Usuario ou senha invalidos", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Emitir", "@issue": {}, "issueDate": "Data de emissao", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nome", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nao conectado", "@notConnected": {}, "notes": "Notas", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Nenhuma imagem disponível", "@noImageAvailable": {}, + "noPricingAvailable": "Nenhum preço disponível", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Nenhuma subcategoria", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nenhuma subcategoria disponível", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "A senha não pode estar em branco", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Sua conta não possui as permissões necessárias para realizar esta ação", "@permissionAccountDenied": {}, "permissionRequired": "Permissão Necessária", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Servidor não selecionado", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Envios", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Adicionar envio", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Enviado", "@shipped": {}, "sku": "Código (SKU)", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Preço Total", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transferir", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Página Web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Preço", "@price": {}, "priceRange": "Faixa de Preço", @@ -1141,15 +1197,5 @@ "currency": "Moeda", "@currency": {}, "priceBreaks": "Quebra de Preço", - "@priceBreaks": {}, - "noPricingAvailable": "Nenhum preço disponível", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Tem certeza de que deseja excluir essa imagem?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Excluir Imagem", - "@deleteImageTooltip": {}, - "deleteImage": "Excluir Imagem", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 4c9478b..ef86447 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Alocar estoque", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Exibir notas de versão do aplicativo", "@appReleaseNotes": {}, "appSettings": "Configurações do App", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Falha ao excluir", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Excluir esta parte", "@deletePart": {}, "deletePartDetail": "Remover esta peça da base de dados", "@deletePartDetail": {}, "deleteSuccess": "Excluído com sucesso", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descrição", "@description": {}, "destination": "Destino", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostrar botão de pedido de compra na tela inicial", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostrar Pedidos de Vendas", "@homeShowSo": {}, "homeShowSoDescription": "Mostrar botão de pedido de compra na tela inicial", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "O nome de utilizador ou a palavra-passe não estão corretos", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Erro", "@issue": {}, "issueDate": "Data de emissão", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "A palavra-passe não pode estar vazia", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "A sua conta não tem as permissões necessárias para executar esta ação", "@permissionAccountDenied": {}, "permissionRequired": "Permissão necessária", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index e3c54e9..62167ef 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Alocare Stoc", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Afișează notele de lansare a aplicației", "@appReleaseNotes": {}, "appSettings": "Setări Aplicație", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Operațiune de ștergere eșuată", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Șterge Piesa", "@deletePart": {}, "deletePartDetail": "Elimină această piesă din baza de date", "@deletePartDetail": {}, "deleteSuccess": "Operație de ștergere reușită", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Descriere", "@description": {}, "destination": "Destinație", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Afișați butonul de achiziții pe ecranul principal", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Arată Comenzile de Vânzări", "@homeShowSo": {}, "homeShowSoDescription": "Afișare buton vânzări pe ecranul principal", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinație de nume utilizator / parolă invalida", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Problemă", "@issue": {}, "issueDate": "Data emiterii", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Nume", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Neconectat", "@notConnected": {}, "notes": "Notițe", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Nu există subcategorii", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nicio subcategorie disponibilă", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Câmpul pentru Parola nu poate fi gol", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Contul dvs. nu are permisiunile necesare pentru a efectua această acțiune", "@permissionAccountDenied": {}, "permissionRequired": "Permisiune necesară", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index bbc7cc5..800335e 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Выделить запас", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Показать заметки о выпуске приложения", "@appReleaseNotes": {}, "appSettings": "Настройки приложения", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Ошибка удаления", "@deleteFailed": {}, + "deleteImageConfirmation": "Вы уверены, что хотите удалить изображение?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Удалить изображение", + "@deleteImageTooltip": {}, + "deleteImage": "Удалить изображение", + "@deleteImage": {}, "deletePart": "Удалить деталь", "@deletePart": {}, "deletePartDetail": "Удалить эту деталь из базы данных", "@deletePartDetail": {}, "deleteSuccess": "Удаление успешно завершено", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Описание", "@description": {}, "destination": "Назначение", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Показывать кнопку заказа на главном экране", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Показать заказы на продажу", "@homeShowSo": {}, "homeShowSoDescription": "Показывать кнопку заказов на продажу на главном экране", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Оформить", "@issue": {}, "issueDate": "Дата проблемы", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Название", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Соединение не установлено", "@notConnected": {}, "notes": "Заметки", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Нет доступного изображения", "@noImageAvailable": {}, + "noPricingAvailable": "Нет данных о цене", + "@noPricingAvailable": {}, + "noPricingDataFound": "Для этой детали не найдены данные о ценах", + "@noPricingDataFound": {}, "noSubcategories": "Нет подкатегории", "@noSubcategories": {}, "noSubcategoriesAvailable": "Нет доступных подкатегорий", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Пароль не может быть пустым", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Ваш аккаунт не имеет разрешения на выполнение этого действия", "@permissionAccountDenied": {}, "permissionRequired": "Требуется разрешение", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не выбран", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Поставки", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Новое Отправление", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Отгружено", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Общая стоимость", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Перемещение", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Сайт", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Цена", "@price": {}, "priceRange": "Диапазон цен", @@ -1141,15 +1197,5 @@ "currency": "Валюта", "@currency": {}, "priceBreaks": "Разбивка по ценам", - "@priceBreaks": {}, - "noPricingAvailable": "Нет данных о цене", - "@noPricingAvailable": {}, - "noPricingDataFound": "Для этой детали не найдены данные о ценах", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Вы уверены, что хотите удалить изображение?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Удалить изображение", - "@deleteImageTooltip": {}, - "deleteImage": "Удалить изображение", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 5e98aa3..a7d26a4 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index e82b80f..3ca8730 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allocate Stock", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Display app release notes", "@appReleaseNotes": {}, "appSettings": "App Settings", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 856048e..c3e9f4b 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Alociraj zalihe", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Prikaži informacije o aplikaciji", "@appReleaseNotes": {}, "appSettings": "Podešavanja aplikacije", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Neuspešna operacija brisanja", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Obriši deo", "@deletePart": {}, "deletePartDetail": "Ukloni ovaj deo iz baze podataka", "@deletePartDetail": {}, "deleteSuccess": "Operacija brisanja uspešna", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Opis", "@description": {}, "destination": "Odredište", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Datum izdavanja", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Ime", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Nije povezano", "@notConnected": {}, "notes": "Beleške", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Nema podkategorija", "@noSubcategories": {}, "noSubcategoriesAvailable": "Nema dostupnih podkategorija", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 14b3b90..30e561c 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Allokera lager", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Visa versionsinfo för app", "@appReleaseNotes": {}, "appSettings": "Appinställningar", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Borttagning misslyckades", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Ta bort del", "@deletePart": {}, "deletePartDetail": "Ta bort denna del från databasen", "@deletePartDetail": {}, "deleteSuccess": "Borttagning lyckad", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Beskrivning", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Visa knappen för inköpsorder på startskärmen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Visa försäljningsorder", "@homeShowSo": {}, "homeShowSoDescription": "Visa knappen för försäljningsorder på startskärmen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Felaktigt användarnamn / lösenord kombination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Ärende", "@issue": {}, "issueDate": "Utfärdad datum", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Namn", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Ej ansluten", "@notConnected": {}, "notes": "Anteckningar", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Ingen bild tillgänglig", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, "noSubcategoriesAvailable": "Inga underkategorier tillgängliga", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Lösenordet får inte vara tomt", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Ditt konto har inte de rättigheter som krävs för att utföra denna åtgärd", "@permissionAccountDenied": {}, "permissionRequired": "Särskilda behörigheter krävs", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Servern är inte vald", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Frakt", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Lägg till frakt", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Skickad", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Totalpris", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Överföring", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Webbplats", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index c97b24c..2206a8c 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "จัดสรรคลัง", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "แสดงข้อมูลรุ่นของโปรแกรม", "@appReleaseNotes": {}, "appSettings": "การตั้งค่าแอปพลิเคชั่น", @@ -86,7 +88,7 @@ "@barcodeAssigned": {}, "barcodeError": "สแกนบาร์โค้ดผิดพลาด", "@barcodeError": {}, - "barcodeInUse": "Barcode already assigned", + "barcodeInUse": "", "@barcodeInUse": {}, "barcodeMissingHash": "Barcode hash data missing from response", "@barcodeMissingHash": {}, @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Delete operation failed", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Delete Part", "@deletePart": {}, "deletePartDetail": "Remove this part from the database", "@deletePartDetail": {}, "deleteSuccess": "Delete operation successful", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Description", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Show purchase order button on home screen", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Show Sales Orders", "@homeShowSo": {}, "homeShowSoDescription": "Show sales order button on home screen", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Invalid username / password combination", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Name", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Not Connected", "@notConnected": {}, "notes": "Notes", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Your account does not have the required permissions to perform this action", "@permissionAccountDenied": {}, "permissionRequired": "Permission Required", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Server not selected", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Shipped", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 8430f4c..8e24014 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Tahsisli stok", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Uygulama yayınlama notlarını göster", "@appReleaseNotes": {}, "appSettings": "Uygulama Ayarları", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Silme işlemi başarısız", "@deleteFailed": {}, + "deleteImageConfirmation": "Bu resmi silmek istediğinizden emin misiniz?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Görüntüyü Sil", + "@deleteImageTooltip": {}, + "deleteImage": "Resmi sil", + "@deleteImage": {}, "deletePart": "Parça Sil", "@deletePart": {}, "deletePartDetail": "Bu parçayı veritabanından kaldır", "@deletePartDetail": {}, "deleteSuccess": "Silme işlemi başarılı", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Açıklama", "@description": {}, "destination": "Varış Yeri", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Satış Siparişlerini Göster", "@homeShowSo": {}, "homeShowSoDescription": "Satış siparişleri tuşunu giriş ekranında göster", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Sorun", "@issue": {}, "issueDate": "Sorun Tarihi", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Adı", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Bağlı değil", "@notConnected": {}, "notes": "Notlar", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Kullanılabilir resim yok", "@noImageAvailable": {}, + "noPricingAvailable": "Fiyatlandırma mevcut değil", + "@noPricingAvailable": {}, + "noPricingDataFound": "Bu parça için fiyatlandırma verisi bulunamadı", + "@noPricingDataFound": {}, "noSubcategories": "Alt kategori yok", "@noSubcategories": {}, "noSubcategoriesAvailable": "Uygun alt kategori yok", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Parola boş bırakılamaz", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", "@permissionAccountDenied": {}, "permissionRequired": "İzin Gerekli", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Sunucu bulunamadı", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Gönderiler", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Gönderi Ekle", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Gönderildi", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Toplam Fiyat", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Aktarım", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Web sitesi", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Fiyat", "@price": {}, "priceRange": "Fiyat Aralığı", @@ -1141,15 +1197,5 @@ "currency": "Para Birimi", "@currency": {}, "priceBreaks": "Fiyat Aralığı", - "@priceBreaks": {}, - "noPricingAvailable": "Fiyatlandırma mevcut değil", - "@noPricingAvailable": {}, - "noPricingDataFound": "Bu parça için fiyatlandırma verisi bulunamadı", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Bu resmi silmek istediğinizden emin misiniz?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Görüntüyü Sil", - "@deleteImageTooltip": {}, - "deleteImage": "Resmi sil", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 94a669f..6947b48 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Виділити запас", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Показати примітки до випуску", "@appReleaseNotes": {}, "appSettings": "Налаштування додатку", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Помилка видалення", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Видалити деталь", "@deletePart": {}, "deletePartDetail": "Видалити цю частину з бази даних", "@deletePartDetail": {}, "deleteSuccess": "Операція видалення пройшла успішно", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Опис", "@description": {}, "destination": "Місце призначення", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Показувати кнопку замовлення на домашньому екрані", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Показати замовлення", "@homeShowSo": {}, "homeShowSoDescription": "Показувати кнопку замовлення на домашньому екрані", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неправильна комбінація імені користувача та пароля", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Issue", "@issue": {}, "issueDate": "Issue Date", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Назва", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Не під’єднано", "@notConnected": {}, "notes": "Нотатки", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "Немає доступного зображення", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "No Subcategories", "@noSubcategories": {}, "noSubcategoriesAvailable": "No subcategories available", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Пароль не може бути порожнім", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Ваш обліковий запис не має необхідних прав для виконання цієї дії", "@permissionAccountDenied": {}, "permissionRequired": "Потрібен дозвіл", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не вибраний", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Shipments", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Add Shipment", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Відправлено", "@shipped": {}, "sku": "SKU", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Total Price", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index cca6071..8639cdb 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "Phân kho", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "Hiển thị ghi chú phát hành ứng dụng", "@appReleaseNotes": {}, "appSettings": "Cài đặt ứng dụng", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "Thao tác xóa đã thất bại", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "Xóa phần", "@deletePart": {}, "deletePartDetail": "Xóa một phần ra khỏi cơ sở dữ liệu", "@deletePartDetail": {}, "deleteSuccess": "Thao tác xóa thành công", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "Mô tả", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "Hiển thị đơn hàng mới tại màn hình chính", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "Hiện đơn hàng bán", "@homeShowSo": {}, "homeShowSoDescription": "Hiện nút đơn hàng bán tại màn hình trang chủ", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Tên người dùng / mật khẩu không hợp lệ", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "Vấn đề", "@issue": {}, "issueDate": "Ngày phát hành", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "Tên", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "Không được kết nối", "@notConnected": {}, "notes": "Ghi chú", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "Không có danh mục con", "@noSubcategories": {}, "noSubcategoriesAvailable": "Không có sẵn danh mục", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "Mật khẩu không được để trống", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "Tài khoản này bắt buộc phải có đủ các quyền để thực hiện thao tác này", "@permissionAccountDenied": {}, "permissionRequired": "Yêu cầu quyền truy cập", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "Chưa chọn máy chủ", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "Vận chuyển", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "Thêm phương thức vận chuyển", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "Đã vận chuyển", "@shipped": {}, "sku": "Mã sản phẩm", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Tổng tiền", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "Chuyển", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "Trang web", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 84422dd..207089c 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "分配库存", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "显示应用发布笔记", "@appReleaseNotes": {}, "appSettings": "应用设置", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "删除操作失败", "@deleteFailed": {}, + "deleteImageConfirmation": "您确认要删除此图片吗?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "删除图片", + "@deleteImageTooltip": {}, + "deleteImage": "删除图片", + "@deleteImage": {}, "deletePart": "删除零件", "@deletePart": {}, "deletePartDetail": "从数据库中删除此零件", "@deletePartDetail": {}, "deleteSuccess": "删除操作成功", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "描述", "@description": {}, "destination": "目的地", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "在主屏幕上显示订单按钮", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "显示销售订单", "@homeShowSo": {}, "homeShowSoDescription": "在主屏幕上显示销售订单按钮", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "无效的用户名密码组合", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "下单任务", "@issue": {}, "issueDate": "签发日期", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "名称", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "未连接", "@notConnected": {}, "notes": "注释", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "没有可用的图片", "@noImageAvailable": {}, + "noPricingAvailable": "无可用价格", + "@noPricingAvailable": {}, + "noPricingDataFound": "未找到此零件的定价数据", + "@noPricingDataFound": {}, "noSubcategories": "无子类别", "@noSubcategories": {}, "noSubcategoriesAvailable": "无可用子类别", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "密码不能为空", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "您的账户没有执行此操作所需的权限", "@permissionAccountDenied": {}, "permissionRequired": "需要授权:", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "未选定服务器", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "配送", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "添加配送", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "已配送", "@shipped": {}, "sku": "库存单位 (SKU)", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "总价", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "转移", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "网站", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "价格", "@price": {}, "priceRange": "价格范围", @@ -1141,15 +1197,5 @@ "currency": "币种", "@currency": {}, "priceBreaks": "批发价", - "@priceBreaks": {}, - "noPricingAvailable": "无可用价格", - "@noPricingAvailable": {}, - "noPricingDataFound": "未找到此零件的定价数据", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "您确认要删除此图片吗?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "删除图片", - "@deleteImageTooltip": {}, - "deleteImage": "删除图片", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 8a0a327..6d6f300 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -46,6 +46,8 @@ "@aspectRatioSquare": {}, "allocateStock": "分配庫存", "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, "appReleaseNotes": "顯示應用程式發布說明", "@appReleaseNotes": {}, "appSettings": "程式設定", @@ -226,12 +228,20 @@ "@delete": {}, "deleteFailed": "刪除失敗", "@deleteFailed": {}, + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + "deleteImage": "Delete Image", + "@deleteImage": {}, "deletePart": "刪除零件", "@deletePart": {}, "deletePartDetail": "從數據庫中刪除此零件", "@deletePartDetail": {}, "deleteSuccess": "刪除成功", "@deleteSuccess": {}, + "deliveryDate": "Delivery Date", + "@deliveryDate": {}, "description": "敘述", "@description": {}, "destination": "Destination", @@ -374,6 +384,10 @@ "@homeShowPo": {}, "homeShowPoDescription": "在主屏幕上顯示訂單按鈕", "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, "homeShowSo": "顯示銷售訂單", "@homeShowSo": {}, "homeShowSoDescription": "在主屏幕上顯示銷售訂單按鈕", @@ -440,6 +454,10 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "無效的用户名密碼組合", "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, "issue": "發行", "@issue": {}, "issueDate": "發行日期", @@ -520,6 +538,10 @@ "@missingData": {}, "name": "名稱", "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, "notConnected": "未連接", "@notConnected": {}, "notes": "備註", @@ -536,6 +558,10 @@ "@noResults": {}, "noImageAvailable": "No image available", "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, "noSubcategories": "無子類別", "@noSubcategories": {}, "noSubcategoriesAvailable": "無可用子類別", @@ -628,6 +654,8 @@ "@password": {}, "passwordEmpty": "密碼不能為空", "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, "permissionAccountDenied": "您的賬户沒有執行此操作所需的權限", "@permissionAccountDenied": {}, "permissionRequired": "需要授權:", @@ -906,10 +934,34 @@ "@serverNotConnected": {}, "serverNotSelected": "未選定服務器", "@serverNotSelected": {}, + "shipment": "Shipment", + "@shipment": {}, "shipments": "配送", "@shipments": {}, + "shipmentsPending": "Pending Shipments", + "@shipmentsPending": {}, "shipmentAdd": "添加配送", "@shipmentAdd": {}, + "shipmentCheck": "Check Shipment", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Mark this shipment as checked", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Shipment Checked", + "@shipmentChecked": {}, + "shipmentDate": "Shipment Date", + "@shipmentDate": {}, + "shipmentEdit": "Edit Shipment", + "@shipmentEdit": {}, + "shipmentReference": "Shipment Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Shipment", + "@shipmentSend": {}, + "shipmentUncheck": "Uncheck Shipment", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, "shipped": "已配送", "@shipped": {}, "sku": "庫存單位 (SKU)", @@ -1054,6 +1106,8 @@ "@tokenMissingFromResponse": {}, "totalPrice": "總價", "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, "transfer": "轉移", "@transfer": { "description": "transfer" @@ -1114,6 +1168,8 @@ "@viewSupplierPart": {}, "website": "網站", "@website": {}, + "yes": "Yes", + "@yes": {}, "price": "Price", "@price": {}, "priceRange": "Price Range", @@ -1141,15 +1197,5 @@ "currency": "Currency", "@currency": {}, "priceBreaks": "Price Breaks", - "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", - "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", - "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", - "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", - "@deleteImage": {} + "@priceBreaks": {} } \ No newline at end of file From 2b68c305688fd159a643f42a197e64736c71f919 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 29 Oct 2025 15:03:59 +1100 Subject: [PATCH 710/746] New translations app_en.arb (Portuguese) (#701) --- lib/l10n/pt_PT/app_pt_PT.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index ef86447..de33d15 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -600,7 +600,7 @@ "@parametersSettingDetail": {}, "parent": "Parent", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Categoria Principal", "@parentCategory": {}, "parentLocation": "Parent Location", "@parentLocation": {}, From 2f8f42822aee3b7108ef5b22f4fb2647a2997983 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 31 Oct 2025 15:26:18 +1100 Subject: [PATCH 711/746] Possible fix for barcode scanner issues (#702) * Possible fix for barcode scanner issues Ref: https://github.com/juliansteenbakker/mobile_scanner/issues/1454#issuecomment-3329405748 * Bump release notes * Bump app revision --- assets/release_notes.md | 5 +++++ lib/barcode/camera_controller.dart | 1 + pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 3020661..8f5daf9 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.20.1 - October 2025 +--- + +- Bug fix for camera barcode scanner + ### 0.20.0 - October 2025 --- diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index ba73b10..c456721 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -55,6 +55,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override void dispose() { super.dispose(); + controller.dispose(); WakelockPlus.disable(); } diff --git a/pubspec.yaml b/pubspec.yaml index 92de267..e4100bf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.20.0+103 +version: 0.20.1+104 environment: sdk: ^3.8.1 From 9083f195310c569569fe27d981a359972504c051 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Nov 2025 20:33:54 +1100 Subject: [PATCH 712/746] New Crowdin updates (#703) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Swedish) * New translations app_en.arb (Swedish) --- lib/l10n/sv_SE/app_sv_SE.arb | 14 +++++------ lib/l10n/zh_CN/app_zh_CN.arb | 46 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 30e561c..4e5a2c8 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -230,9 +230,9 @@ "@deleteFailed": {}, "deleteImageConfirmation": "Are you sure you want to delete this image?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Radera bild", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Radera bild", "@deleteImage": {}, "deletePart": "Ta bort del", "@deletePart": {}, @@ -456,7 +456,7 @@ "@invalidUsernamePassword": {}, "invoice": "Invoice", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Fakturanummer", "@invoiceNumber": {}, "issue": "Ärende", "@issue": {}, @@ -538,7 +538,7 @@ "@missingData": {}, "name": "Namn", "@name": {}, - "no": "No", + "no": "Nej", "@no": {}, "notApplicable": "N/A", "@notApplicable": {}, @@ -1142,7 +1142,7 @@ "@uploadFailed": {}, "uploadSuccess": "Fil har laddats upp", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Ladda upp bild", "@uploadImage": {}, "usedIn": "Används i", "@usedIn": {}, @@ -1168,9 +1168,9 @@ "@viewSupplierPart": {}, "website": "Webbplats", "@website": {}, - "yes": "Yes", + "yes": "Ja", "@yes": {}, - "price": "Price", + "price": "Pris", "@price": {}, "priceRange": "Price Range", "@priceRange": {}, diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 207089c..fb1bd41 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "分配库存", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "已分配库存", "@allocatedStock": {}, "appReleaseNotes": "显示应用发布笔记", "@appReleaseNotes": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "删除操作成功", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "交货日期", "@deliveryDate": {}, "description": "描述", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "在主屏幕上显示订单按钮", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "显示货件", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "在首页显示待处理货件", "@homeShowShipmentsDescription": {}, "homeShowSo": "显示销售订单", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "无效的用户名密码组合", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "发票", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "发票号码", "@invoiceNumber": {}, "issue": "下单任务", "@issue": {}, @@ -538,9 +538,9 @@ "@missingData": {}, "name": "名称", "@name": {}, - "no": "No", + "no": "否", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "不适用", "@notApplicable": {}, "notConnected": "未连接", "@notConnected": {}, @@ -654,7 +654,7 @@ "@password": {}, "passwordEmpty": "密码不能为空", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "等待", "@pending": {}, "permissionAccountDenied": "您的账户没有执行此操作所需的权限", "@permissionAccountDenied": {}, @@ -934,33 +934,33 @@ "@serverNotConnected": {}, "serverNotSelected": "未选定服务器", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "发货", "@shipment": {}, "shipments": "配送", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "待处理货件", "@shipmentsPending": {}, "shipmentAdd": "添加配送", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "查询物流", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "标记为已核对", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "已核对", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "发货日期", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "编辑货件", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "参考编号", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "确认发货", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "取消核对", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "标记为未核对", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "货件信息已更新", "@shipmentUpdated": {}, "shipped": "已配送", "@shipped": {}, @@ -1106,7 +1106,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "总价", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "运单号", "@trackingNumber": {}, "transfer": "转移", "@transfer": { @@ -1168,7 +1168,7 @@ "@viewSupplierPart": {}, "website": "网站", "@website": {}, - "yes": "Yes", + "yes": "是", "@yes": {}, "price": "价格", "@price": {}, From 0fc80b1be3f45a0a4204a1e4bd7c8688fa1e7657 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Nov 2025 21:39:39 +1100 Subject: [PATCH 713/746] Tweaks (#707) * Remove debug msg * Only request test templates for testable parts * Format --- lib/inventree/part.dart | 4 ++-- lib/widget/part/part_detail.dart | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index c0050ec..23e306c 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -278,8 +278,6 @@ class InvenTreePart extends InvenTreeModel { // Request pricing data for this part Future getPricing() async { - print("REQUEST PRICING FOR: ${pk}"); - try { final response = await InvenTreeAPI().get("/api/part/${pk}/pricing/"); if (response.isValid()) { @@ -411,6 +409,8 @@ class InvenTreePart extends InvenTreeModel { bool get isTrackable => getBool("trackable"); + bool get isTestable => getBool("testable"); + // Get the IPN (internal part number) for the Part instance String get IPN => getString("IPN"); diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index e6c7d6e..4cbfa49 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -190,11 +190,13 @@ class _PartDisplayState extends RefreshableState { } // Request part test templates - part.getTestTemplates().then((value) { - if (mounted) { - setState(() {}); - } - }); + if (part.isTestable) { + part.getTestTemplates().then((value) { + if (mounted) { + setState(() {}); + } + }); + } // Request the number of attachments InvenTreePartAttachment().countAttachments(part.pk).then((int value) { From 490d008447b97eaa91e7884336474517e181ef40 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Nov 2025 21:39:48 +1100 Subject: [PATCH 714/746] Fix URL for reporting an issue via GitHub (#706) * Fix URL for reporting an issue via GitHub * Format --- assets/release_notes.md | 6 ++++++ lib/settings/about.dart | 3 ++- pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 8f5daf9..421f14b 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### 0.20.2 - November 2025 +--- + +- Fixes URL for reporting issues on GitHub + + ### 0.20.1 - October 2025 --- diff --git a/lib/settings/about.dart b/lib/settings/about.dart index bc8c345..fa11eb3 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -49,7 +49,8 @@ class InvenTreeAboutWidget extends StatelessWidget { var url = Uri( scheme: "https", host: "github.com", - path: "inventree/inventree-app/issues/new?title=Enter+bug+description", + path: "inventree/inventree-app/issues/new/", + queryParameters: {"title": "Enter bug description"}, ); if (await canLaunchUrl(url)) { diff --git a/pubspec.yaml b/pubspec.yaml index e4100bf..a6c479e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.20.1+104 +version: 0.20.2+105 environment: sdk: ^3.8.1 From 2252dd2fd6a26c907f2cf5df0b294da08fbb9fdd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 3 Nov 2025 22:10:00 +1100 Subject: [PATCH 715/746] Thumbnail errors (#708) * Extract error info from thumbnail errors * Formatting --- lib/api.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 5d79a22..7ea44ac 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1545,8 +1545,15 @@ class InvenTreeAPI { return CachedNetworkImage( imageUrl: url, placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => - Icon(TablerIcons.circle_x, color: COLOR_DANGER), + errorWidget: (context, url, error) { + print("CachedNetworkimage error: ${error.toString()}"); + return GestureDetector( + child: Icon(TablerIcons.circle_x, color: COLOR_DANGER), + onTap: () => { + showSnackIcon(error.toString().split(",")[0], success: false), + }, + ); + }, httpHeaders: defaultHeaders(), height: height, width: width, From ae1d8dd1886565974e9c5a5878fb9caf34a76d6d Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Nov 2025 12:32:38 +1100 Subject: [PATCH 716/746] File upload fix (#712) * Allow file upload with non-strict https - Create custom client for uploads - Observe the USE_STRICT_HTTPS setting * Formatting * Update release notes * Fix await code --- assets/release_notes.md | 2 +- lib/api.dart | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 421f14b..2e6b291 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,7 +2,7 @@ --- - Fixes URL for reporting issues on GitHub - +- Fix for uploading files against server with self-signed certificates ### 0.20.1 - October 2025 --- diff --git a/lib/api.dart b/lib/api.dart index 7ea44ac..a2a48f9 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -4,6 +4,7 @@ import "dart:io"; import "package:flutter/foundation.dart"; import "package:http/http.dart" as http; +import "package:http/io_client.dart"; import "package:intl/intl.dart"; import "package:inventree/main.dart"; import "package:one_context/one_context.dart"; @@ -983,12 +984,23 @@ class InvenTreeAPI { String method = "POST", Map? fields, }) async { - var _url = makeApiUrl(url); + bool strictHttps = await InvenTreeSettingsManager().getBool( + INV_STRICT_HTTPS, + false, + ); - var request = http.MultipartRequest(method, Uri.parse(_url)); + // Create an IOClient wrapper for sending the MultipartRequest + final ioClient = IOClient(createClient(url, strictHttps: strictHttps)); - request.headers.addAll(defaultHeaders()); + final uri = Uri.parse(makeApiUrl(url)); + final request = http.MultipartRequest(method, uri); + // Default headers + defaultHeaders().forEach((key, value) { + request.headers[key] = value; + }); + + // Optional fields if (fields != null) { fields.forEach((String key, dynamic value) { if (value == null) { @@ -999,20 +1011,24 @@ class InvenTreeAPI { }); } + // Add file to upload var _file = await http.MultipartFile.fromPath(name, f.path); - request.files.add(_file); + // Construct a response object to return APIResponse response = APIResponse(url: url, method: method); String jsondata = ""; try { - var httpResponse = await request.send().timeout(Duration(seconds: 120)); + var streamedResponse = await ioClient + .send(request) + .timeout(Duration(seconds: 120)); + final httpResponse = await http.Response.fromStream(streamedResponse); response.statusCode = httpResponse.statusCode; - jsondata = await httpResponse.stream.bytesToString(); + jsondata = httpResponse.body; response.data = json.decode(jsondata); From daf3bf829143718afe4102613d14e8220f0a739f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Nov 2025 23:01:24 +1100 Subject: [PATCH 717/746] Update python version for CI (#714) --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2ecf506..c317876 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: - name: Install Python uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Setup Java uses: actions/setup-java@v3 From 0eedf25d11c06d06d95dd258df0318669bdb67dd Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Nov 2025 23:16:07 +1100 Subject: [PATCH 718/746] New Crowdin updates (#709) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Swedish) * New translations app_en.arb (Romanian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Turkish) * New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 2 +- lib/l10n/ro_RO/app_ro_RO.arb | 188 +++++++++++++++++------------------ lib/l10n/sv_SE/app_sv_SE.arb | 10 +- lib/l10n/tr_TR/app_tr_TR.arb | 46 ++++----- lib/l10n/uk_UA/app_uk_UA.arb | 2 +- 5 files changed, 124 insertions(+), 124 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 172b055..86a9617 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -1196,6 +1196,6 @@ "@pricingOverrides": {}, "currency": "Währung", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Preisstaffel", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 62167ef..2fc5240 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -42,11 +42,11 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Pătrat (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Alocare Stoc", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Stocuri alocate", "@allocatedStock": {}, "appReleaseNotes": "Afișează notele de lansare a aplicației", "@appReleaseNotes": {}, @@ -170,7 +170,7 @@ "@categoryUpdated": {}, "company": "Companie", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Adăugare companie", "@companyAdd": {}, "companyEdit": "Editare companie", "@companyEdit": {}, @@ -180,11 +180,11 @@ "@companyUpdated": {}, "companies": "Companii", "@companies": {}, - "complete": "Complete", + "complete": "Finalizare", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Comandă completă", "@completeOrder": {}, - "completionDate": "Completion Date", + "completionDate": "Data completării", "@completionDate": {}, "configureServer": "Configurare setări server", "@configureServer": {}, @@ -204,9 +204,9 @@ }, "credits": "Credite", "@credits": {}, - "crop": "Crop", + "crop": "Decupați", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Decupare imagine", "@cropImage": {}, "customer": "Client", "@customer": {}, @@ -228,11 +228,11 @@ "@delete": {}, "deleteFailed": "Operațiune de ștergere eșuată", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Sunteți sigur că doriți să ștergeți această imagine?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Șterge imaginea", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Șterge imaginea", "@deleteImage": {}, "deletePart": "Șterge Piesa", "@deletePart": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Operație de ștergere reușită", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Data livrării", "@deliveryDate": {}, "description": "Descriere", "@description": {}, @@ -254,9 +254,9 @@ }, "documentation": "Documentație", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Descărcare completă", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Eroare la descărcarea imaginii", "@downloadError": {}, "downloading": "Se descarcă fișierul", "@downloading": {}, @@ -282,7 +282,7 @@ "@editItem": {}, "editLineItem": "Editare element rând", "@editLineItem": {}, - "email": "Email", + "email": "E-mail", "@email": {}, "enterPassword": "Introdu parola", "@enterPassword": {}, @@ -316,9 +316,9 @@ "@expiryExpired": {}, "expiryStale": "", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Elemente suplimentare", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Elemente suplimentare", "@extraLineItems": {}, "feedback": "Feedback", "@feedback": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Afișați butonul de achiziții pe ecranul principal", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Afișare livrări", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Arată transporturile în așteptare pe ecranul principal", "@homeShowShipmentsDescription": {}, "homeShowSo": "Arată Comenzile de Vânzări", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinație de nume utilizator / parolă invalida", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Factură", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Număr factură", "@invoiceNumber": {}, "issue": "Problemă", "@issue": {}, @@ -480,7 +480,7 @@ "@labelTemplate": {}, "labelSelectTemplate": "Selectați șablon de etichetă", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Selectați imprimanta de etichete", "@labelSelectPrinter": {}, "language": "Limba", "@language": {}, @@ -526,7 +526,7 @@ "@lost": {}, "manufacturerPart": "", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Editați piesa producătorului", "@manufacturerPartEdit": {}, "manufacturerPartNumber": "Număr Serie Producător", "@manufacturerPartNumber": {}, @@ -538,9 +538,9 @@ "@missingData": {}, "name": "Nume", "@name": {}, - "no": "No", + "no": "Nu", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "Indisponibil", "@notApplicable": {}, "notConnected": "Neconectat", "@notConnected": {}, @@ -556,11 +556,11 @@ "@noResponse": {}, "noResults": "Niciun rezultat", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Nici o imagine disponibilă", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Nu există prețuri disponibile", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Nu au fost găsite date despre prețuri pentru această piesă", "@noPricingDataFound": {}, "noSubcategories": "Nu există subcategorii", "@noSubcategories": {}, @@ -624,9 +624,9 @@ "@partsNone": {}, "partNoResults": "Nicio piesă care se potrivește", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Preț piesă", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Afișați informații despre preț", "@pricingSettingDetail": {}, "partSettings": "Setări Piesa", "@partSettings": {}, @@ -654,13 +654,13 @@ "@password": {}, "passwordEmpty": "Câmpul pentru Parola nu poate fi gol", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "În așteptare", "@pending": {}, "permissionAccountDenied": "Contul dvs. nu are permisiunile necesare pentru a efectua această acțiune", "@permissionAccountDenied": {}, "permissionRequired": "Permisiune necesară", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, "printLabel": "Printati Eticheta", "@printLabel": {}, @@ -678,143 +678,143 @@ "@printLabelSuccess": {}, "profile": "Profiluri", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "Adaugă Profil Server", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "Conectare la server", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "Editează Profilul Serverului", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "Ștergere profil server", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Deconectare profil", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "Nume profil", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "Nici un profil disponibil", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "Nici un profil selectat", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "Selectați serverul InvenTree", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "Selectează server sau creează un profil nou", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "Atingeți pentru a crea sau a selecta un profil", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Cod proiect", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Confirmați datele scanate", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Confirmați detaliile la scanarea articolelor", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Activați comenzile de achiziție", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Activează funcționalitatea comenzii de achiziție", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Scurtătura Cameră", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Activează comanda rapidă pentru încărcarea imaginilor pe ecranul comenzii de achiziție", "@purchaseOrderShowCameraDetail": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "Comandă de achiziție", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Comandă nouă de achiziție", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "Editați comanda de achiziție", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Setări comandă de achiziție", "@purchaseOrderSettings": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "Comandă de achiziție", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "Comandă de achiziție actualizată", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "Preț achiziție", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Cantitate", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Cantitate disponibilă", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Cantitatea este goală", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Cantitate invalida", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Cantitatea trebuie să fie pozitivă", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Introdu text căutat", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "Nici un rezultat pentru cautare", "@queryNoResults": {}, - "received": "Received", + "received": "Recepţionat", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Afișare articole primite", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Articole primite", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "Articol primit în stoc", "@receivedItem": {}, - "reference": "Reference", + "reference": "Referinţă", "@reference": {}, - "refresh": "Refresh", + "refresh": "Actualizare", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Rotire la 90° în sens orar", "@rotateClockwise": {}, - "refreshing": "Refreshing", + "refreshing": "Actualizare", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Respins", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "Informații & versiune", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Șterge", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "Retragere stoc", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Raportează o eroare", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "Trimite raportul de eroare (necesită cont GitHub)", "@reportBugDescription": {}, "responsible": "Responsabil", "@responsible": {}, - "results": "Results", + "results": "Rezultate", "@results": {}, - "request": "Request", + "request": "Solicitare", "@request": {}, "requestFailed": "Cerere eșuată", "@requestFailed": {}, "requestSuccessful": "", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "Solicitare date", "@requestingData": {}, - "required": "Required", + "required": "Obligatoriu", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "Cerere greşită", "@response400": {}, - "response401": "Unauthorized", + "response401": "Neautorizat", "@response401": {}, - "response403": "Permission Denied", + "response403": "Acces interzis", "@response403": {}, - "response404": "Resource Not Found", + "response404": "Resursa nu a fost găsită", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "Metoda nu este permisă", "@response405": {}, - "response429": "Too Many Requests", + "response429": "Prea multe solicitări", "@response429": {}, - "response500": "Internal Server Error", + "response500": "Eroare internă server", "@response500": {}, - "response501": "Not Implemented", + "response501": "Nu este implementat", "@response501": {}, - "response502": "Bad Gateway", + "response502": "Gateway greșit", "@response502": {}, - "response503": "Service Unavailable", + "response503": "Serviciu indisponibil", "@response503": {}, - "response504": "Gateway Timeout", + "response504": "Timeout gateway", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "Versiunea HTTP nu este suportată", "@response505": {}, "responseData": "Response data", "@responseData": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 4e5a2c8..72eee06 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -42,7 +42,7 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Kvadrat (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Allokera lager", "@allocateStock": {}, @@ -454,7 +454,7 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Felaktigt användarnamn / lösenord kombination", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Faktura", "@invoice": {}, "invoiceNumber": "Fakturanummer", "@invoiceNumber": {}, @@ -660,7 +660,7 @@ "@permissionAccountDenied": {}, "permissionRequired": "Särskilda behörigheter krävs", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, "printLabel": "Skriv ut etikett", "@printLabel": {}, @@ -1172,7 +1172,7 @@ "@yes": {}, "price": "Pris", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Prisintervall", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, @@ -1194,7 +1194,7 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Valuta", "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {} diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 8e24014..804aaae 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Tahsisli stok", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Tahsis Edilen Stok", "@allocatedStock": {}, "appReleaseNotes": "Uygulama yayınlama notlarını göster", "@appReleaseNotes": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Silme işlemi başarılı", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Teslim Tarihi", "@deliveryDate": {}, "description": "Açıklama", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Teslimatları Göster", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Bekleyen teslimatları ana ekranda göster", "@homeShowShipmentsDescription": {}, "homeShowSo": "Satış Siparişlerini Göster", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Fatura", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Fatura Numarası", "@invoiceNumber": {}, "issue": "Sorun", "@issue": {}, @@ -538,9 +538,9 @@ "@missingData": {}, "name": "Adı", "@name": {}, - "no": "No", + "no": "Hayır", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "Yok / Geçerli Değil", "@notApplicable": {}, "notConnected": "Bağlı değil", "@notConnected": {}, @@ -654,7 +654,7 @@ "@password": {}, "passwordEmpty": "Parola boş bırakılamaz", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Beklemede", "@pending": {}, "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", "@permissionAccountDenied": {}, @@ -934,33 +934,33 @@ "@serverNotConnected": {}, "serverNotSelected": "Sunucu bulunamadı", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Teslimat", "@shipment": {}, "shipments": "Gönderiler", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Bekleyen Teslimatlar", "@shipmentsPending": {}, "shipmentAdd": "Gönderi Ekle", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Teslimatı Kontrol Et", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Bu teslimatı kontrol edildi olarak işaretle", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Teslimat Kontrol Edildi", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Teslimat Tarihi", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Teslimatı Düzenle", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Teslimat Referansı", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Teslimatı Gönder", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Teslimat İşaretini Kaldır", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Bu teslimatı kontrol edilmedi olarak işaretle", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Teslimat Güncellendi", "@shipmentUpdated": {}, "shipped": "Gönderildi", "@shipped": {}, @@ -1106,7 +1106,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Toplam Fiyat", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Takip Numarası", "@trackingNumber": {}, "transfer": "Aktarım", "@transfer": { @@ -1168,7 +1168,7 @@ "@viewSupplierPart": {}, "website": "Web sitesi", "@website": {}, - "yes": "Yes", + "yes": "Evet", "@yes": {}, "price": "Fiyat", "@price": {}, diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 6947b48..c10396c 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -856,7 +856,7 @@ "@scanBarcode": {}, "scanSupplierPart": "Сканувати штрих-код позиції постачальника", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "", "@scanIntoLocation": {}, "scanIntoLocationDetail": "Scan this item into location", "@scanIntoLocationDetail": {}, From ed7d73b9c0b682ed2047b503e540a3542d4b01df Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Nov 2025 23:37:05 +1100 Subject: [PATCH 719/746] Default location (#715) * Fix async loading of parent part - Don't block render while fetching data * Display default location on part detail page * Use pathstring instead of name * Update release notes * Display in stock detail too * dart format --- assets/release_notes.md | 5 +++ lib/l10n/app_en.arb | 4 ++- lib/widget/part/part_detail.dart | 53 +++++++++++++++++++++++++----- lib/widget/stock/stock_detail.dart | 35 +++++++++++++++++++- pubspec.yaml | 2 +- 5 files changed, 87 insertions(+), 12 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 2e6b291..b1c2f95 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.21.0 - November 2025 +--- + +- Display default stock location in part detail page + ### 0.20.2 - November 2025 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 83fef3a..b57df1f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -719,7 +719,6 @@ "languageSelect": "Select Language", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", "@lastStocktake": {}, @@ -753,6 +752,9 @@ "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "No location specified", "@locationNotSet": {}, diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 4cbfa49..e54bb75 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -47,6 +47,8 @@ class _PartDisplayState extends RefreshableState { InvenTreePart? parentPart; + InvenTreeStockLocation? defaultLocation; + int parameterCount = 0; bool allowLabelPrinting = false; @@ -177,16 +179,35 @@ class _PartDisplayState extends RefreshableState { // If the part points to a parent "template" part, request that too int? templatePartId = part.variantOf; - if (templatePartId == null) { - parentPart = null; - } else { - final result = await InvenTreePart().get(templatePartId); - - if (result != null && result is InvenTreePart) { - parentPart = result; - } else { + if (templatePartId != null) { + InvenTreePart().get(templatePartId).then((value) { + if (mounted) { + setState(() { + parentPart = value as InvenTreePart?; + }); + } + }); + } else if (mounted) { + setState(() { parentPart = null; - } + }); + } + + // Is there a default location specified for this part? + int? defaultLocationId = part.defaultLocation; + + if (defaultLocationId != null) { + InvenTreeStockLocation().get(defaultLocationId).then((value) { + if (mounted) { + setState(() { + defaultLocation = value as InvenTreeStockLocation?; + }); + } + }); + } else if (mounted) { + setState(() { + defaultLocation = null; + }); } // Request part test templates @@ -414,6 +435,20 @@ class _PartDisplayState extends RefreshableState { ), ); + if (defaultLocation != null) { + tiles.add( + ListTile( + title: Text(L10().locationDefault), + subtitle: Text(defaultLocation!.pathstring), + leading: Icon(TablerIcons.map_pin), + trailing: LinkIcon(), + onTap: () { + defaultLocation?.goToDetailPage(context); + }, + ), + ); + } + if (showPricing && partPricing != null) { String pricing = formatPriceRange( partPricing?.overallMin, diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 19f1592..648610c 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -49,6 +49,7 @@ class _StockItemDisplayState extends RefreshableState { // Linked data fields InvenTreePart? part; + InvenTreeStockLocation? defaultLocation; InvenTreeSalesOrder? salesOrder; InvenTreeCompany? customer; @@ -234,6 +235,23 @@ class _StockItemDisplayState extends RefreshableState { stockShowTests &= part?.isTrackable ?? false; + // Request default location + int? defaultLocationId = part?.defaultLocation; + + if (defaultLocationId != null) { + InvenTreeStockLocation().get(defaultLocationId).then((value) { + if (mounted) { + setState(() { + defaultLocation = value as InvenTreeStockLocation?; + }); + } + }); + } else if (mounted) { + setState(() { + defaultLocation = null; + }); + } + // Request test results (async) if (stockShowTests) { widget.item.getTestResults().then((value) { @@ -569,6 +587,21 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (defaultLocation != null && + defaultLocation?.pk != widget.item.locationId) { + tiles.add( + ListTile( + title: Text(L10().locationDefault), + subtitle: Text(defaultLocation!.pathstring), + leading: Icon(TablerIcons.map_pin), + trailing: LinkIcon(), + onTap: () { + defaultLocation?.goToDetailPage(context); + }, + ), + ); + } + // Quantity information if (widget.item.isSerialized()) { tiles.add( @@ -744,7 +777,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().lastStocktake), - subtitle: Text(widget.item.stocktakeDateString), + trailing: LargeText(widget.item.stocktakeDateString), leading: Icon(TablerIcons.calendar), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index a6c479e..a445035 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.20.2+105 +version: 0.21.0+106 environment: sdk: ^3.8.1 From 6707f89019db8bf2168bef75538208f560662d91 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Nov 2025 23:54:03 +1100 Subject: [PATCH 720/746] Display supplier part stock (#717) * Display supplier part stock * dart format * Update release notes --- assets/release_notes.md | 3 ++- lib/inventree/company.dart | 4 +++ lib/widget/company/supplier_part_detail.dart | 26 +++++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index b1c2f95..413d34a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,7 +1,8 @@ ### 0.21.0 - November 2025 --- -- Display default stock location in part detail page +- Display default stock location in Part detail page +- Display stock information in SupplierPart detail page ### 0.20.2 - November 2025 --- diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index f9f6b42..a2a3f21 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -225,6 +225,10 @@ class InvenTreeSupplierPart extends InvenTreeModel { int get partId => getInt("part"); + double get inStock => getDouble("in_stock"); + + double get onOrder => getDouble("on_order"); + String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index b2a965f..77e29ab 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/widget/link_icon.dart"; import "package:inventree/app_colors.dart"; @@ -15,6 +16,7 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/company/manufacturer_part_detail.dart"; +import "package:inventree/widget/stock/stock_list.dart"; /* * Detail widget for viewing a single SupplierPart instance @@ -142,6 +144,28 @@ class _SupplierPartDisplayState ); } + // Stock levels associated with this SupplierPart + tiles.add( + ListTile( + title: Text(L10().availableStock), + leading: Icon(TablerIcons.packages), + trailing: LinkIcon( + text: simpleNumberString(widget.supplierPart.inStock), + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockItemList({ + "in_stock": "true", + "supplier_part": widget.supplierPart.pkString, + }), + ), + ); + }, + ), + ); + // Supplier details tiles.add( ListTile( @@ -196,7 +220,7 @@ class _SupplierPartDisplayState tiles.add( ListTile( - title: Text(L10().manufacturerPartNumber), + title: Text(L10().manufacturerPart), subtitle: Text(widget.supplierPart.MPN), leading: Icon(TablerIcons.hash, color: COLOR_ACTION), trailing: LinkIcon(), From 8a4750d298c4e2e0012bc6d33b54d012b78a5e34 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 15 Nov 2025 08:03:12 +1100 Subject: [PATCH 721/746] New Crowdin updates (#719) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 2 ++ lib/l10n/bg_BG/app_bg_BG.arb | 2 ++ lib/l10n/cs_CZ/app_cs_CZ.arb | 2 ++ lib/l10n/da_DK/app_da_DK.arb | 2 ++ lib/l10n/de_DE/app_de_DE.arb | 6 ++++-- lib/l10n/el_GR/app_el_GR.arb | 2 ++ lib/l10n/es_ES/app_es_ES.arb | 2 ++ lib/l10n/es_MX/app_es_MX.arb | 2 ++ lib/l10n/et_EE/app_et_EE.arb | 2 ++ lib/l10n/fa_IR/app_fa_IR.arb | 2 ++ lib/l10n/fi_FI/app_fi_FI.arb | 2 ++ lib/l10n/fr_FR/app_fr_FR.arb | 2 ++ lib/l10n/he_IL/app_he_IL.arb | 2 ++ lib/l10n/hi_IN/app_hi_IN.arb | 2 ++ lib/l10n/hu_HU/app_hu_HU.arb | 2 ++ lib/l10n/id_ID/app_id_ID.arb | 2 ++ lib/l10n/it_IT/app_it_IT.arb | 2 ++ lib/l10n/ja_JP/app_ja_JP.arb | 2 ++ lib/l10n/ko_KR/app_ko_KR.arb | 2 ++ lib/l10n/lt_LT/app_lt_LT.arb | 2 ++ lib/l10n/lv_LV/app_lv_LV.arb | 2 ++ lib/l10n/nl_NL/app_nl_NL.arb | 2 ++ lib/l10n/no_NO/app_no_NO.arb | 2 ++ lib/l10n/pl_PL/app_pl_PL.arb | 2 ++ lib/l10n/pt_BR/app_pt_BR.arb | 2 ++ lib/l10n/pt_PT/app_pt_PT.arb | 2 ++ lib/l10n/ro_RO/app_ro_RO.arb | 2 ++ lib/l10n/ru_RU/app_ru_RU.arb | 2 ++ lib/l10n/sk_SK/app_sk_SK.arb | 2 ++ lib/l10n/sl_SI/app_sl_SI.arb | 2 ++ lib/l10n/sr_CS/app_sr_CS.arb | 2 ++ lib/l10n/sv_SE/app_sv_SE.arb | 2 ++ lib/l10n/th_TH/app_th_TH.arb | 2 ++ lib/l10n/tr_TR/app_tr_TR.arb | 2 ++ lib/l10n/vi_VN/app_vi_VN.arb | 2 ++ lib/l10n/zh_CN/app_zh_CN.arb | 2 ++ lib/l10n/zh_TW/app_zh_TW.arb | 2 ++ 37 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index c91a4af..f865457 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index aaa8f5c..57bd141 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 6d05582..2855022 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Vytvořit nové skladové místo", "@locationCreateDetail": {}, + "locationDefault": "Výchozí umístění", + "@locationDefault": {}, "locationNotSet": "Není zadáno žádné umístění", "@locationNotSet": {}, "locationUpdated": "Skladové místo bylo aktualizováno", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 7683b84..41f578c 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 86a9617..a6725bd 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Bestand zuweisen", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Zugewiesener Bestand", "@allocatedStock": {}, "appReleaseNotes": "App-Versionshinweise anzeigen", "@appReleaseNotes": {}, @@ -182,7 +182,7 @@ "@companies": {}, "complete": "", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Bestellung abschließen", "@completeOrder": {}, "completionDate": "Abgeschlossen am", "@completionDate": {}, @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Neuen Lagerort erstellen", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Lagerort nicht angegeben", "@locationNotSet": {}, "locationUpdated": "Lagerort aktualisiert", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index a3a252b..243b8e5 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 28a808d..98f8eb6 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Crear nueva ubicación de stock", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No se especificó ninguna ubicación", "@locationNotSet": {}, "locationUpdated": "Ubicación de stock actualizada", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index f70e9d0..87e27b3 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Crear nueva ubicación de inventario", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No se especificó ninguna ubicación", "@locationNotSet": {}, "locationUpdated": "Ubicación de inventario actualizada", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 2bd5e32..b887671 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 131d551..2dc9b6c 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "مکان سهام جدید ایجاد کنید", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "هیچ مکانی مشخص نشده است", "@locationNotSet": {}, "locationUpdated": "مکان سهام به روز شد", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 3126d75..b125042 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Sijaintia ei ole määritetty", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index f5f55ac..9762e8a 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Créer un nouvel emplacement de stock", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Aucun emplacement spécifié", "@locationNotSet": {}, "locationUpdated": "Emplacement du stock mis à jour", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 2099406..ef1c0b9 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "צור מיקום מלאי חדש", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "לא צוין מיקום", "@locationNotSet": {}, "locationUpdated": "מיקום המלאי עודכן", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 1bf6e29..9bdf06b 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index b3ba87d..1837a91 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Új készlet hely létrehozása", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nincs megadva hely", "@locationNotSet": {}, "locationUpdated": "Készlet hely adatai frissítve", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 9d2ae4b..205c20e 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index af8f225..d50a788 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Crea nuova ubicazione di magazzino", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nessuna ubicazione specificata", "@locationNotSet": {}, "locationUpdated": "Ubicazione di magazzino aggiornata", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 170c512..0489fcf 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "新しい在庫場所を作成", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "在庫場所が指定されていません", "@locationNotSet": {}, "locationUpdated": "在庫場所を更新しました", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 6241ddb..ba576bf 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 6e5ff34..abb7b83 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 7dbe58f..acb13d5 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 4e574ec..83d40f0 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Creëer nieuwe voorraadlocatie", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Geen locatie opgegeven", "@locationNotSet": {}, "locationUpdated": "Voorraadlocatie bijgewerkt", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 408c72b..3c6ee3d 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Opprett ny lagerplassering", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Ingen plassering spesifisert", "@locationNotSet": {}, "locationUpdated": "Lagerplassering oppdatert", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 8b8ac2a..2743161 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Utwórz nową pozycję magazynową", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nie określono lokacji", "@locationNotSet": {}, "locationUpdated": "Lokalizacja stanu magazynowego została zaktualizowana", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 7e715d6..43a7cfb 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Criar nova localizacao no estoque", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nenhuma localizacao especificada", "@locationNotSet": {}, "locationUpdated": "Localizacao no estoque atualizada", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index de33d15..c0b8366 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 2fc5240..67150c0 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Creează o nouă locație de stoc", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nici o locaţie specificată", "@locationNotSet": {}, "locationUpdated": "Locație stoc actualizată", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 800335e..3d31ce2 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Создать новое расположение склада", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Не указано месторасположение", "@locationNotSet": {}, "locationUpdated": "Расположение склада обновлено", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index a7d26a4..e0eabe3 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 3ca8730..746c845 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index c3e9f4b..0e2d400 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Kreiraj novu lokaciju zaliha", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Nema određene lokacije", "@locationNotSet": {}, "locationUpdated": "Ažurirana lokacija zaliha", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 72eee06..e14da80 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Skapa ny lagerplats", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Ingen plats specificerad", "@locationNotSet": {}, "locationUpdated": "Lagerplatsen uppdaterad", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 2206a8c..d37c3c3 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "No location specified", "@locationNotSet": {}, "locationUpdated": "Stock location updated", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 804aaae..3bfed5e 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Yeni stok konumu oluştur", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Belirtilmiş konum yok", "@locationNotSet": {}, "locationUpdated": "Stok lokasyonu güncellendi", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 8639cdb..fd0d271 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "Thêm mới vị trí kho hàng", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Không xác định được vị trí", "@locationNotSet": {}, "locationUpdated": "Cập nhật vị trí kho hàng", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index fb1bd41..2826146 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "创建新库存地点", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "没有指定仓储位置", "@locationNotSet": {}, "locationUpdated": "库存地点已更新", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 6d6f300..849aefe 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -510,6 +510,8 @@ "@locationCreate": {}, "locationCreateDetail": "創建新庫存地點", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "沒有指定倉儲位置", "@locationNotSet": {}, "locationUpdated": "庫存地點已更新", From a75245b183f473b9e8b8d1e29cfc05f67cd6329c Mon Sep 17 00:00:00 2001 From: Alexander Leisentritt Date: Wed, 19 Nov 2025 20:44:02 +0100 Subject: [PATCH 722/746] Add zoom slider to barcode scanning (#725) --- lib/barcode/camera_controller.dart | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index c456721..0cfe9cb 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -41,6 +41,8 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { String scanned_code = ""; + double zoomFactor = 0.0; + final MobileScannerController controller = MobileScannerController( autoZoom: true, ); @@ -311,6 +313,60 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { return SpeedDial(icon: Icons.more_horiz, children: actions); } + Widget zoomSlider() { + return Positioned( + left: 0, + right: 0, + bottom: 16, + child: Center( + child: Container( + width: 225, + height: 56, + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(28), + ), + padding: EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Icon(TablerIcons.zoom_out, color: Colors.white, size: 20), + Expanded( + child: Slider( + value: zoomFactor, + min: 0.0, + max: 1.0, + activeColor: Colors.white, + inactiveColor: Colors.white.withValues(alpha: 0.3), + onChanged: (value) { + setState(() { + zoomFactor = value; + controller.setZoomScale(value); + }); + }, + onChangeStart: (value) async { + if (mounted) { + setState(() { + scanning_paused = true; + }); + } + }, + onChangeEnd: (value) async { + if (mounted) { + setState(() { + scanning_paused = false; + }); + } + }, + ), + ), + Icon(TablerIcons.zoom_in, color: Colors.white, size: 20), + ], + ), + ), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -333,6 +389,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { Column(children: [Expanded(child: BarcodeReader(context))]), topCenterOverlay(), bottomCenterOverlay(), + zoomSlider(), ], ), ), From d039f3cfcfa7335ced082a0898ce69a75ae7ddb9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Nov 2025 06:48:19 +1100 Subject: [PATCH 723/746] New Crowdin updates (#722) * New translations app_en.arb (German) * New translations app_en.arb (German) * New translations app_en.arb (Romanian) * New translations app_en.arb (Italian) * New translations app_en.arb (Swedish) --- lib/l10n/de_DE/app_de_DE.arb | 38 +++++++++++++++---------------- lib/l10n/it_IT/app_it_IT.arb | 44 ++++++++++++++++++------------------ lib/l10n/ro_RO/app_ro_RO.arb | 2 +- lib/l10n/sv_SE/app_sv_SE.arb | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index a6725bd..c92af22 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Löschvorgang erfolgreich", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Lieferdatum", "@deliveryDate": {}, "description": "Beschreibung", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Lieferungen anzeigen", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Ausstehende Lieferaufträge auf der Startseite anzeigen", "@homeShowShipmentsDescription": {}, "homeShowSo": "Aufträge anzeigen", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Rechnung", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Rechnungsnummer", "@invoiceNumber": {}, "issue": "Aufgeben", "@issue": {}, @@ -510,7 +510,7 @@ "@locationCreate": {}, "locationCreateDetail": "Neuen Lagerort erstellen", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Standard Lagerort", "@locationDefault": {}, "locationNotSet": "Lagerort nicht angegeben", "@locationNotSet": {}, @@ -540,9 +540,9 @@ "@missingData": {}, "name": "Name", "@name": {}, - "no": "No", + "no": "Nein", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "nicht verfügbar", "@notApplicable": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, @@ -656,7 +656,7 @@ "@password": {}, "passwordEmpty": "Passwort darf nicht leer sein", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Ausstehend", "@pending": {}, "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", "@permissionAccountDenied": {}, @@ -936,23 +936,23 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Sendung", "@shipment": {}, "shipments": "Lieferungen", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Ausstehende Sendungen", "@shipmentsPending": {}, "shipmentAdd": "Lieferung hinzufügen", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Sendung prüfen", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Diese Sendung als geprüft markieren", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Sendung geprüft", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Versanddatum", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Sendung bearbeiten", "@shipmentEdit": {}, "shipmentReference": "Shipment Reference", "@shipmentReference": {}, @@ -1108,7 +1108,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Gesamtbetrag", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Sendungsverfolgungsnummer", "@trackingNumber": {}, "transfer": "Verschieben", "@transfer": { @@ -1170,13 +1170,13 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, - "yes": "Yes", + "yes": "Ja", "@yes": {}, "price": "Preis", "@price": {}, "priceRange": "Preisspanne", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Mindestpreis überschreiben", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index d50a788..81a74a8 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Alloca stock", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Scorte Assegnate", "@allocatedStock": {}, "appReleaseNotes": "Mostra le note di rilascio dell'app", "@appReleaseNotes": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Operazione di eliminazione riuscita", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Data di consegna", "@deliveryDate": {}, "description": "Descrizione", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Mostra Spedizioni", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Mostra le spedizioni in sospeso nella schermata home", "@homeShowShipmentsDescription": {}, "homeShowSo": "Mostra ordini di vendita", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Combinazione nome utente e password non valida", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Fattura", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Numero Fattura", "@invoiceNumber": {}, "issue": "Problema", "@issue": {}, @@ -510,7 +510,7 @@ "@locationCreate": {}, "locationCreateDetail": "Crea nuova ubicazione di magazzino", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Posizione Predefinita", "@locationDefault": {}, "locationNotSet": "Nessuna ubicazione specificata", "@locationNotSet": {}, @@ -656,7 +656,7 @@ "@password": {}, "passwordEmpty": "La password non può essere vuota", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "In sospeso", "@pending": {}, "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", "@permissionAccountDenied": {}, @@ -936,33 +936,33 @@ "@serverNotConnected": {}, "serverNotSelected": "Server non selezionato", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Spedizione", "@shipment": {}, "shipments": "Spedizioni", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Spedizioni in sospeso", "@shipmentsPending": {}, "shipmentAdd": "Aggiungi Spedizione", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Controlla spedizione", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Segna questa spedizione come controllata", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Spedizione Controllata", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Data di spedizione", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Modifica spedizione", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Riferimento della spedizione", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Invia Spedizione", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Deseleziona Spedizione", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Contrassegna questa spedizione come non controllata", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Spedizione Aggiornata", "@shipmentUpdated": {}, "shipped": "Spedito", "@shipped": {}, @@ -1108,7 +1108,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Prezzo Totale", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Numero Di Tracking", "@trackingNumber": {}, "transfer": "Trasferisci", "@transfer": { @@ -1170,7 +1170,7 @@ "@viewSupplierPart": {}, "website": "Sito Web", "@website": {}, - "yes": "Yes", + "yes": "Si", "@yes": {}, "price": "Prezzo", "@price": {}, diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 67150c0..ca8982e 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -510,7 +510,7 @@ "@locationCreate": {}, "locationCreateDetail": "Creează o nouă locație de stoc", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Locație implicită", "@locationDefault": {}, "locationNotSet": "Nici o locaţie specificată", "@locationNotSet": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index e14da80..8d7c456 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -656,7 +656,7 @@ "@password": {}, "passwordEmpty": "Lösenordet får inte vara tomt", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Väntande", "@pending": {}, "permissionAccountDenied": "Ditt konto har inte de rättigheter som krävs för att utföra denna åtgärd", "@permissionAccountDenied": {}, From e41842a31dbad2e1c8e6e83280562b6d2966cc5f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 20 Nov 2025 07:51:19 +1100 Subject: [PATCH 724/746] Barcode tweaks (#726) * Barcode tweaks - Disable autozoom - Update release notes - Update contributor credits * format --- assets/credits.md | 1 + assets/release_notes.md | 1 + lib/barcode/camera_controller.dart | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/credits.md b/assets/credits.md index abf8611..31eb4f0 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -10,6 +10,7 @@ Thanks to the following contributors, for their work building this app! - [Bobbe](https://github.com/30350n) - [awnz](https://github.com/awnz) - [joaomnuno](https://github.com/joaomnuno) +- [Alex9779](https://github.com/Alex9779) -------- ## Assets diff --git a/assets/release_notes.md b/assets/release_notes.md index 413d34a..21b0d09 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.21.0 - November 2025 --- +- Adds zoom controller for barcode scanner camera view - Display default stock location in Part detail page - Display stock information in SupplierPart detail page diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 0cfe9cb..2baaca0 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -44,7 +44,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { double zoomFactor = 0.0; final MobileScannerController controller = MobileScannerController( - autoZoom: true, + autoZoom: false, // Disable autoZoom as we implement a manual slider ); @override From 13d95dd1b17328748b62e7f4eb49871ac1137d55 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 22 Nov 2025 07:26:37 +1100 Subject: [PATCH 725/746] Modern Label printing (#724) * Basic widget * Redirect label printing action * Refactor label printing code * Construct form elements * Refactor to allow re-use of forms * Basic rendering of label printing form * Remove dead code * Pass custom handler through to form context * Refactoring API forms: - Allow custom pk field name - Add callback when values change * linting * Dynamically rebuild form * Handle nested fields * Handle label printing status * Run dart format * Update release notes * Remove unused var * Enable close icon * Handle initial plugin default value * Store default values: - Selected template (per label type) - Selected printing plugin * Dart format * Fix dart linting * use setter * Just use a public field --- assets/release_notes.md | 1 + lib/api.dart | 17 +- lib/api_form.dart | 233 ++++++++------ lib/l10n/app_en.arb | 6 + lib/labels.dart | 422 ++++++++++++++----------- lib/preferences.dart | 4 + lib/widget/part/part_detail.dart | 32 +- lib/widget/snacks.dart | 1 + lib/widget/stock/location_display.dart | 39 +-- lib/widget/stock/stock_detail.dart | 38 +-- 10 files changed, 425 insertions(+), 368 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 21b0d09..f97832a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.21.0 - November 2025 --- +- Support label printing again, fixing issues with new printing API - Adds zoom controller for barcode scanner camera view - Display default stock location in Part detail page - Display stock information in SupplierPart detail page diff --git a/lib/api.dart b/lib/api.dart index a2a48f9..1d24b39 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -7,6 +7,7 @@ import "package:http/http.dart" as http; import "package:http/io_client.dart"; import "package:intl/intl.dart"; import "package:inventree/main.dart"; +import "package:inventree/widget/progress.dart"; import "package:one_context/one_context.dart"; import "package:open_filex/open_filex.dart"; import "package:cached_network_image/cached_network_image.dart"; @@ -912,6 +913,8 @@ class InvenTreeAPI { var client = createClient(url, strictHttps: strictHttps); + showLoadingOverlay(); + // Attempt to open a connection to the server try { _request = await client @@ -953,6 +956,7 @@ class InvenTreeAPI { await localFile.writeAsBytes(bytes); if (openOnDownload) { + hideLoadingOverlay(); OpenFilex.open(local_path); } } else { @@ -972,6 +976,8 @@ class InvenTreeAPI { stackTrace, ); } + + hideLoadingOverlay(); } /* @@ -1085,8 +1091,15 @@ class InvenTreeAPI { * We send this with the currently selected "locale", * so that (hopefully) the field messages are correctly translated */ - Future options(String url) async { - HttpClientRequest? request = await apiRequest(url, "OPTIONS"); + Future options( + String url, { + Map params = const {}, + }) async { + HttpClientRequest? request = await apiRequest( + url, + "OPTIONS", + urlParams: params, + ); if (request == null) { // Return an "invalid" APIResponse diff --git a/lib/api_form.dart b/lib/api_form.dart index 7852c45..ea0bc79 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -26,23 +26,52 @@ import "package:inventree/widget/fields.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; +/* + * Extract field options from a returned OPTIONS request + */ +Map extractFields(APIResponse response) { + if (!response.isValid()) { + return {}; + } + + var data = response.asMap(); + + if (!data.containsKey("actions")) { + return {}; + } + + var actions = response.data["actions"] as Map; + + dynamic result = actions["POST"] ?? actions["PUT"] ?? actions["PATCH"] ?? {}; + + return result as Map; +} + /* * Class that represents a single "form field", * defined by the InvenTree API */ class APIFormField { // Constructor - APIFormField(this.name, this.data); + APIFormField(this.name, this.data, {this.formHandler}); // File to be uploaded for this filed File? attachedfile; + APIFormWidgetState? formHandler; + // Name of this field final String name; // JSON data which defines the field final Map data; + // Function to update the value of this field + void setFieldValue(dynamic val) { + data["value"] = val; + formHandler?.onValueChanged(name, value); + } + // JSON field definition provided by the server Map definition = {}; @@ -88,6 +117,8 @@ class APIFormField { } } + String get pk_field => (getParameter("pk_field") ?? "pk") as String; + // Get the "api_url" associated with a related field String get api_url => (getParameter("api_url") ?? "") as String; @@ -244,18 +275,13 @@ class APIFormField { return; } - int? pk = int.tryParse(value.toString()); - - if (pk == null) { - return; - } - - String url = api_url + "/" + pk.toString() + "/"; + String url = api_url + "/" + value.toString() + "/"; final APIResponse response = await InvenTreeAPI().get(url, params: filters); if (response.successful()) { initial_data = response.data; + formHandler?.onValueChanged(name, value); } } @@ -269,6 +295,7 @@ class APIFormField { return _constructBoolean(); case "related field": return _constructRelatedField(); + case "integer": case "float": case "decimal": return _constructFloatField(); @@ -318,8 +345,7 @@ class APIFormField { onPressed: () async { var handler = UniqueBarcodeHandler((String hash) { controller.text = hash; - data["value"] = hash; - + setFieldValue(hash); barcodeSuccess(L10().barcodeAssigned); }); @@ -347,9 +373,9 @@ class APIFormField { onChanged: (DateTime? time) { // Save the time string if (time == null) { - data["value"] = null; + setFieldValue(null); } else { - data["value"] = time.toString().split(" ").first; + setFieldValue(time.toString().split(" ").first); } }, onShowPicker: (context, value) async { @@ -432,9 +458,9 @@ class APIFormField { }, onSaved: (item) { if (item == null) { - data["value"] = null; + setFieldValue(null); } else { - data["value"] = item["value"]; + setFieldValue(item["value"]); } }, ); @@ -481,7 +507,7 @@ class APIFormField { return null; }, onSaved: (val) { - data["value"] = val; + setFieldValue(val); }, ); } @@ -527,7 +553,20 @@ class APIFormField { hintText: helpText, ), ), - onChanged: null, + onChanged: (item) { + if (item != null) { + setFieldValue(item[pk_field]); + } else { + setFieldValue(null); + } + }, + onSaved: (item) { + if (item != null) { + setFieldValue(item[pk_field]); + } else { + setFieldValue(null); + } + }, itemAsString: (dynamic item) { Map data = item as Map; @@ -551,13 +590,6 @@ class APIFormField { dropdownBuilder: (context, item) { return _renderRelatedField(name, item, true, false); }, - onSaved: (item) { - if (item != null) { - data["value"] = item["pk"]; - } else { - data["value"] = null; - } - }, compareFn: (dynamic item, dynamic selectedItem) { // Comparison is based on the PK value @@ -568,7 +600,8 @@ class APIFormField { bool result = false; try { - result = item["pk"].toString() == selectedItem["pk"].toString(); + result = + item[pk_field].toString() == selectedItem[pk_field].toString(); } catch (error) { // Catch any conversion errors result = false; @@ -765,6 +798,18 @@ class APIFormField { so.customer?.thumbnail ?? so.customer?.image ?? "", ), ); + case "labeltemplate": + return ListTile( + title: Text((data["name"] ?? "").toString()), + subtitle: Text((data["description"] ?? "").toString()), + ); + case "pluginconfig": + return ListTile( + title: Text( + (data["meta"]?["human_name"] ?? data["name"] ?? "").toString(), + ), + subtitle: Text((data["meta"]?["description"] ?? "").toString()), + ); default: return ListTile( title: Text( @@ -810,8 +855,11 @@ class APIFormField { maxLines: multiline ? null : 1, expands: false, initialValue: (value ?? "") as String, + onChanged: (val) { + setFieldValue(val); + }, onSaved: (val) { - data["value"] = val; + setFieldValue(val); }, validator: (value) { if (required && (value == null || value.isEmpty)) { @@ -842,7 +890,7 @@ class APIFormField { initial: initial_value, tristate: (getParameter("tristate") ?? false) as bool, onSaved: (val) { - data["value"] = val; + setFieldValue(val); }, ); } @@ -865,27 +913,6 @@ class APIFormField { } } -/* - * Extract field options from a returned OPTIONS request - */ -Map extractFields(APIResponse response) { - if (!response.isValid()) { - return {}; - } - - var data = response.asMap(); - - if (!data.containsKey("actions")) { - return {}; - } - - var actions = response.data["actions"] as Map; - - dynamic result = actions["POST"] ?? actions["PUT"] ?? actions["PATCH"] ?? {}; - - return result as Map; -} - /* * Extract a field definition (map) from the provided JSON data. * @@ -981,6 +1008,7 @@ Future launchApiForm( Function(Map)? onSuccess, bool Function(Map)? validate, Function? onCancel, + APIFormWidgetState? formHandler, IconData icon = TablerIcons.device_floppy, }) async { showLoadingOverlay(); @@ -1041,7 +1069,7 @@ Future launchApiForm( field.data["instance_value"] = model_value; if (field.data["value"] == null) { - field.data["value"] = model_value; + field.setFieldValue(model_value); } } formFields.add(field); @@ -1066,6 +1094,7 @@ Future launchApiForm( onSuccess: onSuccess, validate: validate, fileField: fileField, + state: formHandler, icon: icon, ), ), @@ -1079,6 +1108,7 @@ class APIFormWidget extends StatefulWidget { this.fields, this.method, { Key? key, + this.state, this.onSuccess, this.validate, this.fileField = "", @@ -1105,12 +1135,15 @@ class APIFormWidget extends StatefulWidget { final bool Function(Map)? validate; + final APIFormWidgetState? state; + + // Default form handler is constructed if none is provided @override - _APIFormWidgetState createState() => _APIFormWidgetState(); + APIFormWidgetState createState() => state ?? APIFormWidgetState(); } -class _APIFormWidgetState extends State { - _APIFormWidgetState() : super(); +class APIFormWidgetState extends State { + APIFormWidgetState() : super(); final _formKey = GlobalKey(); @@ -1118,6 +1151,33 @@ class _APIFormWidgetState extends State { bool spacerRequired = false; + // Return a list of all fields used for this form + // The default implementation just returns the fields provided to the widget + // However, custom form implementations may override this function + List get formFields { + final List fields = widget.fields; + + // Ensure each field has access to this form handler + for (var field in fields) { + field.formHandler ??= this; + } + + return fields; + } + + // Callback for when a field value is changed + // Default implementation does nothing, + // but custom form implementations may override this function + void onValueChanged(String field, dynamic value) {} + + Future handleSuccess( + Map submittedData, + Map responseData, + ) async { + widget.onSuccess?.call(responseData); + Navigator.pop(context); + } + List _buildForm() { List widgets = []; @@ -1135,7 +1195,7 @@ class _APIFormWidgetState extends State { widgets.add(Divider(height: 5)); } - for (var field in widget.fields) { + for (var field in formFields) { if (field.hidden) { continue; } @@ -1190,7 +1250,7 @@ class _APIFormWidgetState extends State { // Pop the "file" field data.remove(widget.fileField); - for (var field in widget.fields) { + for (var field in formFields) { if (field.name == widget.fileField) { File? file = field.attachedfile; @@ -1275,7 +1335,7 @@ class _APIFormWidgetState extends State { match = true; continue; default: - for (var field in widget.fields) { + for (var field in formFields) { // Hidden fields can't display errors, so we won't match if (field.hidden) { continue; @@ -1327,7 +1387,7 @@ class _APIFormWidgetState extends State { // Iterate through and find "simple" top-level fields - for (var field in widget.fields) { + for (var field in formFields) { if (field.readOnly) { continue; } @@ -1366,20 +1426,11 @@ class _APIFormWidgetState extends State { return; } - // Run custom onSuccess function - var successFunc = widget.onSuccess; - // An "empty" URL means we don't want to submit the form anywhere // Perhaps we just want to process the data? if (widget.url.isEmpty) { // Hide the form - Navigator.pop(context); - - if (successFunc != null) { - // Return the raw "submitted" data, rather than the server response - successFunc(data); - } - + handleSuccess(data, {}); return; } @@ -1394,29 +1445,24 @@ class _APIFormWidgetState extends State { case 200: case 201: // Form was successfully validated by the server + // Ensure the response is a valid JSON structure + Map json = {}; - // Hide this form - Navigator.pop(context); + var responseData = response.asMap(); - if (successFunc != null) { - // Ensure the response is a valid JSON structure - Map json = {}; - - var data = response.asMap(); - - for (String key in data.keys) { - json[key.toString()] = data[key]; - } - - successFunc(json); + for (String key in responseData.keys) { + json[key.toString()] = responseData[key]; } + + handleSuccess(data, json); + return; case 400: // Form submission / validation error showSnackIcon(L10().formError, success: false); // Update field errors - for (var field in widget.fields) { + for (var field in formFields) { field.extractErrorMessages(response); } @@ -1444,6 +1490,22 @@ class _APIFormWidgetState extends State { }); } + // Construct the internal form widget, based on the provided fields + Widget buildForm(BuildContext context) { + return Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: _buildForm(), + ), + padding: EdgeInsets.all(16), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -1463,18 +1525,7 @@ class _APIFormWidgetState extends State { ), ], ), - body: Form( - key: _formKey, - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: _buildForm(), - ), - padding: EdgeInsets.all(16), - ), - ), + body: buildForm(context), ); } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b57df1f..9ea177e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -695,6 +695,12 @@ "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", "@labelPrinting": {}, diff --git a/lib/labels.dart b/lib/labels.dart index 10e2c20..2b7cc27 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -1,11 +1,206 @@ import "package:flutter/cupertino.dart"; -import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:flutter/material.dart"; import "package:inventree/api.dart"; -import "package:inventree/widget/progress.dart"; +import "package:inventree/preferences.dart"; import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; +import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; +const String PRINT_LABEL_URL = "api/label/print/"; + +/* + * Custom form handler for label printing. + * Required to manage dynamic form fields. + */ +class LabelFormWidgetState extends APIFormWidgetState { + LabelFormWidgetState() : super(); + + List dynamicFields = []; + + String pluginKey = ""; + String labelType = ""; + + @override + List get formFields { + final baseFields = super.formFields; + + if (pluginKey.isEmpty) { + // Handle case where default plugin is provided + final APIFormField pluginField = baseFields.firstWhere( + (field) => field.name == "plugin", + ); + + if (pluginField.initial_data != null) { + pluginKey = pluginField.value.toString(); + onValueChanged("plugin", pluginKey); + } + } + + return [...baseFields, ...dynamicFields]; + } + + @override + void onValueChanged(String field, dynamic value) { + if (field == "plugin") { + onPluginChanged(value.toString()); + } + } + + @override + Future handleSuccess( + Map submittedData, + Map responseData, + ) async { + super.handleSuccess(submittedData, responseData); + + // Save default values to the database + final String? plugin = submittedData["plugin"]?.toString(); + final int? template = submittedData["template"] as int?; + + // Save default printing plugin + if (plugin != null) { + InvenTreeSettingsManager().setValue(INV_LABEL_DEFAULT_PLUGIN, plugin); + } + + // Save default template for this label type + if (labelType.isNotEmpty && template != null) { + final defaultTemplates = + await InvenTreeSettingsManager().getValue( + INV_LABEL_DEFAULT_TEMPLATES, + null, + ) + as Map?; + + InvenTreeSettingsManager().setValue(INV_LABEL_DEFAULT_TEMPLATES, { + ...?defaultTemplates, + labelType: template, + }); + } + } + + /* + * Re-fetch printing options when the plugin changes + */ + Future onPluginChanged(String key) async { + showLoadingOverlay(); + + InvenTreeAPI().options(PRINT_LABEL_URL, params: {"plugin": key}).then(( + APIResponse response, + ) { + if (response.isValid()) { + updateFields(response); + hideLoadingOverlay(); + } + }); + } + + /* + * Callback when the server responds with printing options, + * based on the selected printing plugin + */ + Future updateFields(APIResponse response) async { + Map printingFields = extractFields(response); + + // Find only the fields which are not in the "base" fields + List uniqueFields = []; + + for (String key in printingFields.keys) { + if (super.formFields.any((field) => field.name == key)) { + continue; + } + + dynamic data = printingFields[key]; + + Map fieldData = {}; + + if (data is Map) { + fieldData = Map.from(data); + } + + APIFormField field = APIFormField(key, fieldData); + field.definition = extractFieldDefinition( + printingFields, + field.lookupPath, + ); + + if (field.type == "dependent field") { + // Dependent fields must be handled separately + + // TODO: This should be refactored into api_form.dart + dynamic child = field.definition["child"]; + + if (child != null && child is Map) { + Map child_map = child as Map; + dynamic nested_children = child_map["children"]; + + if (nested_children != null && nested_children is Map) { + Map nested_child_map = + nested_children as Map; + + for (var field_key in nested_child_map.keys) { + field = APIFormField(field_key, nested_child_map); + field.definition = extractFieldDefinition( + nested_child_map, + field_key, + ); + uniqueFields.add(field); + } + } + } + } else { + // This is a "standard" (non-nested) field + uniqueFields.add(field); + } + } + + if (mounted) { + setState(() { + dynamicFields = uniqueFields; + }); + } + } +} + +Future handlePrintingSuccess( + BuildContext context, + Map data, + int repeatCount, +) async { + const int MAX_REPEATS = 60; + + int id = (data["pk"] ?? -1) as int; + bool complete = (data["complete"] ?? false) as bool; + bool error = data["errors"] != null; + String? output = data["output"] as String?; + + if (complete) { + if (output != null && output.isNotEmpty) { + // An output was generated - we can download it! + showSnackIcon(L10().downloading, success: true); + InvenTreeAPI().downloadFile(output); + } else { + // Label was offloaded, likely to an external printer + showSnackIcon(L10().printLabelSuccess, success: true); + } + } else if (error) { + showSnackIcon(L10().printLabelFailure, success: false); + } else if (repeatCount < MAX_REPEATS && id > 0) { + // Printing is not yet complete, but we have a valid output ID + Future.delayed(Duration(milliseconds: 1000), () async { + // Re-query the printing status + InvenTreeAPI().get("data-output/$id/").then((response) { + if (response.statusCode == 200) { + if (response.data is Map) { + final responseData = response.data as Map; + handlePrintingSuccess(context, responseData, repeatCount + 1); + } + } + }); + }); + } +} + /* * Select a particular label, from a provided list of options, * and print against the selected instances. @@ -13,202 +208,73 @@ import "package:inventree/widget/snacks.dart"; */ Future selectAndPrintLabel( BuildContext context, - List> labels, - int instanceId, String labelType, - String labelQuery, + int instanceId, ) async { if (!InvenTreeAPI().isConnected()) { return; } - // Find a list of available plugins which support label printing - var plugins = InvenTreeAPI().getPlugins(mixin: "labels"); - - dynamic initial_label; - dynamic initial_plugin; - - List> label_options = []; - List> plugin_options = []; - - // Construct list of available label templates - for (var label in labels) { - String name = (label["name"] ?? "").toString(); - String description = (label["description"] ?? "").toString(); - - if (description.isNotEmpty) { - name += " - ${description}"; - } - - int pk = (label["pk"] ?? -1) as int; - - if (name.isNotEmpty && pk > 0) { - label_options.add({"display_name": name, "value": pk}); - } + if (!InvenTreeAPI().supportsModernLabelPrinting) { + // Legacy label printing API not supported + showSnackIcon("Label printing not supported by server", success: false); + return; } - if (label_options.length == 1) { - initial_label = label_options.first["value"]; + // Fetch default values for label printing + + // Default template + final defaultTemplates = await InvenTreeSettingsManager().getValue( + INV_LABEL_DEFAULT_TEMPLATES, + null, + ); + int? defaultTemplate; + + if (defaultTemplates != null && defaultTemplates is Map) { + defaultTemplate = defaultTemplates[labelType] as int?; } - // Construct list of available plugins - for (var plugin in plugins) { - plugin_options.add({"display_name": plugin.humanName, "value": plugin.key}); - } - - String selectedPlugin = await InvenTreeAPI().getUserSetting( - "LABEL_DEFAULT_PRINTER", + // Default plugin + final defaultPlugin = await InvenTreeSettingsManager().getValue( + INV_LABEL_DEFAULT_PLUGIN, + null, ); - if (selectedPlugin.isNotEmpty) { - initial_plugin = selectedPlugin; - } else if (plugin_options.length == 1) { - initial_plugin = plugin_options.first["value"]; - } - - Map fields = { - "label": { - "label": L10().labelTemplate, - "type": "choice", - "value": initial_label, - "choices": label_options, - "required": true, + // Specify a default list of fields for printing + // The selected plugin may optionally extend this list of fields dynamically + Map> baseFields = { + "template": { + "default": defaultTemplate, + "filters": { + "enabled": true, + "model_type": labelType, + "items": instanceId.toString(), + }, }, "plugin": { - "label": L10().pluginPrinter, - "type": "choice", - "value": initial_plugin, - "choices": plugin_options, - "required": true, + "default": defaultPlugin, + "pk_field": "key", + "filters": {"enabled": true, "mixin": "labels"}, + }, + "items": { + "hidden": true, + "value": [instanceId], }, }; + final formHandler = LabelFormWidgetState(); + formHandler.labelType = labelType; + launchApiForm( context, L10().printLabel, - "", - fields, - icon: TablerIcons.printer, - validate: (Map data) { - final template = data["label"]; - final plugin = data["plugin"]; - - if (template == null) { - showSnackIcon(L10().labelSelectTemplate, success: false); - return false; - } - - if (plugin == null) { - showSnackIcon(L10().labelSelectPrinter, success: false); - return false; - } - - return true; - }, - onSuccess: (Map data) async { - int labelId = (data["label"] ?? -1) as int; - var pluginKey = data["plugin"]; - - bool result = false; - - if (labelId != -1 && pluginKey != null) { - showLoadingOverlay(); - - if (InvenTreeAPI().supportsModernLabelPrinting) { - // Modern label printing API uses a POST request to a single API endpoint. - await InvenTreeAPI() - .post( - "/label/print/", - body: { - "plugin": pluginKey, - "template": labelId, - "items": [instanceId], - }, - ) - .then((APIResponse response) { - if (response.isValid() && - response.statusCode >= 200 && - response.statusCode <= 201) { - var data = response.asMap(); - - if (data.containsKey("output")) { - String? label_file = (data["output"]) as String?; - - if (label_file != null && label_file.isNotEmpty) { - // Attempt to open generated file - InvenTreeAPI().downloadFile(label_file); - } - - result = true; - } - } - }); - } else { - // Legacy label printing API - // Uses a GET request to a specially formed URL which depends on the parameters - String url = - "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; - await InvenTreeAPI().get(url).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - var data = response.asMap(); - if (data.containsKey("file")) { - var label_file = (data["file"] ?? "") as String; - - // Attempt to open remote file - InvenTreeAPI().downloadFile(label_file); - result = true; - } - } - }); - } - - hideLoadingOverlay(); - - if (result) { - showSnackIcon(L10().printLabelSuccess, success: true); - } else { - showSnackIcon(L10().printLabelFailure, success: false); - } - } + PRINT_LABEL_URL, + baseFields, + method: "POST", + modelData: {"plugin": defaultPlugin, "template": defaultTemplate}, + formHandler: formHandler, + onSuccess: (data) async { + handlePrintingSuccess(context, data, 0); }, ); } - -/* - * Discover which label templates are available for a given item - */ -Future>> getLabelTemplates( - String labelType, - Map data, -) async { - if (!InvenTreeAPI().isConnected() || - !InvenTreeAPI().supportsMixin("labels")) { - return []; - } - - // Filter by active plugins - data["enabled"] = "true"; - - String url = "/label/template/"; - - if (InvenTreeAPI().supportsModernLabelPrinting) { - data["model_type"] = labelType; - } else { - // Legacy label printing API endpoint - url = "/label/${labelType}/"; - } - - List> labels = []; - - await InvenTreeAPI().get(url, params: data).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - for (var label in response.resultsList()) { - if (label is Map) { - labels.add(label); - } - } - } - }); - - return labels; -} diff --git a/lib/preferences.dart b/lib/preferences.dart index bf0d8ae..de7bb0f 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -25,7 +25,11 @@ const int SCREEN_ORIENTATION_LANDSCAPE = 2; const String INV_SOUNDS_BARCODE = "barcodeSounds"; const String INV_SOUNDS_SERVER = "serverSounds"; +// Label printing settings const String INV_ENABLE_LABEL_PRINTING = "enableLabelPrinting"; +const String INV_LABEL_DEFAULT_TEMPLATES = "defaultLabelTemplates"; +const String INV_LABEL_DEFAULT_PRINTER = "defaultLabelPrinter"; +const String INV_LABEL_DEFAULT_PLUGIN = "defaultLabelPlugin"; // Part settings const String INV_PART_SHOW_PARAMETERS = "partShowParameters"; diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index e54bb75..98cf173 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -63,8 +63,6 @@ class _PartDisplayState extends RefreshableState { InvenTreePartPricing? partPricing; - List> labels = []; - @override String getAppBarTitle() => L10().partDetails; @@ -121,19 +119,13 @@ class _PartDisplayState extends RefreshableState { ); } - if (labels.isNotEmpty) { + if (allowLabelPrinting && api.supportsModernLabelPrinting) { actions.add( SpeedDialChild( child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { - selectAndPrintLabel( - context, - labels, - widget.part.pk, - "part", - "part=${widget.part.pk}", - ); + selectAndPrintLabel(context, "part", widget.part.pk); }, ), ); @@ -271,26 +263,6 @@ class _PartDisplayState extends RefreshableState { }); } }); - - List> _labels = []; - allowLabelPrinting &= api.supportsMixin("labels"); - - if (allowLabelPrinting) { - String model_type = api.supportsModernLabelPrinting - ? InvenTreePart.MODEL_TYPE - : "part"; - String item_key = api.supportsModernLabelPrinting ? "items" : "part"; - - _labels = await getLabelTemplates(model_type, { - item_key: widget.part.pk.toString(), - }); - } - - if (mounted) { - setState(() { - labels = _labels; - }); - } } void _editPartDialog(BuildContext context) { diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index 580955f..f00b1ec 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -64,6 +64,7 @@ void showSnackIcon( }, ), backgroundColor: backgroundColor, + showCloseIcon: true, action: onAction == null ? null : SnackBarAction( diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index 7719724..f6f74db 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -38,7 +38,7 @@ class _LocationDisplayState extends RefreshableState { final InvenTreeStockLocation? location; - List> labels = []; + bool allowLabelPrinting = false; @override String getAppBarTitle() { @@ -179,19 +179,15 @@ class _LocationDisplayState extends RefreshableState { ); } - if (widget.location != null && labels.isNotEmpty) { + if (widget.location != null && + allowLabelPrinting && + api.supportsModernLabelPrinting) { actions.add( SpeedDialChild( child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { - selectAndPrintLabel( - context, - labels, - widget.location!.pk, - "location", - "location=${widget.location!.pk}", - ); + selectAndPrintLabel(context, "stocklocation", widget.location!.pk); }, ), ); @@ -236,33 +232,10 @@ class _LocationDisplayState extends RefreshableState { } } - List> _labels = []; - bool allowLabelPrinting = await InvenTreeSettingsManager().getBool( + allowLabelPrinting = await InvenTreeSettingsManager().getBool( INV_ENABLE_LABEL_PRINTING, true, ); - allowLabelPrinting &= api.supportsMixin("labels"); - - if (allowLabelPrinting) { - if (widget.location != null) { - String model_type = api.supportsModernLabelPrinting - ? InvenTreeStockLocation.MODEL_TYPE - : "location"; - String item_key = api.supportsModernLabelPrinting - ? "items" - : "location"; - - _labels = await getLabelTemplates(model_type, { - item_key: widget.location!.pk.toString(), - }); - } - } - - if (mounted) { - setState(() { - labels = _labels; - }); - } } Future _newLocation(BuildContext context) async { diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 648610c..db295ca 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -128,19 +128,13 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (labels.isNotEmpty) { + if (allowLabelPrinting && api.supportsModernLabelPrinting) { actions.add( SpeedDialChild( child: Icon(TablerIcons.printer), label: L10().printLabel, onTap: () async { - selectAndPrintLabel( - context, - labels, - widget.item.pk, - "stock", - "item=${widget.item.pk}", - ); + selectAndPrintLabel(context, "stockitem", widget.item.pk); }, ), ); @@ -196,10 +190,7 @@ class _StockItemDisplayState extends RefreshableState { return actions; } - // Is label printing enabled for this StockItem? - // This will be determined when the widget is loaded - List> labels = []; - + bool allowLabelPrinting = false; int attachmentCount = 0; @override @@ -318,31 +309,10 @@ class _StockItemDisplayState extends RefreshableState { } } - List> _labels = []; - bool allowLabelPrinting = await InvenTreeSettingsManager().getBool( + allowLabelPrinting = await InvenTreeSettingsManager().getBool( INV_ENABLE_LABEL_PRINTING, true, ); - allowLabelPrinting &= api.supportsMixin("labels"); - - // Request information on labels available for this stock item - if (allowLabelPrinting) { - String model_type = api.supportsModernLabelPrinting - ? InvenTreeStockItem.MODEL_TYPE - : "stock"; - String item_key = api.supportsModernLabelPrinting ? "items" : "item"; - - // Clear the existing labels list - _labels = await getLabelTemplates(model_type, { - item_key: widget.item.pk.toString(), - }); - } - - if (mounted) { - setState(() { - labels = _labels; - }); - } } /// Delete the stock item from the database From 01ac0fc59e2c6ba58cbcbee5992aeade9ed621cf Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 22 Nov 2025 07:26:55 +1100 Subject: [PATCH 726/746] New Crowdin updates (#727) * New translations app_en.arb (German) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Greek) --- lib/l10n/de_DE/app_de_DE.arb | 4 +- lib/l10n/el_GR/app_el_GR.arb | 1050 +++++++++++++++++----------------- lib/l10n/vi_VN/app_vi_VN.arb | 4 +- 3 files changed, 529 insertions(+), 529 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index c92af22..e1c3fd6 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -936,7 +936,7 @@ "@serverNotConnected": {}, "serverNotSelected": "Server nicht ausgewählt", "@serverNotSelected": {}, - "shipment": "Sendung", + "shipment": "Lieferung", "@shipment": {}, "shipments": "Lieferungen", "@shipments": {}, @@ -956,7 +956,7 @@ "@shipmentEdit": {}, "shipmentReference": "Shipment Reference", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Lieferung versenden", "@shipmentSend": {}, "shipmentUncheck": "Uncheck Shipment", "@shipmentUncheck": {}, diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 243b8e5..e254be3 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -30,9 +30,9 @@ "@address": {}, "appAbout": "Σχετικά με το InvenTree", "@appAbout": {}, - "appCredits": "Πρόσθετες μονάδες εφαρμογής", + "appCredits": "Πιστώσεις Εφαρμογής", "@appCredits": {}, - "appDetails": "Λεπτομέρειες εφαρμογής", + "appDetails": "Λεπτομέρειες Εφαρμογής", "@appDetails": {}, "allocated": "Κατανεμημένο", "@allocated": {}, @@ -42,11 +42,11 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Τετράγωνο (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Κατανομή Αποθέματος", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Κατανεμημένο Απόθεμα", "@allocatedStock": {}, "appReleaseNotes": "Προβολή πληροφοριών έκδοσης εφαρμογής", "@appReleaseNotes": {}, @@ -54,9 +54,9 @@ "@appSettings": {}, "appSettingsDetails": "Διαμόρφωση ρυθμίσεων της εφαρμογής InvenTree", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Ανατεθειμένα σε εμένα", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Προβολή παραγγελιών που έχουν ανατεθεί σε εμένα", "@assignedToMeDetail": {}, "attachments": "Συνημμένα", "@attachments": {}, @@ -64,7 +64,7 @@ "@attachImage": { "description": "Attach an image" }, - "attachmentNone": "Δε βρέθηκαν συνημμένα", + "attachmentNone": "Δεν βρέθηκαν συνημμένα", "@attachmentNone": {}, "attachmentNoneDetail": "Δεν βρέθηκαν συνημμένα", "@attachmentNoneDetail": {}, @@ -84,17 +84,17 @@ "@barcodeAssign": {}, "barcodeAssignDetail": "Σαρώστε προσαρμοσμένο barcode για ανάθεση", "@barcodeAssignDetail": {}, - "barcodeAssigned": "Το Βarcode καταχωρήθηκε", + "barcodeAssigned": "Το barcode καταχωρήθηκε", "@barcodeAssigned": {}, "barcodeError": "Σφάλμα σάρωσης Barcode", "@barcodeError": {}, "barcodeInUse": "Το Barcode έχει ήδη ανατεθεί", "@barcodeInUse": {}, - "barcodeMissingHash": "Λείπουν δεδομένα κατακερματισμού Barcode από την απόκριση", + "barcodeMissingHash": "Λείπουν δεδομένα κατακερματισμού barcode από την απόκριση", "@barcodeMissingHash": {}, "barcodeNoMatch": "Δεν υπάρχει αντιστοιχία με το barcode", "@barcodeNoMatch": {}, - "barcodeNotAssigned": "Το Βarcode δεν καταχωρήθηκε", + "barcodeNotAssigned": "Το barcode δεν καταχωρήθηκε", "@barcodeNotAssigned": {}, "barcodeScanPart": "Σάρωση barcode εξαρτήματος", "@barcodeScanPart": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Παύση σάρωσης barcode", "@barodeScanPaused": {}, - "barcodeScanPause": "Πατήστε ή κρατήστε πατημένο για να κάνετε παύση σάρωσης", + "barcodeScanPause": "Πατήστε ή κρατήστε πατημένο για παύση σάρωσης", "@barcodeScanPause": {}, "barcodeScanAssign": "Σάρωση για εκχώρηση barcode", "@barcodeScanAssign": {}, @@ -110,1094 +110,1094 @@ "@barcodeScanController": {}, "barcodeScanControllerDetail": "Επιλέξτε πηγή εισόδου για σαρωτή barcode", "@barcodeScanControllerDetail": {}, - "barcodeScanDelay": "Barcode Scan Delay", + "barcodeScanDelay": "Καθυστέρηση Σάρωσης Barcode", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Καθυστέρηση μεταξύ σαρώσεων barcode", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "Σάρωση InvenTree barcode", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Σάρωση αντικειμένων σε αυτήν την τοποθεσία", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "Σάρωση τοποθεσίας αποθέματος", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Λειτουργία Μονής Σάρωσης", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Παύση του σαρωτή μετά από κάθε σάρωση", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "Σαρώθηκε στην τοποθεσία", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "Το αντικείμενο δεν σαρώθηκε", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "Σάρωση αντικειμένου αποθέματος", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Ήχοι Barcode", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "Αφαίρεση Ανάθεσης Barcode", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "Το barcode δεν αναγνωρίζεται", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "Κωδικός Παρτίδας", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "Κατάσταση Υλικών", "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Εμφάνιση Κατάστασης Υλικών", "@bomEnable": {}, - "build": "Build", + "build": "Κατασκευή", "@build": {}, - "building": "Building", + "building": "Κατασκευάζεται", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Αδυναμία ανοίγματος κάμερας", "@cameraCreationError": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Εσωτερική Κάμερα", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Χρήση εσωτερικής κάμερας για ανάγνωση barcodes", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "Ακύρωση", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Ακύρωση Παραγγελίας", "@cancelOrder": {}, - "category": "Category", + "category": "Κατηγορία", "@category": {}, "categoryCreate": "Νέα Κατηγορία", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "Δημιουργία νέας κατηγορίας εξαρτημάτων", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Η κατηγορία ενημερώθηκε", "@categoryUpdated": {}, - "company": "Company", + "company": "Εταιρεία", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Προσθήκη Εταιρείας", "@companyAdd": {}, - "companyEdit": "Edit Company", + "companyEdit": "Επεξεργασία Εταιρείας", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "Καμία εταιρεία δεν ταιριάζει με την αναζήτηση", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "Τα στοιχεία της εταιρείας ενημερώθηκαν", "@companyUpdated": {}, - "companies": "Companies", + "companies": "Εταιρείες", "@companies": {}, - "complete": "Complete", + "complete": "Ολοκλήρωση", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Ολοκλήρωση Παραγγελίας", "@completeOrder": {}, - "completionDate": "Completion Date", + "completionDate": "Ημερομηνία Ολοκλήρωσης", "@completionDate": {}, - "configureServer": "Configure server settings", + "configureServer": "Ρύθμιση παραμέτρων διακομιστή", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Επιβεβαίωση Μεταφοράς", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Επιβεβαίωση λεπτομερειών μεταφοράς κατά τη σάρωση barcodes", "@confirmScanDetail": {}, - "connectionRefused": "Connection Refused", + "connectionRefused": "Η σύνδεση απορρίφθηκε", "@connectionRefused": {}, - "count": "Count", + "count": "Μέτρηση", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "Καταμέτρηση Αποθέματος", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "Πιστώσεις", "@credits": {}, - "crop": "Crop", + "crop": "Περικοπή", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Περικοπή Εικόνας", "@cropImage": {}, - "customer": "Customer", + "customer": "Πελάτης", "@customer": {}, - "customers": "Customers", + "customers": "Πελάτες", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Αναφορά Πελάτη", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Κατεστραμμένο", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Συνδυασμός Χρωμάτων", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Επιλογή συνδυασμού χρωμάτων", "@colorSchemeDetail": {}, - "darkMode": "Dark Mode", + "darkMode": "Σκουρόχρωμη Λειτουργία", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Ενεργοποίηση σκοτεινής λειτουργίας", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "Διαγραφή", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Η διαγραφή απέτυχε", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτή την εικόνα;", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Διαγραφή Εικόνας", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Διαγραφή Εικόνας", "@deleteImage": {}, - "deletePart": "Delete Part", + "deletePart": "Διαγραφή Εξαρτήματος", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "Αφαίρεση αυτού του εξαρτήματος από τη βάση δεδομένων", "@deletePartDetail": {}, - "deleteSuccess": "Delete operation successful", + "deleteSuccess": "Η διαγραφή ολοκληρώθηκε με επιτυχία", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Ημερομηνία Παράδοσης", "@deliveryDate": {}, - "description": "Description", + "description": "Περιγραφή", "@description": {}, - "destination": "Destination", + "destination": "Προορισμός", "@destination": {}, - "destroyed": "Destroyed", + "destroyed": "Καταστράφηκε", "@destroyed": {}, - "details": "Details", + "details": "Λεπτομέρειες", "@details": { "description": "details" }, - "documentation": "Documentation", + "documentation": "Τεκμηρίωση", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Η λήψη ολοκληρώθηκε", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Σφάλμα κατά τη λήψη της εικόνας", "@downloadError": {}, - "downloading": "Downloading File", + "downloading": "Λήψη Αρχείου", "@downloading": {}, - "edit": "Edit", + "edit": "Επεξεργασία", "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Επεξεργασία Συνημμένου", "@editAttachment": {}, - "editCategory": "Edit Category", + "editCategory": "Επεξεργασία Κατηγορίας", "@editCategory": {}, - "editLocation": "Edit Location", + "editLocation": "Επεξεργασία Τοποθεσίας", "@editLocation": {}, - "editNotes": "Edit Notes", + "editNotes": "Επεξεργασία Σημειώσεων", "@editNotes": {}, - "editParameter": "Edit Parameter", + "editParameter": "Επεξεργασία Παραμέτρου", "@editParameter": {}, - "editPart": "Edit Part", + "editPart": "Επεξεργασία Εξαρτήματος", "@editPart": { "description": "edit part" }, - "editItem": "Edit Stock Item", + "editItem": "Επεξεργασία Αντικειμένου Αποθέματος", "@editItem": {}, - "editLineItem": "Edit Line Item", + "editLineItem": "Επεξεργασία Γραμμής", "@editLineItem": {}, "email": "Email", "@email": {}, - "enterPassword": "Enter password", + "enterPassword": "Εισαγάγετε τον κωδικό", "@enterPassword": {}, - "enterUsername": "Enter username", + "enterUsername": "Εισαγάγετε το όνομα χρήστη", "@enterUsername": {}, - "error": "Error", + "error": "Σφάλμα", "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "Σφάλμα κατά τη δημιουργία εγγραφής", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "Σφάλμα κατά τη διαγραφή εγγραφής", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "Λεπτομέρειες Σφάλματος", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "Σφάλμα κατά την ανάκτηση δεδομένων από τον διακομιστή", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Σφάλμα κατά το αίτημα ρόλων χρήστη", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Σφάλμα κατά το αίτημα πληροφοριών plugin", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "Αναφορά Σφαλμάτων", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "Ανέβασμα Αναφορών Σφαλμάτων", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Ανώνυμη αποστολή αναφορών σφαλμάτων και καταγραφών κρασαρισμάτων", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Ημερομηνία Λήξης", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Έχει λήξει", "@expiryExpired": {}, - "expiryStale": "Stale", + "expiryStale": "Παλαιό", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Επιπλέον Γραμμή", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Επιπλέον Γραμμές", "@extraLineItems": {}, - "feedback": "Feedback", + "feedback": "Ανατροφοδότηση", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Σφάλμα κατά την αποστολή ανατροφοδότησης", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Η ανατροφοδότηση στάλθηκε", "@feedbackSuccess": {}, - "filterActive": "Active", + "filterActive": "Ενεργά", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Εμφάνιση ενεργών εξαρτημάτων", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Συναρμολογημένα", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Εμφάνιση συναρμολογημένων εξαρτημάτων", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Εξάρτημα", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Εμφάνιση εξαρτημάτων", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Εξωτερικά", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Εμφάνιση αποθέματος σε εξωτερικές τοποθεσίες", "@filterExternalDetail": {}, - "filterInStock": "In Stock", + "filterInStock": "Σε Απόθεμα", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Εμφάνιση εξαρτημάτων που έχουν απόθεμα", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Με Σειριακό Αριθμό", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Εμφάνιση αντικειμένων αποθέματος με σειριακό αριθμό", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Πρότυπο", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Εμφάνιση πρότυπων εξαρτημάτων", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Ιχνηλάσιμο", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Εμφάνιση ιχνηλάσιμων εξαρτημάτων", "@filterTrackableDetail": {}, - "filterVirtual": "Virtual", + "filterVirtual": "Εικονικά", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Εμφάνιση εικονικών εξαρτημάτων", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Επιλογές Φιλτραρίσματος", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Εξαίρεση Μορφοποίησης", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "Εξαίρεση μορφής JSON", "@formatExceptionJson": {}, - "formError": "Form Error", + "formError": "Σφάλμα Φόρμας", "@formError": {}, - "history": "History", + "history": "Ιστορικό", "@history": { "description": "history" }, - "home": "Home", + "home": "Αρχική", "@home": {}, - "homeScreen": "Home Screen", + "homeScreen": "Αρχική Οθόνη", "@homeScreen": {}, - "homeScreenSettings": "Configure home screen settings", + "homeScreenSettings": "Ρύθμιση αρχικής οθόνης", "@homeScreenSettings": {}, - "homeShowPo": "Show Purchase Orders", + "homeShowPo": "Εμφάνιση Παραγγελιών Αγοράς", "@homeShowPo": {}, - "homeShowPoDescription": "Show purchase order button on home screen", + "homeShowPoDescription": "Εμφάνιση κουμπιού παραγγελιών αγοράς στην αρχική οθόνη", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Εμφάνιση Αποστολών", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Εμφάνιση εκκρεμών αποστολών στην αρχική οθόνη", "@homeShowShipmentsDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Εμφάνιση Παραγγελιών Πώλησης", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Εμφάνιση κουμπιού παραγγελιών πώλησης στην αρχική οθόνη", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Εγγεγραμμένα Εξαρτήματα", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Εμφάνιση εγγεγραμμένων εξαρτημάτων στην αρχική οθόνη", "@homeShowSubscsribedDescription": {}, - "homeShowSuppliers": "Show Suppliers", + "homeShowSuppliers": "Εμφάνιση Προμηθευτών", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Εμφάνιση κουμπιού προμηθευτών στην αρχική οθόνη", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "Εμφάνιση Κατασκευαστών", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Εμφάνιση κουμπιού κατασκευαστών στην αρχική οθόνη", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Εμφάνιση Πελατών", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Εμφάνιση κουμπιού πελατών στην αρχική οθόνη", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Αποτυχία μεταφόρτωσης εικόνας", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Η εικόνα μεταφορτώθηκε", "@imageUploadSuccess": {}, - "inactive": "Inactive", + "inactive": "Ανενεργό", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Αυτή η εταιρεία έχει επισημανθεί ως ανενεργή", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "Αυτό το εξάρτημα έχει επισημανθεί ως ανενεργό", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "Συμπερίληψη Υποκατηγοριών", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "Εμφάνιση αποτελεσμάτων από υποκατηγορίες", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "Συμπερίληψη Υποτοποθεσιών", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Εμφάνιση αποτελεσμάτων από υποτοποθεσίες", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "Ελλιπείς λεπτομέρειες προφίλ", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "Εσωτερικός Κωδικός Εξαρτήματος", "@internalPartNumber": {}, - "info": "Info", + "info": "Πληροφορίες", "@info": {}, - "inProduction": "In Production", + "inProduction": "Σε Παραγωγή", "@inProduction": {}, - "inProductionDetail": "This stock item is in production", + "inProductionDetail": "Αυτό το αντικείμενο αποθέματος βρίσκεται σε παραγωγή", "@inProductionDetail": {}, - "internalPart": "Internal Part", + "internalPart": "Εσωτερικό Εξάρτημα", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "Μη έγκυρο hostname", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "Το παρεχόμενο hostname δεν είναι έγκυρο", "@invalidHostDetails": {}, - "invalidPart": "Invalid Part", + "invalidPart": "Μη έγκυρο Εξάρτημα", "@invalidPart": {}, - "invalidPartCategory": "Invalid Part Category", + "invalidPartCategory": "Μη έγκυρη Κατηγορία Εξαρτήματος", "@invalidPartCategory": {}, - "invalidStockLocation": "Invalid Stock Location", + "invalidStockLocation": "Μη έγκυρη Τοποθεσία Αποθέματος", "@invalidStockLocation": {}, - "invalidStockItem": "Invalid Stock Item", + "invalidStockItem": "Μη έγκυρο Αντικείμενο Αποθέματος", "@invalidStockItem": {}, - "invalidSupplierPart": "Invalid Supplier Part", + "invalidSupplierPart": "Μη έγκυρο Εξάρτημα Προμηθευτή", "@invalidSupplierPart": {}, - "invalidUsernamePassword": "Invalid username / password combination", + "invalidUsernamePassword": "Μη έγκυρος συνδυασμός ονόματος χρήστη / κωδικού", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Τιμολόγιο", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Αριθμός Τιμολογίου", "@invoiceNumber": {}, - "issue": "Issue", + "issue": "Έκδοση", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Ημερομηνία Έκδοσης", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Έκδοση Παραγγελίας", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "Το αντικείμενο βρίσκεται ήδη στην τοποθεσία", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Το αντικείμενο αφαιρέθηκε", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Το αντικείμενο ενημερώθηκε", "@itemUpdated": {}, - "keywords": "Keywords", + "keywords": "Λέξεις-Κλειδιά", "@keywords": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Εκτύπωση Ετικετών", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Ενεργοποίηση εκτύπωσης ετικετών", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Πρότυπο Ετικέτας", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Επιλογή Προτύπου Ετικέτας", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Επιλογή Εκτυπωτή Ετικετών", "@labelSelectPrinter": {}, - "language": "Language", + "language": "Γλώσσα", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Προεπιλεγμένη γλώσσα συστήματος", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Επιλογή Γλώσσας", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Τελευταία Απογραφή", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "Τελευταία Ενημέρωση", "@lastUpdated": {}, - "level": "Level", + "level": "Επίπεδο", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Προσθήκη Γραμμής", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Γραμμή", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "Γραμμές", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Η γραμμή ενημερώθηκε", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Εντοπισμός αντικειμένου αποθέματος", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Εντοπισμός τοποθεσίας αποθέματος", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Νέα Τοποθεσία", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "Δημιουργία νέας τοποθεσίας αποθέματος", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Προεπιλεγμένη Τοποθεσία", "@locationDefault": {}, - "locationNotSet": "No location specified", + "locationNotSet": "Δεν έχει οριστεί τοποθεσία", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "Η τοποθεσία ενημερώθηκε", "@locationUpdated": {}, - "login": "Login", + "login": "Σύνδεση", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Εισαγάγετε τα στοιχεία σύνδεσης", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Το όνομα χρήστη και ο κωδικός δεν αποθηκεύονται τοπικά", "@loginEnterDetails": {}, - "link": "Link", + "link": "Σύνδεσμος", "@link": {}, - "lost": "Lost", + "lost": "Χαμένο", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Κωδικός Κατασκευαστή", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Επεξεργασία Κωδικού Κατασκευαστή", "@manufacturerPartEdit": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Αριθμός Κωδικού Κατασκευαστή", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Κατασκευαστής", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "Κατασκευαστές", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Ελλιπή Δεδομένα", "@missingData": {}, - "name": "Name", + "name": "Όνομα", "@name": {}, - "no": "No", + "no": "Όχι", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "Μ/Δ", "@notApplicable": {}, - "notConnected": "Not Connected", + "notConnected": "Δεν υπάρχει σύνδεση", "@notConnected": {}, - "notes": "Notes", + "notes": "Σημειώσεις", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Ειδοποιήσεις", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Καμία μη αναγνωσμένη ειδοποίηση", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Χωρίς απόκριση από τον διακομιστή", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Κανένα αποτέλεσμα", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Δεν υπάρχει διαθέσιμη εικόνα", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Δεν υπάρχουν διαθέσιμες τιμές", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Δεν βρέθηκαν δεδομένα τιμολόγησης για αυτό το εξάρτημα", "@noPricingDataFound": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Δεν υπάρχουν υποκατηγορίες", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Δεν υπάρχουν διαθέσιμες υποκατηγορίες", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Μη έγκυρος αριθμός", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "Σε Παραγγελία", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Αντικείμενα που βρίσκονται σε παραγγελία", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Προσανατολισμός Οθόνης", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Προσανατολισμός οθόνης (απαιτεί επανεκκίνηση)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Οριζόντια", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Κάθετη", "@orientationPortrait": {}, - "orientationSystem": "System", + "orientationSystem": "Σύστημα", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Εκκρεμείς", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Εμφάνιση εκκρεμών παραγγελιών", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Καθυστερημένες", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Εμφάνιση καθυστερημένων παραγγελιών", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Συσκευασία", "@packaging": {}, - "packageName": "Package Name", + "packageName": "Όνομα Πακέτου", "@packageName": {}, - "parameters": "Parameters", + "parameters": "Παράμετροι", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Εμφάνιση παραμέτρων εξαρτήματος", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "Γονικό", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Γονική Κατηγορία", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "Γονική Τοποθεσία", "@parentLocation": {}, - "part": "Part", + "part": "Εξάρτημα", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Νέο Εξάρτημα", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Δημιουργία νέου εξαρτήματος σε αυτή την κατηγορία", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Το εξάρτημα ενημερώθηκε", "@partEdited": {}, - "parts": "Parts", + "parts": "Εξαρτήματα", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Το εξάρτημα δεν έχει χαρακτηριστεί ως διαθέσιμο προς πώληση", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "Δεν υπάρχουν εξαρτήματα", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "Κανένα εξάρτημα δεν ταιριάζει με την αναζήτηση", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Τιμολόγηση Εξαρτήματος", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Εμφάνιση πληροφοριών τιμολόγησης εξαρτήματος", "@pricingSettingDetail": {}, - "partSettings": "Part Settings", + "partSettings": "Ρυθμίσεις Εξαρτημάτων", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "Εγγεγραμμένα Εξαρτήματα", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "Δεν υπάρχουν εγγεγραμμένα εξαρτήματα", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "Προμηθευτές Εξαρτήματος", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "Κατηγορία Εξαρτήματος", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "Κατηγορία εξαρτήματος ανώτερου επιπέδου", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "Κατηγορίες Εξαρτημάτων", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Λεπτομέρειες Εξαρτήματος", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Σημειώσεις Εξαρτήματος", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Απόθεμα Εξαρτήματος", "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "Κωδικός", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "Ο κωδικός δεν μπορεί να είναι κενός", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Σε αναμονή", "@pending": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Ο λογαριασμός σας δεν έχει τα απαραίτητα δικαιώματα για αυτή την ενέργεια", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Απαιτούνται Δικαιώματα", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Τηλέφωνο", "@phone": {}, - "printLabel": "Print Label", + "printLabel": "Εκτύπωση Ετικέτας", "@printLabel": {}, - "plugin": "Plugin", + "plugin": "Πρόσθετο", "@plugin": {}, - "pluginPrinter": "Printer", + "pluginPrinter": "Εκτυπωτής", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "Υποστήριξη Plugin ενεργοποιημένη", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Ο διακομιστής υποστηρίζει προσαρμοσμένα plugins", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "Η εκτύπωση ετικέτας απέτυχε", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "Η ετικέτα στάλθηκε στον εκτυπωτή", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Προφίλ", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "Προσθήκη Προφίλ Διακομιστή", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "Σύνδεση με Διακομιστή", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "Επεξεργασία Προφίλ Διακομιστή", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "Διαγραφή Προφίλ Διακομιστή", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Αποσύνδεση Προφίλ", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "Όνομα Προφίλ", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "Δεν υπάρχουν διαθέσιμα προφίλ", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "Δεν επιλέχθηκε προφίλ", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "Επιλογή Διακομιστή InvenTree", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "Επιλέξτε διακομιστή ή δημιουργήστε νέο προφίλ", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "Πατήστε για δημιουργία ή επιλογή προφίλ", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Κωδικός Έργου", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Επιβεβαίωση Δεδομένων Σάρωσης", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Επιβεβαίωση λεπτομερειών κατά τη σάρωση αντικειμένων", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Ενεργοποίηση Παραγγελιών Αγοράς", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Ενεργοποίηση λειτουργιών παραγγελίας αγοράς", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Συντόμευση Κάμερας", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Ενεργοποίηση συντόμευσης μεταφόρτωσης εικόνων στην οθόνη παραγγελίας", "@purchaseOrderShowCameraDetail": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "Παραγγελία Αγοράς", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Νέα Παραγγελία Αγοράς", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "Επεξεργασία Παραγγελίας Αγοράς", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Ρυθμίσεις Παραγγελιών Αγοράς", "@purchaseOrderSettings": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "Παραγγελίες Αγοράς", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "Η παραγγελία αγοράς ενημερώθηκε", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "Τιμή Αγοράς", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Ποσότητα", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Διαθέσιμη Ποσότητα", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Η ποσότητα είναι κενή", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Η ποσότητα δεν είναι έγκυρη", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Η ποσότητα πρέπει να είναι θετική", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Εισαγάγετε αναζήτηση", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "Δεν υπάρχουν αποτελέσματα για την αναζήτηση", "@queryNoResults": {}, - "received": "Received", + "received": "Παραλήφθηκε", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Εμφάνιση παραληφθέντων αντικειμένων", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Παραλαβή Αντικειμένου", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "Παραληφθέν Αντικείμενο Αποθέματος", "@receivedItem": {}, - "reference": "Reference", + "reference": "Αναφορά", "@reference": {}, - "refresh": "Refresh", + "refresh": "Ανανέωση", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Περιστροφή 90° δεξιόστροφα", "@rotateClockwise": {}, - "refreshing": "Refreshing", + "refreshing": "Γίνεται ανανέωση", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Απορρίφθηκε", "@rejected": {}, - "releaseNotes": "Release Notes", + "releaseNotes": "Σημειώσεις Έκδοσης", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Αφαίρεση", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "Αφαίρεση Αποθέματος", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Αναφορά Σφάλματος", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "Υποβολή αναφοράς σφάλματος (απαιτεί λογαριασμό GitHub)", "@reportBugDescription": {}, - "responsible": "Responsible", + "responsible": "Υπεύθυνος", "@responsible": {}, - "results": "Results", + "results": "Αποτελέσματα", "@results": {}, - "request": "Request", + "request": "Αίτημα", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "Η αίτηση απέτυχε", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "Η αίτηση ολοκληρώθηκε με επιτυχία", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "Ανάκτηση Δεδομένων", "@requestingData": {}, - "required": "Required", + "required": "Απαιτείται", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "Μη Έγκυρο Αίτημα", "@response400": {}, - "response401": "Unauthorized", + "response401": "Μη Εξουσιοδοτημένο", "@response401": {}, - "response403": "Permission Denied", + "response403": "Δεν Επιτρέπεται", "@response403": {}, - "response404": "Resource Not Found", + "response404": "Ο Πόρος Δεν Βρέθηκε", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "Μη Επιτρεπτή Μέθοδος", "@response405": {}, - "response429": "Too Many Requests", + "response429": "Πάρα Πολλά Αιτήματα", "@response429": {}, - "response500": "Internal Server Error", + "response500": "Εσωτερικό Σφάλμα Διακομιστή", "@response500": {}, - "response501": "Not Implemented", + "response501": "Μη Υλοποιημένο", "@response501": {}, - "response502": "Bad Gateway", + "response502": "Εσφαλμένη Πύλη (Bad Gateway)", "@response502": {}, - "response503": "Service Unavailable", + "response503": "Υπηρεσία Μη Διαθέσιμη", "@response503": {}, - "response504": "Gateway Timeout", + "response504": "Λήξη Χρόνου Πύλης (Gateway Timeout)", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "Η Έκδοση HTTP Δεν Υποστηρίζεται", "@response505": {}, - "responseData": "Response data", + "responseData": "Δεδομένα Απόκρισης", "@responseData": {}, - "responseInvalid": "Invalid Response Code", + "responseInvalid": "Μη έγκυρος κωδικός απόκρισης", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "Άγνωστη Απόκριση", "@responseUnknown": {}, - "result": "Result", + "result": "Αποτέλεσμα", "@result": { "description": "" }, - "returned": "Returned", + "returned": "Επιστράφηκε", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Παραγγελία Πώλησης", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "Παραγγελίες Πώλησης", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Ενεργοποίηση Παραγγελιών Πώλησης", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Ενεργοποίηση λειτουργιών παραγγελιών πώλησης", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Συντόμευση Κάμερας", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Ενεργοποίηση συντόμευσης μεταφόρτωσης εικόνας στην οθόνη παραγγελίας πώλησης", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Ρυθμίσεις Παραγγελιών Πώλησης", "@salesOrderSettings": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Νέα Παραγγελία Πώλησης", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Επεξεργασία Παραγγελίας Πώλησης", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Η παραγγελία πώλησης ενημερώθηκε", "@salesOrderUpdated": {}, - "save": "Save", + "save": "Αποθήκευση", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "Σάρωση Barcode", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Σάρωση barcode εξαρτήματος προμηθευτή", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "Σάρωση σε Τοποθεσία", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Σαρώστε αυτό το αντικείμενο στην τοποθεσία", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Εξωτερικός Σαρωτής", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Χρήση εξωτερικού σαρωτή για ανάγνωση barcodes (wedge mode)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Σάρωση Παραληφθέντων Εξαρτημάτων", "@scanReceivedParts": {}, - "search": "Search", + "search": "Αναζήτηση", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Γίνεται αναζήτηση", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "Αναζήτηση τοποθεσίας", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "Αναζήτηση εξαρτημάτων", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "Αναζήτηση αποθέματος", "@searchStock": {}, - "select": "Select", + "select": "Επιλογή", "@select": {}, - "selectFile": "Select File", + "selectFile": "Επιλογή Αρχείου", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Επιλογή Εικόνας", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Επιλογή τοποθεσίας", "@selectLocation": {}, - "send": "Send", + "send": "Αποστολή", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Σειριακός Αριθμός", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Σειριακοί Αριθμοί", "@serialNumbers": {}, - "server": "Server", + "server": "Διακομιστής", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Διεύθυνση Διακομιστή", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Απαιτούμενη Έκδοση API", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Έκδοση API Διακομιστή", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Σφάλμα Πιστοποίησης", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Σφάλμα Πιστοποιητικού", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Το πιστοποιητικό HTTPS του διακομιστή δεν είναι έγκυρο", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Συνδεδεμένο με τον Διακομιστή", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Σύνδεση με τον διακομιστή", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Αδυναμία σύνδεσης με τον διακομιστή", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Το πεδίο διακομιστή δεν μπορεί να είναι κενό", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Σφάλμα Διακομιστή", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Λεπτομέρειες Διακομιστή", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "Η απόκριση του διακομιστή δεν περιέχει τα απαιτούμενα δεδομένα", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Παλιά Έκδοση Διακομιστή", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Ρυθμίσεις Διακομιστή", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Ο διακομιστής πρέπει να ξεκινά με http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Ρυθμίσεις", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Περίπτωση Διακομιστή", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Δεν υπάρχει σύνδεση με τον διακομιστή", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Δεν έχει επιλεγεί διακομιστής", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Αποστολή", "@shipment": {}, - "shipments": "Shipments", + "shipments": "Αποστολές", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Εκκρεμείς Αποστολές", "@shipmentsPending": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Προσθήκη Αποστολής", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Έλεγχος Αποστολής", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Σημειώστε την αποστολή ως ελεγμένη", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Η Αποστολή Ελέγχθηκε", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Ημερομηνία Αποστολής", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Επεξεργασία Αποστολής", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Αναφορά Αποστολής", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Αποστολή", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Αναίρεση Ελέγχου Αποστολής", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Σημειώστε την αποστολή ως μη ελεγμένη", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Η Αποστολή Ενημερώθηκε", "@shipmentUpdated": {}, - "shipped": "Shipped", + "shipped": "Απεστάλη", "@shipped": {}, "sku": "SKU", "@sku": {}, - "sounds": "Sounds", + "sounds": "Ήχοι", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Αναπαραγωγή ήχου κατά τη δράση barcode", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Αναπαραγωγή ήχου σε σφάλμα διακομιστή", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Ημερομηνία Έναρξης", "@startDate": {}, - "status": "Status", + "status": "Κατάσταση", "@status": {}, - "statusCode": "Status Code", + "statusCode": "Κωδικός Κατάστασης", "@statusCode": {}, - "stock": "Stock", + "stock": "Απόθεμα", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Τρέχουσα διαθέσιμη ποσότητα αποθέματος", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "Αντικείμενο Αποθέματος", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "Αντικείμενα Αποθέματος", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "Νέο Αντικείμενο Αποθέματος", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "Δημιουργία νέου αντικειμένου αποθέματος σε αυτή την τοποθεσία", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "Διαγραφή Αντικειμένου Αποθέματος", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το αντικείμενο αποθέματος;", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "Δεν ήταν δυνατή η διαγραφή του αντικειμένου αποθέματος", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "Το αντικείμενο αποθέματος διαγράφηκε", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "Ιστορικό Αποθέματος", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Εμφάνιση ιστορικών πληροφοριών παρακολούθησης αποθέματος", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "Το αντικείμενο αποθέματος μεταφέρθηκε", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "Το αντικείμενο αποθέματος ενημερώθηκε", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "Δεν υπάρχουν διαθέσιμα αντικείμενα αποθέματος", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "Σημειώσεις Αντικειμένου Αποθέματος", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "Το αντικείμενο αποθέματος ενημερώθηκε", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "Η ενημέρωση του αντικειμένου απέτυχε", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "Τοποθεσία Αποθέματος", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "Τοποθεσίες Αποθέματος", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "Τοποθεσία αποθέματος ανώτερου επιπέδου", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Χρήση Αποκλειστικού HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Επιβολή αυστηρού ελέγχου πιστοποιητικών HTTPS", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "Υποκατηγορία", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "Υποκατηγορίες", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "Υποτοποθεσία", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "Υποτοποθεσίες", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "Δεν υπάρχουν υποτοποθεσίες", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "Δεν υπάρχουν διαθέσιμες υποτοποθεσίες", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "Υποβολή Ανατροφοδότησης", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "Προμηθευμένα Εξαρτήματα", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "Προμηθευτής", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Κωδικός Προμηθευτή", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Επεξεργασία Κωδικού Προμηθευτή", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Αριθμός Κωδικού Προμηθευτή", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Ο κωδικός προμηθευτή ενημερώθηκε", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Κωδικοί Προμηθευτή", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "Προμηθευτές", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "Αναφορά Προμηθευτή", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Αλλαγή Κάμερας", "@switchCamera": {}, - "takePicture": "Take Picture", + "takePicture": "Λήψη Φωτογραφίας", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "Ημερομηνία Στόχος", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "Γονικό Πρότυπο Εξάρτημα", "@templatePart": {}, - "testName": "Test Name", + "testName": "Όνομα Δοκιμής", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "Επιτυχία ή αποτυχία δοκιμής", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "Απαιτούμενες Δοκιμές", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "Αποτελέσματα Δοκιμών", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Εμφάνιση αποτελεσμάτων δοκιμών αντικειμένου αποθέματος", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "Προσθήκη Αποτελέσματος Δοκιμής", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "Δεν υπάρχουν αποτελέσματα δοκιμών", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "Δεν υπάρχουν διαθέσιμα αποτελέσματα δοκιμών", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "Σφάλμα κατά την αποστολή αποτελέσματος δοκιμής", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "Το αποτέλεσμα δοκιμής μεταφορτώθηκε", "@testResultUploadPass": {}, - "timeout": "Timeout", + "timeout": "Λήξη Χρόνου", "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Εναλλαγή Φακού", "@toggleTorch": {}, - "tokenError": "Token Error", + "tokenError": "Σφάλμα Διακριτικού", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "Λείπει Διακριτικό", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "Το διακριτικό πρόσβασης λείπει από την απόκριση", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Συνολική Τιμή", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Αριθμός Παρακολούθησης", "@trackingNumber": {}, - "transfer": "Transfer", + "transfer": "Μεταφορά", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "Μεταφορά Αποθέματος", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "Μεταφορά του αντικειμένου σε διαφορετική τοποθεσία", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Μεταφορά Τοποθεσίας Αποθέματος", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Μεταφορά αυτής της τοποθεσίας αποθέματος σε άλλη", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "Μετάφραση", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "Βοηθήστε στη μετάφραση της εφαρμογής InvenTree", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Μη Διαθέσιμο", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Το αντικείμενο δεν είναι διαθέσιμο", "@unavailableDetail": {}, - "unitPrice": "Unit Price", + "unitPrice": "Τιμή Μονάδας", "@unitPrice": {}, - "units": "Units", + "units": "Μονάδες", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "Άγνωστη Απόκριση", "@unknownResponse": {}, - "upload": "Upload", + "upload": "Μεταφόρτωση", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "Η μεταφόρτωση του αρχείου απέτυχε", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "Το αρχείο μεταφορτώθηκε", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Μεταφόρτωση Εικόνας", "@uploadImage": {}, - "usedIn": "Used In", + "usedIn": "Χρησιμοποιείται Σε", "@usedIn": {}, - "usedInDetails": "Assemblies which require this part", + "usedInDetails": "Συναρμολογήσεις που απαιτούν αυτό το εξάρτημα", "@usedInDetails": {}, - "username": "Username", + "username": "Όνομα Χρήστη", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "Το όνομα χρήστη δεν μπορεί να είναι κενό", "@usernameEmpty": {}, - "value": "Value", + "value": "Τιμή", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "Η τιμή δεν μπορεί να είναι κενή", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "Η τιμή απαιτείται", "@valueRequired": {}, - "variants": "Variants", + "variants": "Παραλλαγές", "@variants": {}, - "version": "Version", + "version": "Έκδοση", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "Προβολή Κωδικού Προμηθευτή", "@viewSupplierPart": {}, - "website": "Website", + "website": "Ιστοσελίδα", "@website": {}, - "yes": "Yes", + "yes": "Ναι", "@yes": {}, - "price": "Price", + "price": "Τιμή", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Εύρος Τιμών", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Ελάχιστη Τιμή Override", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Μέγιστη Τιμή Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Τιμή Πώλησης", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Ιστορικό Πωλήσεων", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Τιμολόγηση Προμηθευτή", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Κόστος BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Εσωτερικό Κόστος", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Κόστος Παραλλαγής", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Συνολική Τιμολόγηση", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Price Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Νόμισμα", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Τμήματα Τιμής", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index fd0d271..7accb1a 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -282,7 +282,7 @@ "@editItem": {}, "editLineItem": "Sửa dòng sản phẩm", "@editLineItem": {}, - "email": "Email", + "email": "Địa chỉ email", "@email": {}, "enterPassword": "Nhập mật khẩu", "@enterPassword": {}, @@ -468,7 +468,7 @@ "@itemInLocation": {}, "itemDeleted": "Hàng hóa đã bị xóa", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Mẫu đã được cập nhật", "@itemUpdated": {}, "keywords": "Từ khóa", "@keywords": {}, From 3ee2192c92a12a46f9ec7e9644e6c5120d48669b Mon Sep 17 00:00:00 2001 From: Alexander Leisentritt Date: Fri, 21 Nov 2025 21:27:26 +0100 Subject: [PATCH 727/746] Update barcode scan pause instruction text (#728) --- lib/l10n/app_en.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9ea177e..905be19 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -148,7 +148,7 @@ "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", From 6e02d1da975ea754a79bf54b93fc20d74548ff16 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 23 Nov 2025 09:08:14 +1100 Subject: [PATCH 728/746] New Crowdin updates (#731) * New translations app_en.arb (Romanian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (German) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Romanian) --- lib/l10n/ar_SA/app_ar_SA.arb | 6 +++++- lib/l10n/bg_BG/app_bg_BG.arb | 6 +++++- lib/l10n/cs_CZ/app_cs_CZ.arb | 6 +++++- lib/l10n/da_DK/app_da_DK.arb | 6 +++++- lib/l10n/de_DE/app_de_DE.arb | 6 +++++- lib/l10n/el_GR/app_el_GR.arb | 6 +++++- lib/l10n/es_ES/app_es_ES.arb | 6 +++++- lib/l10n/es_MX/app_es_MX.arb | 6 +++++- lib/l10n/et_EE/app_et_EE.arb | 6 +++++- lib/l10n/fa_IR/app_fa_IR.arb | 6 +++++- lib/l10n/fi_FI/app_fi_FI.arb | 6 +++++- lib/l10n/fr_FR/app_fr_FR.arb | 6 +++++- lib/l10n/he_IL/app_he_IL.arb | 6 +++++- lib/l10n/hi_IN/app_hi_IN.arb | 6 +++++- lib/l10n/hu_HU/app_hu_HU.arb | 6 +++++- lib/l10n/id_ID/app_id_ID.arb | 6 +++++- lib/l10n/it_IT/app_it_IT.arb | 6 +++++- lib/l10n/ja_JP/app_ja_JP.arb | 6 +++++- lib/l10n/ko_KR/app_ko_KR.arb | 6 +++++- lib/l10n/lt_LT/app_lt_LT.arb | 6 +++++- lib/l10n/lv_LV/app_lv_LV.arb | 6 +++++- lib/l10n/nl_NL/app_nl_NL.arb | 6 +++++- lib/l10n/no_NO/app_no_NO.arb | 6 +++++- lib/l10n/pl_PL/app_pl_PL.arb | 6 +++++- lib/l10n/pt_BR/app_pt_BR.arb | 6 +++++- lib/l10n/pt_PT/app_pt_PT.arb | 6 +++++- lib/l10n/ro_RO/app_ro_RO.arb | 10 +++++++--- lib/l10n/ru_RU/app_ru_RU.arb | 6 +++++- lib/l10n/sk_SK/app_sk_SK.arb | 6 +++++- lib/l10n/sl_SI/app_sl_SI.arb | 6 +++++- lib/l10n/sr_CS/app_sr_CS.arb | 6 +++++- lib/l10n/sv_SE/app_sv_SE.arb | 6 +++++- lib/l10n/th_TH/app_th_TH.arb | 6 +++++- lib/l10n/tr_TR/app_tr_TR.arb | 6 +++++- lib/l10n/uk_UA/app_uk_UA.arb | 8 +++++++- lib/l10n/vi_VN/app_vi_VN.arb | 6 +++++- lib/l10n/zh_CN/app_zh_CN.arb | 6 +++++- lib/l10n/zh_TW/app_zh_TW.arb | 6 +++++- 38 files changed, 194 insertions(+), 40 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index f865457..1f8c94e 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 57bd141..01a6299 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 2855022..51eb367 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Skenování čárových kódů pozastaveno", "@barodeScanPaused": {}, - "barcodeScanPause": "Klepnutím nebo podržením pozastavíte skenování", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Klíčová slova", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Tisk štítku", "@labelPrinting": {}, "labelPrintingDetail": "Povolit tisk štítku", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 41f578c..697846b 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Stregkode skanning på pause", "@barodeScanPaused": {}, - "barcodeScanPause": "Tryk eller hold nede for at pause i skanningen", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan for at tildele stregkode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index e1c3fd6..dc075ef 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode-Scannen angehalten", "@barodeScanPaused": {}, - "barcodeScanPause": "Tippen oder halten um das Scannen anzuhalten", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scannen um Barcode zuzuweisen", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Schlüsselwörter", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Etikettendruck", "@labelPrinting": {}, "labelPrintingDetail": "Etikettendruck aktivieren", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index e254be3..436d4f7 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Παύση σάρωσης barcode", "@barodeScanPaused": {}, - "barcodeScanPause": "Πατήστε ή κρατήστε πατημένο για παύση σάρωσης", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Σάρωση για εκχώρηση barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Λέξεις-Κλειδιά", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Εκτύπωση Ετικετών", "@labelPrinting": {}, "labelPrintingDetail": "Ενεργοποίηση εκτύπωσης ετικετών", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index 98f8eb6..ef947d4 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Escaneo de código de barras en pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Toque o mantenga pulsado para pausar el escaneo", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Palabras claves", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Impresión de etiquetas", "@labelPrinting": {}, "labelPrintingDetail": "Habilitar impresión de etiquetas", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 87e27b3..4f0ec84 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Escaneo de código de barras en pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Toque o mantenga pulsado para pausar el escaneo", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Escanear para asignar código de barras", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Palabras claves", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Impresión de etiquetas", "@labelPrinting": {}, "labelPrintingDetail": "Habilitar impresión de etiquetas", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index b887671..b6847d8 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Märksõnad", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 2dc9b6c..02358b0 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "اسکن بارکد متوقف شد", "@barodeScanPaused": {}, - "barcodeScanPause": "برای توقف اسکن ضربه بزنید یا نگه دارید", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "برای اختصاص بارکد اسکن کنید", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "کلمات کلیدی", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "چاپ لیبل", "@labelPrinting": {}, "labelPrintingDetail": "چاپ لیبل را انتخاب کنید", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index b125042..26ba3e3 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Avainsanat", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 9762e8a..929c962 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Scan de code-barres en pause", "@barodeScanPaused": {}, - "barcodeScanPause": "Appuyez ou maintenez pour mettre en pause le scan", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scanner pour attribuer un code-barres", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Mots clés", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Impression étiquettes", "@labelPrinting": {}, "labelPrintingDetail": "Activer l'impression d'étiquettes", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index ef1c0b9..2273108 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "סריקת ברקוד מושהית", "@barodeScanPaused": {}, - "barcodeScanPause": "בקש או החזק כדי להשהות את הסריקה", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "סרוק כדי להקצות ברקוד", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "מילות מפתח", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "הדפסת תווית", "@labelPrinting": {}, "labelPrintingDetail": "אפשר הדפסת תווית", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 9bdf06b..c0c3cbb 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 1837a91..3286dfa 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Vonalkód olvasás megállítva", "@barodeScanPaused": {}, - "barcodeScanPause": "Kattints vagy tartsd lenyomva a beolvasás felfüggesztéséhez", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Kulcsszavak", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Címke nyomtatás", "@labelPrinting": {}, "labelPrintingDetail": "Címke nyomtatás engedélyezése", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 205c20e..2346557 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Pemindaian barcode dijeda", "@barodeScanPaused": {}, - "barcodeScanPause": "Ketuk atau tahan untuk menjeda pemindaian", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Pindai untuk menetapkan barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Kata Kunci", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 81a74a8..db6286a 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Scansione codice a barre in pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Premi oppure tieni premuti per mettere in pausa la scansione", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scansiona per assegnare codice a barre", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Parole Chiave", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Etichetta in stampa", "@labelPrinting": {}, "labelPrintingDetail": "Abilita stampa etichette", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 0489fcf..88722da 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "バーコードスキャンを一時停止中", "@barodeScanPaused": {}, - "barcodeScanPause": "スキャンを一時停止するにはタップまたはホールドします", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "スキャンしてバーコードを割り当てます", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "キーワード", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "ラベル印刷", "@labelPrinting": {}, "labelPrintingDetail": "ラベル印刷を有効化", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index ba576bf..390183d 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "키워드", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index abb7b83..dbb63e9 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index acb13d5..064ec61 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 83d40f0..d8eab7d 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scannen gepauzeerd", "@barodeScanPaused": {}, - "barcodeScanPause": "Tik of houd om scannen te pauzeren", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Trefwoorden", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label afdrukken", "@labelPrinting": {}, "labelPrintingDetail": "Label afdrukken inschakelen", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index 3c6ee3d..d9e3196 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Skanning satt på pause", "@barodeScanPaused": {}, - "barcodeScanPause": "Trykk eller hold for å pause skanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Skann for å tildele strekkode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Nøkkelord", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Etikettutskrift", "@labelPrinting": {}, "labelPrintingDetail": "Aktiver etikettutskrift", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 2743161..ac7a6c2 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Skanowanie kodów kreskowych wstrzymane", "@barodeScanPaused": {}, - "barcodeScanPause": "Dotknij lub przytrzymaj, aby wstrzymać skanowanie", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Słowa kluczowe", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Drukowanie etykiet", "@labelPrinting": {}, "labelPrintingDetail": "Włącz drukowanie etykiet", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 43a7cfb..991ea1d 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Escaneamento de código de barras pausado", "@barodeScanPaused": {}, - "barcodeScanPause": "Toque ou segure para pausar o escaneamento", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Palavras chave", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Impressão de Etiqueta", "@labelPrinting": {}, "labelPrintingDetail": "Habilitar Impressão de Etiqueta", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index c0b8366..4fc3583 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Verificação do código de barras pausada", "@barodeScanPaused": {}, - "barcodeScanPause": "Toque ou segure para pausar a verificação", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Escaneie para atribuir código de barras", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Palavras-chave", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Impressão de etiqueta", "@labelPrinting": {}, "labelPrintingDetail": "Ativar impressão de etiquetas", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index ca8982e..ff74b98 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Scanare cod de bare întreruptă", "@barodeScanPaused": {}, - "barcodeScanPause": "Atingeți sau țineți apăsat pentru a întrerupe scanarea", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scanează pentru a atribui cod de bare", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Cuvinte cheie", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Printare etichete", "@labelPrinting": {}, "labelPrintingDetail": "Permite tipărirea etichetei", @@ -1150,9 +1154,9 @@ "@usedIn": {}, "usedInDetails": "Assemblies which require this part", "@usedInDetails": {}, - "username": "Username", + "username": "Nume utilizator", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "Numele de utilizator nu poate fi gol", "@usernameEmpty": {}, "value": "Value", "@value": { diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 3d31ce2..fa9f15b 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Сканирование штрих-кода приостановлено", "@barodeScanPaused": {}, - "barcodeScanPause": "Нажмите или удерживайте, чтобы приостановить сканирование", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Сканировать для присвоения штрих-кода", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Ключевые слова", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Печать этикеток", "@labelPrinting": {}, "labelPrintingDetail": "Включить печать этикеток", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index e0eabe3..ef1ac29 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 746c845..1414c2c 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scanning paused", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 0e2d400..e48713c 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Pauzirano skeniranje bar kodova", "@barodeScanPaused": {}, - "barcodeScanPause": "Pritisni ili drži za pauzu skeniranja", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Skeniraj za dodelu bar koda", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Ključne reči", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Štampanje natpisa", "@labelPrinting": {}, "labelPrintingDetail": "Omogući štampanje natpisa", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 8d7c456..ae837a4 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Streckkodsskanning pausad", "@barodeScanPaused": {}, - "barcodeScanPause": "Tryck eller håll ned för att pausa skanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Skanna för att tilldela streckkod", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Nyckelord", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Utskrift av etiketter", "@labelPrinting": {}, "labelPrintingDetail": "Aktivera etikettutskrift", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index d37c3c3..af0ca84 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "หยุดการสแกนบาร์โค้ด", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap or hold to pause scanning", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan to assign barcode", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Keywords", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Label Printing", "@labelPrinting": {}, "labelPrintingDetail": "Enable label printing", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 3bfed5e..dfffe0e 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barkod tarama duraklatıldı", "@barodeScanPaused": {}, - "barcodeScanPause": "Taramayı duraklatmak için dokunun veya basılı tutun", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Etiket Yazdırma", "@labelPrinting": {}, "labelPrintingDetail": "Etiket yazdırmayı aktifleştir", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index c10396c..5eb5c48 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Сканування штрих-кодів призупинено", "@barodeScanPaused": {}, - "barcodeScanPause": "Торкніться або утримуйте, щоб призупинити сканування", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Сканувати щоб призначити штрих-код", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Ключові слова", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "Друк Ярликів", "@labelPrinting": {}, "labelPrintingDetail": "Увімкнути друк ярликів", @@ -510,6 +514,8 @@ "@locationCreate": {}, "locationCreateDetail": "Створити нове розташування на складі", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, "locationNotSet": "Розташування не вказано", "@locationNotSet": {}, "locationUpdated": "Розташування запасів оновлено", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 7accb1a..77777c0 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Quét mã vạch đã bị dừng", "@barodeScanPaused": {}, - "barcodeScanPause": "Nhấp hoặc giữ để dừng quét", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Quét để gán mã vạch", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "Từ khóa", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "In nhãn mã vạch", "@labelPrinting": {}, "labelPrintingDetail": "Bật in nhãn tem", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 2826146..edb54e2 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "条形码扫描已暂停", "@barodeScanPaused": {}, - "barcodeScanPause": "点击或按住以暂停扫描", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "扫描以分配条形码", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "关键词", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "打印标签", "@labelPrinting": {}, "labelPrintingDetail": "启用标签打印功能", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 849aefe..f0ba7e5 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "條碼掃描已暫停", "@barodeScanPaused": {}, - "barcodeScanPause": "點擊或按住以暫停掃描", + "barcodeScanPause": "Tap to pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "掃描以設置條碼", "@barcodeScanAssign": {}, @@ -472,6 +472,10 @@ "@itemUpdated": {}, "keywords": "關鍵字", "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, "labelPrinting": "標籤印製", "@labelPrinting": {}, "labelPrintingDetail": "啓用標籤打印功能", From 7283c07b76ba980dfb3f842b3f04a2bc90f288c3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 23 Nov 2025 09:18:49 +1100 Subject: [PATCH 729/746] Form success fix (#733) * Fix order of operations on form success - Pop widget before running callback * Update release notes --- assets/release_notes.md | 5 +++++ lib/api_form.dart | 2 +- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index f97832a..17fd96d 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.21.1 - November 2025 +--- + +- Fixed app freeze bug after form submission + ### 0.21.0 - November 2025 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index ea0bc79..429c71d 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1174,8 +1174,8 @@ class APIFormWidgetState extends State { Map submittedData, Map responseData, ) async { - widget.onSuccess?.call(responseData); Navigator.pop(context); + widget.onSuccess?.call(responseData); } List _buildForm() { diff --git a/pubspec.yaml b/pubspec.yaml index a445035..bf7987f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.21.0+106 +version: 0.21.1+107 environment: sdk: ^3.8.1 @@ -40,7 +40,7 @@ dependencies: path: ^1.9.0 path_provider: ^2.1.5 # Local file storage sembast: ^3.6.0 # NoSQL data storage - sentry_flutter: 8.14.2 # Error reporting + sentry_flutter: 8.14.2 # Error reporting url_launcher: ^6.3.1 # Open link in system browser wakelock_plus: ^1.3.2 # Prevent device from sleeping From 0f31638bdc1e15f68d75e77d0bf54485e36f6d21 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 24 Nov 2025 09:10:59 +1100 Subject: [PATCH 730/746] [CI] Build Fixes (#734) * precache for ios build * build android on push too * try without cache --- .github/workflows/android.yaml | 5 ++++- .github/workflows/ios.yaml | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 9f30b48..3147927 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -3,6 +3,9 @@ name: Android on: + pull_request: + branches: + - master push: branches: - master @@ -30,7 +33,7 @@ jobs: with: flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} - cache: true + cache: false cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 724fa57..cdd51ed 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -3,6 +3,9 @@ name: iOS on: + pull_request: + branches: + - master push: branches: - master @@ -33,7 +36,7 @@ jobs: with: flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} - cache: true + cache: false cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" @@ -49,6 +52,7 @@ jobs: dart pub global activate fvm fvm install fvm flutter pub get + fvm flutter precache --ios cd ios pod repo update pod install From bb10117f010baf9563d6d30618be2a11851e4905 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 28 Nov 2025 20:01:55 +1100 Subject: [PATCH 731/746] New Crowdin updates (#736) * New translations app_en.arb (Czech) * New translations app_en.arb (Russian) --- lib/l10n/cs_CZ/app_cs_CZ.arb | 6 ++-- lib/l10n/ru_RU/app_ru_RU.arb | 54 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 51eb367..ccd9d94 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Skenování čárových kódů pozastaveno", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Kliknutím pozastavíte skenování", "@barcodeScanPause": {}, "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", "@barcodeScanAssign": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Klíčová slova", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Ovladač pro popisky", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Vyberte ovladač pro tiskárnu štítků", "@labelSelectDriver": {}, "labelPrinting": "Tisk štítku", "@labelPrinting": {}, diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index fa9f15b..8eb938f 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Выделить запас", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Зарезервированные остатки", "@allocatedStock": {}, "appReleaseNotes": "Показать заметки о выпуске приложения", "@appReleaseNotes": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Сканирование штрих-кода приостановлено", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Нажмите, чтобы приостановить сканирование", "@barcodeScanPause": {}, "barcodeScanAssign": "Сканировать для присвоения штрих-кода", "@barcodeScanAssign": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Удаление успешно завершено", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Дата доставки", "@deliveryDate": {}, "description": "Описание", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Показывать кнопку заказа на главном экране", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Показать отгрузки", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Показывать ожидающие отгрузки на главном экране", "@homeShowShipmentsDescription": {}, "homeShowSo": "Показать заказы на продажу", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Счет", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Номер счета", "@invoiceNumber": {}, "issue": "Оформить", "@issue": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Ключевые слова", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Драйвер принтера этикеток", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Выберите драйвер принтера этикеток", "@labelSelectDriver": {}, "labelPrinting": "Печать этикеток", "@labelPrinting": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Создать новое расположение склада", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Расположение по умолчанию", "@locationDefault": {}, "locationNotSet": "Не указано месторасположение", "@locationNotSet": {}, @@ -544,9 +544,9 @@ "@missingData": {}, "name": "Название", "@name": {}, - "no": "No", + "no": "Нет", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "Н/Д", "@notApplicable": {}, "notConnected": "Соединение не установлено", "@notConnected": {}, @@ -660,7 +660,7 @@ "@password": {}, "passwordEmpty": "Пароль не может быть пустым", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "В обработке", "@pending": {}, "permissionAccountDenied": "Ваш аккаунт не имеет разрешения на выполнение этого действия", "@permissionAccountDenied": {}, @@ -940,33 +940,33 @@ "@serverNotConnected": {}, "serverNotSelected": "Сервер не выбран", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Отгрузка", "@shipment": {}, "shipments": "Поставки", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Ожидающие отгрузки", "@shipmentsPending": {}, "shipmentAdd": "Новое Отправление", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Проверить отгрузку", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Отметить этот груз как проверенный", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Отгрузка проверена", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Дата отгрузки", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Редактировать отгрузку", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Ссылка на отгрузку", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Отправить отгрузку", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Снять отметку с отгрузки", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Отметить этот груз как непроверенный", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Отгрузка обновлена", "@shipmentUpdated": {}, "shipped": "Отгружено", "@shipped": {}, @@ -1112,7 +1112,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Общая стоимость", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Номер отслеживания", "@trackingNumber": {}, "transfer": "Перемещение", "@transfer": { @@ -1174,7 +1174,7 @@ "@viewSupplierPart": {}, "website": "Сайт", "@website": {}, - "yes": "Yes", + "yes": "Да", "@yes": {}, "price": "Цена", "@price": {}, From 346b1a150ffc24cddd9131b2d944f6994aa5c472 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 28 Nov 2025 23:53:10 +1100 Subject: [PATCH 732/746] Attachments refactor (#737) * refactor attachment code into its own file * Add getters * Remove custom models for each type of attachment * Refactor existing widgets * Fix double camera open bug * Remove dead code * Remove unused imports * Refactor common code * format * Update release notes --- assets/release_notes.md | 5 + lib/inventree/attachment.dart | 176 ++++++++++++++++++++ lib/inventree/company.dart | 25 --- lib/inventree/model.dart | 170 ------------------- lib/inventree/part.dart | 25 --- lib/inventree/purchase_order.dart | 25 --- lib/inventree/sales_order.dart | 47 +----- lib/inventree/stock.dart | 25 --- lib/widget/attachment_widget.dart | 92 ++++++---- lib/widget/company/company_detail.dart | 49 +++--- lib/widget/order/purchase_order_detail.dart | 58 +++---- lib/widget/order/sales_order_detail.dart | 58 +++---- lib/widget/order/so_shipment_detail.dart | 49 +++--- lib/widget/part/part_detail.dart | 47 +++--- lib/widget/stock/stock_detail.dart | 49 +++--- 15 files changed, 381 insertions(+), 519 deletions(-) create mode 100644 lib/inventree/attachment.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 17fd96d..cbde004 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### x.xx.x - Month Year +--- + +- Fixes bug which launched camera twice when uploading an attachment + ### 0.21.1 - November 2025 --- diff --git a/lib/inventree/attachment.dart b/lib/inventree/attachment.dart new file mode 100644 index 0000000..3f1b913 --- /dev/null +++ b/lib/inventree/attachment.dart @@ -0,0 +1,176 @@ +import "dart:io"; + +import "package:flutter/cupertino.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/sentry.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/fields.dart"; +import "package:inventree/widget/snacks.dart"; +import "package:path/path.dart" as path; + +class InvenTreeAttachment extends InvenTreeModel { + // Class representing an "attachment" file + InvenTreeAttachment() : super(); + + InvenTreeAttachment.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeAttachment createFromJson(Map json) => + InvenTreeAttachment.fromJson(json); + + @override + String get URL => "attachment/"; + + @override + Map> formFields() { + Map> fields = {"link": {}, "comment": {}}; + + if (!hasLink) { + fields.remove("link"); + } + + return fields; + } + + // The model type of the instance this attachment is associated with + String get modelType => getString("model_type"); + + // The ID of the instance this attachment is associated with + int get modelId => getInt("model_id"); + + String get attachment => getString("attachment"); + + bool get hasAttachment => attachment.isNotEmpty; + + // Return the filename of the attachment + String get filename { + return attachment.split("/").last; + } + + IconData get icon { + String fn = filename.toLowerCase(); + + if (fn.endsWith(".pdf")) { + return TablerIcons.file_type_pdf; + } else if (fn.endsWith(".csv")) { + return TablerIcons.file_type_csv; + } else if (fn.endsWith(".doc") || fn.endsWith(".docx")) { + return TablerIcons.file_type_doc; + } else if (fn.endsWith(".xls") || fn.endsWith(".xlsx")) { + return TablerIcons.file_type_xls; + } + + // Image formats + final List img_formats = [".png", ".jpg", ".gif", ".bmp", ".svg"]; + + for (String fmt in img_formats) { + if (fn.endsWith(fmt)) { + return TablerIcons.file_type_jpg; + } + } + + return TablerIcons.file; + } + + String get comment => getString("comment"); + + DateTime? get uploadDate { + if (jsondata.containsKey("upload_date")) { + return DateTime.tryParse((jsondata["upload_date"] ?? "") as String); + } else { + return null; + } + } + + // Return a count of how many attachments exist against the specified model ID + Future countAttachments(String modelType, int modelId) async { + Map filters = {}; + + if (!api.supportsModernAttachments) { + return 0; + } + + filters["model_type"] = modelType; + filters["model_id"] = modelId.toString(); + + return count(filters: filters); + } + + Future uploadAttachment( + File attachment, + String modelType, + int modelId, { + String comment = "", + Map fields = const {}, + }) async { + // Ensure that the correct reference field is set + Map data = Map.from(fields); + + String url = URL; + + if (comment.isNotEmpty) { + data["comment"] = comment; + } + + data["model_type"] = modelType; + data["model_id"] = modelId.toString(); + + final APIResponse response = await InvenTreeAPI().uploadFile( + url, + attachment, + method: "POST", + name: "attachment", + fields: data, + ); + + return response.successful(); + } + + Future uploadImage( + String modelType, + int modelId, { + String prefix = "InvenTree", + }) async { + bool result = false; + + await FilePickerDialog.pickImageFromCamera().then((File? file) { + if (file != null) { + String dir = path.dirname(file.path); + String ext = path.extension(file.path); + String now = DateTime.now().toIso8601String().replaceAll(":", "-"); + + // Rename the file with a unique name + String filename = "${dir}/${prefix}_image_${now}${ext}"; + + try { + return file.rename(filename).then((File renamed) { + return uploadAttachment(renamed, modelType, modelId).then(( + success, + ) { + result = success; + showSnackIcon( + result ? L10().imageUploadSuccess : L10().imageUploadFailure, + success: result, + ); + }); + }); + } catch (error, stackTrace) { + sentryReportError("uploadImage", error, stackTrace); + showSnackIcon(L10().imageUploadFailure, success: false); + } + } + }); + + return result; + } + + /* + * Download this attachment file + */ + Future downloadAttachment() async { + await InvenTreeAPI().downloadFile(attachment); + } +} diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index a2a3f21..90ed77c 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -111,31 +111,6 @@ class InvenTreeCompany extends InvenTreeModel { InvenTreeCompany.fromJson(json); } -/* - * Class representing an attachment file against a Company object - */ -class InvenTreeCompanyAttachment extends InvenTreeAttachment { - InvenTreeCompanyAttachment() : super(); - - InvenTreeCompanyAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - String get REFERENCE_FIELD => "company"; - - @override - String get REF_MODEL_TYPE => "company"; - - @override - String get URL => InvenTreeAPI().supportsModernAttachments - ? "attachment/" - : "company/attachment/"; - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreeCompanyAttachment.fromJson(json); -} - /* * The InvenTreeSupplierPart class represents the SupplierPart model in the InvenTree database */ diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index e08a053..f87b2de 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -1,5 +1,4 @@ import "dart:async"; -import "dart:io"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter/material.dart"; @@ -15,7 +14,6 @@ import "package:inventree/helpers.dart"; import "package:inventree/inventree/sentry.dart"; import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/fields.dart"; // Paginated response object class InvenTreePageResponse { @@ -934,171 +932,3 @@ class InvenTreeUserSetting extends InvenTreeGlobalSetting { @override String get URL => "settings/user/"; } - -class InvenTreeAttachment extends InvenTreeModel { - // Class representing an "attachment" file - InvenTreeAttachment() : super(); - - InvenTreeAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - String get URL => "attachment/"; - - @override - Map> formFields() { - Map> fields = {"link": {}, "comment": {}}; - - if (!hasLink) { - fields.remove("link"); - } - - return fields; - } - - // Override this reference field for any subclasses - // Note: This is used for the *legacy* attachment API - String get REFERENCE_FIELD => ""; - - // Override this reference field for any subclasses - // Note: This is used for the *modern* attachment API - String get REF_MODEL_TYPE => ""; - - String get attachment => getString("attachment"); - - bool get hasAttachment => attachment.isNotEmpty; - - // Return the filename of the attachment - String get filename { - return attachment.split("/").last; - } - - IconData get icon { - String fn = filename.toLowerCase(); - - if (fn.endsWith(".pdf")) { - return TablerIcons.file_type_pdf; - } else if (fn.endsWith(".csv")) { - return TablerIcons.file_type_csv; - } else if (fn.endsWith(".doc") || fn.endsWith(".docx")) { - return TablerIcons.file_type_doc; - } else if (fn.endsWith(".xls") || fn.endsWith(".xlsx")) { - return TablerIcons.file_type_xls; - } - - // Image formats - final List img_formats = [".png", ".jpg", ".gif", ".bmp", ".svg"]; - - for (String fmt in img_formats) { - if (fn.endsWith(fmt)) { - return TablerIcons.file_type_jpg; - } - } - - return TablerIcons.file; - } - - String get comment => getString("comment"); - - DateTime? get uploadDate { - if (jsondata.containsKey("upload_date")) { - return DateTime.tryParse((jsondata["upload_date"] ?? "") as String); - } else { - return null; - } - } - - // Return a count of how many attachments exist against the specified model ID - Future countAttachments(int modelId) { - Map filters = {}; - - if (InvenTreeAPI().supportsModernAttachments) { - filters["model_type"] = REF_MODEL_TYPE; - filters["model_id"] = modelId.toString(); - } else { - filters[REFERENCE_FIELD] = modelId.toString(); - } - - return count(filters: filters); - } - - Future uploadAttachment( - File attachment, - int modelId, { - String comment = "", - Map fields = const {}, - }) async { - // Ensure that the correct reference field is set - Map data = Map.from(fields); - - String url = URL; - - if (comment.isNotEmpty) { - data["comment"] = comment; - } - - if (InvenTreeAPI().supportsModernAttachments) { - url = "attachment/"; - data["model_id"] = modelId.toString(); - data["model_type"] = REF_MODEL_TYPE; - } else { - if (REFERENCE_FIELD.isEmpty) { - sentryReportMessage( - "uploadAttachment called with empty 'REFERENCE_FIELD'", - ); - return false; - } - - data[REFERENCE_FIELD] = modelId.toString(); - } - - final APIResponse response = await InvenTreeAPI().uploadFile( - url, - attachment, - method: "POST", - name: "attachment", - fields: data, - ); - - return response.successful(); - } - - Future uploadImage(int modelId, {String prefix = "InvenTree"}) async { - bool result = false; - - await FilePickerDialog.pickImageFromCamera().then((File? file) { - if (file != null) { - String dir = path.dirname(file.path); - String ext = path.extension(file.path); - String now = DateTime.now().toIso8601String().replaceAll(":", "-"); - - // Rename the file with a unique name - String filename = "${dir}/${prefix}_image_${now}${ext}"; - - try { - file.rename(filename).then((File renamed) { - uploadAttachment(renamed, modelId).then((success) { - result = success; - showSnackIcon( - result ? L10().imageUploadSuccess : L10().imageUploadFailure, - success: result, - ); - }); - }); - } catch (error, stackTrace) { - sentryReportError("uploadImage", error, stackTrace); - showSnackIcon(L10().imageUploadFailure, success: false); - } - } - }); - - return result; - } - - /* - * Download this attachment file - */ - Future downloadAttachment() async { - await InvenTreeAPI().downloadFile(attachment); - } -} diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 23e306c..fc52399 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -547,28 +547,3 @@ class InvenTreePartPricing extends InvenTreeModel { double? get saleHistoryMin => getDoubleOrNull("sale_history_min"); double? get saleHistoryMax => getDoubleOrNull("sale_history_max"); } - -/* - * Class representing an attachment file against a Part object - */ -class InvenTreePartAttachment extends InvenTreeAttachment { - InvenTreePartAttachment() : super(); - - InvenTreePartAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - String get REFERENCE_FIELD => "part"; - - @override - String get REF_MODEL_TYPE => "part"; - - @override - String get URL => InvenTreeAPI().supportsModernAttachments - ? "attachment/" - : "part/attachment/"; - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreePartAttachment.fromJson(json); -} diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 59874dc..65af361 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -336,28 +336,3 @@ class InvenTreePOExtraLineItem extends InvenTreeExtraLineItem { ); } } - -/* - * Class representing an attachment file against a PurchaseOrder object - */ -class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { - InvenTreePurchaseOrderAttachment() : super(); - - InvenTreePurchaseOrderAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - String get REFERENCE_FIELD => "order"; - - @override - String get REF_MODEL_TYPE => "purchaseorder"; - - @override - String get URL => InvenTreeAPI().supportsModernAttachments - ? "attachment/" - : "order/po/attachment/"; - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreePurchaseOrderAttachment.fromJson(json); -} diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 8b661f4..77c3469 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -334,7 +334,7 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { /* * Class representing an allocation of stock against a SalesOrderShipment */ -class InvenTreeSalesOrderAllocation extends InvenTreeAttachment { +class InvenTreeSalesOrderAllocation extends InvenTreeModel { InvenTreeSalesOrderAllocation() : super(); InvenTreeSalesOrderAllocation.fromJson(Map json) @@ -428,48 +428,3 @@ class InvenTreeSalesOrderAllocation extends InvenTreeAttachment { } } } - -/* - * Class representing an attachment file against a SalesOrder object - */ -class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { - InvenTreeSalesOrderAttachment() : super(); - - InvenTreeSalesOrderAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreeSalesOrderAttachment.fromJson(json); - - @override - String get REFERENCE_FIELD => "order"; - - @override - String get REF_MODEL_TYPE => "salesorder"; - - @override - String get URL => InvenTreeAPI().supportsModernAttachments - ? "attachment/" - : "order/so/attachment/"; -} - -class InvenTreeSalesOrderShipmentAttachment extends InvenTreeAttachment { - InvenTreeSalesOrderShipmentAttachment() : super(); - - InvenTreeSalesOrderShipmentAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreeSalesOrderShipmentAttachment.fromJson(json); - - @override - String get REFERENCE_FIELD => "shipment"; - - @override - String get REF_MODEL_TYPE => "salesordershipment"; - - @override - String get URL => "attachment/"; -} diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 1a45e73..4b5bf3b 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -575,31 +575,6 @@ class InvenTreeStockItem extends InvenTreeModel { } } -/* - * Class representing an attachment file against a StockItem object - */ -class InvenTreeStockItemAttachment extends InvenTreeAttachment { - InvenTreeStockItemAttachment() : super(); - - InvenTreeStockItemAttachment.fromJson(Map json) - : super.fromJson(json); - - @override - String get REFERENCE_FIELD => "stock_item"; - - @override - String get REF_MODEL_TYPE => "stockitem"; - - @override - String get URL => InvenTreeAPI().supportsModernAttachments - ? "attachment/" - : "stock/attachment/"; - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreeStockItemAttachment.fromJson(json); -} - class InvenTreeStockLocation extends InvenTreeModel { InvenTreeStockLocation() : super(); diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index b66462f..721909d 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -2,14 +2,13 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api.dart"; +import "package:inventree/inventree/attachment.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:one_context/one_context.dart"; -import "package:inventree/api.dart"; import "package:inventree/l10.dart"; import "package:inventree/app_colors.dart"; - -import "package:inventree/inventree/model.dart"; - import "package:inventree/widget/fields.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; @@ -23,13 +22,13 @@ import "package:inventree/widget/refreshable_state.dart"; */ class AttachmentWidget extends StatefulWidget { const AttachmentWidget( - this.attachmentClass, + this.modelType, this.modelId, this.imagePrefix, this.hasUploadPermission, ) : super(); - final InvenTreeAttachment attachmentClass; + final String modelType; final int modelId; final bool hasUploadPermission; final String imagePrefix; @@ -54,15 +53,15 @@ class _AttachmentWidgetState extends RefreshableState { IconButton( icon: Icon(TablerIcons.camera), onPressed: () async { - widget.attachmentClass.uploadImage( - widget.modelId, - prefix: widget.imagePrefix, - ); - FilePickerDialog.pickImageFromCamera().then((File? file) { - upload(context, file).then((_) { - refresh(context); - }); - }); + InvenTreeAttachment() + .uploadImage( + widget.modelType, + widget.modelId, + prefix: widget.imagePrefix, + ) + .then((_) { + refresh(context); + }); }, ), IconButton( @@ -83,8 +82,9 @@ class _AttachmentWidgetState extends RefreshableState { showLoadingOverlay(); - final bool result = await widget.attachmentClass.uploadAttachment( + final bool result = await InvenTreeAttachment().uploadAttachment( file, + widget.modelType, widget.modelId, ); @@ -168,25 +168,24 @@ class _AttachmentWidgetState extends RefreshableState { Future request(BuildContext context) async { Map filters = {}; - if (InvenTreeAPI().supportsModernAttachments) { - filters["model_type"] = widget.attachmentClass.REF_MODEL_TYPE; - filters["model_id"] = widget.modelId.toString(); - } else { - filters[widget.attachmentClass.REFERENCE_FIELD] = widget.modelId - .toString(); - } + filters["model_type"] = widget.modelType; + filters["model_id"] = widget.modelId.toString(); - await widget.attachmentClass.list(filters: filters).then((var results) { - attachments.clear(); + List _attachments = []; + InvenTreeAttachment().list(filters: filters).then((var results) { for (var result in results) { if (result is InvenTreeAttachment) { - attachments.add(result); + _attachments.add(result); } } - }); - setState(() {}); + if (mounted) { + setState(() { + attachments = _attachments; + }); + } + }); } @override @@ -240,3 +239,40 @@ class _AttachmentWidgetState extends RefreshableState { return tiles; } } + +/* + * Return a ListTile to display attachments for the specified model + */ +ListTile? ShowAttachmentsItem( + BuildContext context, + String modelType, + int modelId, + String imagePrefix, + int attachmentCount, + bool hasUploadPermission, +) { + if (!InvenTreeAPI().supportsModernAttachments) { + return null; + } + + return ListTile( + title: Text(L10().attachments), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: LinkIcon( + text: attachmentCount > 0 ? attachmentCount.toString() : null, + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + modelType, + modelId, + imagePrefix, + hasUploadPermission, + ), + ), + ); + }, + ); +} diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 5d06e58..8947104 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -184,15 +185,15 @@ class _CompanyDetailState extends RefreshableState { } }); - InvenTreeCompanyAttachment().countAttachments(widget.company.pk).then(( - value, - ) { - if (mounted) { - setState(() { - attachmentCount = value; + InvenTreeAttachment() + .countAttachments(InvenTreeCompany.MODEL_TYPE, widget.company.pk) + .then((value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } }); - } - }); } Future editCompany(BuildContext context) async { @@ -393,29 +394,19 @@ class _CompanyDetailState extends RefreshableState { ); } - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeCompanyAttachment(), - widget.company.pk, - widget.company.name, - InvenTreeCompany().canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeCompany.MODEL_TYPE, + widget.company.pk, + widget.company.name, + attachmentCount, + widget.company.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } } diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 4201cd3..0829e06 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -7,6 +7,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/purchase_order.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; @@ -174,8 +175,12 @@ class _PurchaseOrderDetailState /// Upload an image against the current PurchaseOrder Future _uploadImage(BuildContext context) async { - InvenTreePurchaseOrderAttachment() - .uploadImage(widget.order.pk, prefix: widget.order.reference) + InvenTreeAttachment() + .uploadImage( + InvenTreePurchaseOrder.MODEL_TYPE, + widget.order.pk, + prefix: widget.order.reference, + ) .then((result) => refresh(context)); } @@ -295,15 +300,15 @@ class _PurchaseOrderDetailState } } - InvenTreePurchaseOrderAttachment().countAttachments(widget.order.pk).then(( - int value, - ) { - if (mounted) { - setState(() { - attachmentCount = value; + InvenTreeAttachment() + .countAttachments(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } }); - } - }); if (api.supportsPurchaseOrderDestination && widget.order.destinationId > 0) { @@ -565,30 +570,19 @@ class _PurchaseOrderDetailState ), ); - // Attachments - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreePurchaseOrderAttachment(), - widget.order.pk, - widget.order.reference, - widget.order.canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreePurchaseOrder.MODEL_TYPE, + widget.order.pk, + widget.order.reference, + attachmentCount, + widget.order.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index ec18561..30692f2 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -3,6 +3,7 @@ import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/sales_order.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/preferences.dart"; @@ -108,8 +109,12 @@ class _SalesOrderDetailState extends RefreshableState { /// Upload an image for this order Future _uploadImage(BuildContext context) async { - InvenTreeSalesOrderAttachment() - .uploadImage(widget.order.pk, prefix: widget.order.reference) + InvenTreeAttachment() + .uploadImage( + InvenTreeSalesOrder.MODEL_TYPE, + widget.order.pk, + prefix: widget.order.reference, + ) .then((result) => refresh(context)); } @@ -266,15 +271,15 @@ class _SalesOrderDetailState extends RefreshableState { true, ); - InvenTreeSalesOrderAttachment().countAttachments(widget.order.pk).then(( - int value, - ) { - if (mounted) { - setState(() { - attachmentCount = value; + InvenTreeAttachment() + .countAttachments(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } }); - } - }); // Count number of "extra line items" against this order InvenTreeSOExtraLineItem() @@ -492,30 +497,19 @@ class _SalesOrderDetailState extends RefreshableState { ), ); - // Attachments - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeSalesOrderAttachment(), - widget.order.pk, - widget.order.reference, - widget.order.canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeSalesOrder.MODEL_TYPE, + widget.order.pk, + widget.order.reference, + attachmentCount, + widget.order.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } diff --git a/lib/widget/order/so_shipment_detail.dart b/lib/widget/order/so_shipment_detail.dart index 9116fb7..34984df 100644 --- a/lib/widget/order/so_shipment_detail.dart +++ b/lib/widget/order/so_shipment_detail.dart @@ -8,6 +8,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; import "package:inventree/app_colors.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; @@ -91,8 +92,11 @@ class _SOShipmentDetailWidgetState }); } - InvenTreeSalesOrderShipmentAttachment() - .countAttachments(widget.shipment.pk) + InvenTreeAttachment() + .countAttachments( + InvenTreeSalesOrderShipment.MODEL_TYPE, + widget.shipment.pk, + ) .then((int value) { if (mounted) { setState(() { @@ -104,8 +108,12 @@ class _SOShipmentDetailWidgetState /// Upload an image for this shipment Future _uploadImage(BuildContext context) async { - InvenTreeSalesOrderShipmentAttachment() - .uploadImage(widget.shipment.pk, prefix: widget.shipment.reference) + InvenTreeAttachment() + .uploadImage( + InvenTreeSalesOrderShipment.MODEL_TYPE, + widget.shipment.pk, + prefix: widget.shipment.reference, + ) .then((result) => refresh(context)); } @@ -339,30 +347,19 @@ class _SOShipmentDetailWidgetState ), ); - // Attachments - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeSalesOrderShipmentAttachment(), - widget.shipment.pk, - widget.shipment.reference, - widget.shipment.canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeSalesOrderShipment.MODEL_TYPE, + widget.shipment.pk, + widget.shipment.reference, + attachmentCount, + widget.shipment.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 98cf173..30b697c 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -4,6 +4,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; @@ -212,13 +213,15 @@ class _PartDisplayState extends RefreshableState { } // Request the number of attachments - InvenTreePartAttachment().countAttachments(part.pk).then((int value) { - if (mounted) { - setState(() { - attachmentCount = value; + InvenTreeAttachment() + .countAttachments(InvenTreePart.MODEL_TYPE, part.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } }); - } - }); // If show pricing information? if (showPricing) { @@ -596,29 +599,19 @@ class _PartDisplayState extends RefreshableState { ), ); - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreePartAttachment(), - part.pk, - L10().part, - part.canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreePart.MODEL_TYPE, + part.pk, + L10().part, + attachmentCount, + part.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index db295ca..282a962 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -7,6 +7,7 @@ import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/stock.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -255,15 +256,15 @@ class _StockItemDisplayState extends RefreshableState { } // Request the number of attachments - InvenTreeStockItemAttachment().countAttachments(widget.item.pk).then(( - int value, - ) { - if (mounted) { - setState(() { - attachmentCount = value; + InvenTreeAttachment() + .countAttachments(InvenTreeStockItem.MODEL_TYPE, widget.item.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } }); - } - }); // Request SalesOrder information if (widget.item.hasSalesOrder) { @@ -837,29 +838,19 @@ class _StockItemDisplayState extends RefreshableState { ), ); - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: LinkIcon( - text: attachmentCount > 0 ? attachmentCount.toString() : null, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeStockItemAttachment(), - widget.item.pk, - L10().stockItem, - widget.item.canEdit, - ), - ), - ); - }, - ), + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeStockItem.MODEL_TYPE, + widget.item.pk, + L10().stockItem, + attachmentCount, + widget.item.canEdit, ); + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } } From 864c3eea76c2303e285b043e8a58c363b32a6d6d Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 4 Dec 2025 18:34:05 +1100 Subject: [PATCH 733/746] Parameters refactor (#738) * refactor attachment code into its own file * Add getters * Remove custom models for each type of attachment * Refactor existing widgets * Fix double camera open bug * Add check for modern parameter API * Add generic parameter type * Remove old code * Remove dead code * Refactor previous widget * Remove unused imports * Refactor common code * format * Update release notes * Helper func to render parameters list tile * Display parameters on part page * parameters for company * Supplier more model types: - ManufacturerPart - SupplierPart - PurchaseOrder - SalesOrder * dart format * Fix image prefix * Remove unused import * Adjust API version --- lib/api.dart | 4 + lib/inventree/parameter.dart | 77 ++++++++++++++++++ lib/inventree/part.dart | 62 --------------- lib/preferences.dart | 1 - lib/settings/part_settings.dart | 22 ------ lib/widget/company/company_detail.dart | 25 ++++++ .../company/manufacturer_part_detail.dart | 64 +++++++++++++-- lib/widget/company/supplier_part_detail.dart | 59 ++++++++++++++ lib/widget/order/purchase_order_detail.dart | 25 ++++++ lib/widget/order/sales_order_detail.dart | 25 ++++++ ...eter_widget.dart => parameter_widget.dart} | 78 +++++++++++++++---- lib/widget/part/part_detail.dart | 65 +++++++++------- 12 files changed, 378 insertions(+), 129 deletions(-) create mode 100644 lib/inventree/parameter.dart rename lib/widget/{part/part_parameter_widget.dart => parameter_widget.dart} (58%) diff --git a/lib/api.dart b/lib/api.dart index 1d24b39..61a6379 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -353,6 +353,10 @@ class InvenTreeAPI { // Supports separate search against "supplier" / "customer" / "manufacturer" bool get supportsSplitCompanySearch => apiVersion >= 315; + // Does the server support the "modern" (consolidated) parameter API? + // Ref: https://github.com/inventree/InvenTree/pull/10699 + bool get supportsModernParameters => apiVersion >= 429; + // Cached list of plugins (refreshed when we connect to the server) List _plugins = []; diff --git a/lib/inventree/parameter.dart b/lib/inventree/parameter.dart new file mode 100644 index 0000000..22006d7 --- /dev/null +++ b/lib/inventree/parameter.dart @@ -0,0 +1,77 @@ +import "package:inventree/inventree/model.dart"; + +class InvenTreeParameter extends InvenTreeModel { + InvenTreeParameter() : super(); + + InvenTreeParameter.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeParameter createFromJson(Map json) => + InvenTreeParameter.fromJson(json); + + @override + String get URL => "parameter/"; + + @override + Map> formFields() { + Map> fields = { + "header": { + "type": "string", + "read_only": true, + "label": name, + "help_text": description, + "value": "", + }, + "data": {"type": "string"}, + "note": {}, + }; + + return fields; + } + + @override + String get name => getString("name", subKey: "template_detail"); + + @override + String get description => getString("description", subKey: "template_detail"); + + String get value => getString("data"); + + String get valueString { + String v = value; + + if (units.isNotEmpty) { + v += " "; + v += units; + } + + return v; + } + + bool get as_bool => value.toLowerCase() == "true"; + + String get units => getString("units", subKey: "template_detail"); + + bool get is_checkbox => + getBool("checkbox", subKey: "template_detail", backup: false); + + // The model type of the instance this attachment is associated with + String get modelType => getString("model_type"); + + // The ID of the instance this attachment is associated with + int get modelId => getInt("model_id"); + + // Return a count of how many parameters exist against the specified model ID + Future countParameters(String modelType, int modelId) async { + Map filters = {}; + + if (!api.supportsModernParameters) { + return 0; + } + + filters["model_type"] = modelType; + filters["model_id"] = modelId.toString(); + + return count(filters: filters); + } +} diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index fc52399..033fae9 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -132,68 +132,6 @@ class InvenTreePartTestTemplate extends InvenTreeModel { } } -/* - Class representing the PartParameter database model - */ -class InvenTreePartParameter extends InvenTreeModel { - InvenTreePartParameter() : super(); - - InvenTreePartParameter.fromJson(Map json) - : super.fromJson(json); - - @override - String get URL => "part/parameter/"; - - @override - List get rolesRequired => ["part"]; - - @override - InvenTreeModel createFromJson(Map json) => - InvenTreePartParameter.fromJson(json); - - @override - Map> formFields() { - Map> fields = { - "header": { - "type": "string", - "read_only": true, - "label": name, - "help_text": description, - "value": "", - }, - "data": {"type": "string"}, - }; - - return fields; - } - - @override - String get name => getString("name", subKey: "template_detail"); - - @override - String get description => getString("description", subKey: "template_detail"); - - String get value => getString("data"); - - String get valueString { - String v = value; - - if (units.isNotEmpty) { - v += " "; - v += units; - } - - return v; - } - - bool get as_bool => value.toLowerCase() == "true"; - - String get units => getString("units", subKey: "template_detail"); - - bool get is_checkbox => - getBool("checkbox", subKey: "template_detail", backup: false); -} - /* * Class representing the Part database model */ diff --git a/lib/preferences.dart b/lib/preferences.dart index de7bb0f..92eda1f 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -32,7 +32,6 @@ const String INV_LABEL_DEFAULT_PRINTER = "defaultLabelPrinter"; const String INV_LABEL_DEFAULT_PLUGIN = "defaultLabelPlugin"; // Part settings -const String INV_PART_SHOW_PARAMETERS = "partShowParameters"; const String INV_PART_SHOW_BOM = "partShowBom"; const String INV_PART_SHOW_PRICING = "partShowPricing"; diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index b091931..aa13678 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -13,7 +13,6 @@ class InvenTreePartSettingsWidget extends StatefulWidget { class _InvenTreePartSettingsState extends State { _InvenTreePartSettingsState(); - bool partShowParameters = true; bool partShowBom = true; bool partShowPricing = true; bool stockShowHistory = false; @@ -28,10 +27,6 @@ class _InvenTreePartSettingsState extends State { } Future loadSettings() async { - partShowParameters = await InvenTreeSettingsManager().getBool( - INV_PART_SHOW_PARAMETERS, - true, - ); partShowBom = await InvenTreeSettingsManager().getBool( INV_PART_SHOW_BOM, true, @@ -68,23 +63,6 @@ class _InvenTreePartSettingsState extends State { body: Container( child: ListView( children: [ - ListTile( - title: Text(L10().parameters), - subtitle: Text(L10().parametersSettingDetail), - leading: Icon(TablerIcons.list), - trailing: Switch( - value: partShowParameters, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue( - INV_PART_SHOW_PARAMETERS, - value, - ); - setState(() { - partShowParameters = value; - }); - }, - ), - ), ListTile( title: Text(L10().bom), subtitle: Text(L10().bomEnable), diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 8947104..9a6d233 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/inventree/attachment.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -14,6 +15,7 @@ import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/order/sales_order_list.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/company/supplier_part_list.dart"; @@ -38,6 +40,7 @@ class _CompanyDetailState extends RefreshableState { int outstandingPurchaseOrders = 0; int outstandingSalesOrders = 0; + int parameterCount = 0; int attachmentCount = 0; @override @@ -185,6 +188,16 @@ class _CompanyDetailState extends RefreshableState { } }); + InvenTreeParameter() + .countParameters(InvenTreeCompany.MODEL_TYPE, widget.company.pk) + .then((value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + InvenTreeAttachment() .countAttachments(InvenTreeCompany.MODEL_TYPE, widget.company.pk) .then((value) { @@ -394,6 +407,18 @@ class _CompanyDetailState extends RefreshableState { ); } + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreeCompany.MODEL_TYPE, + widget.company.pk, + parameterCount, + widget.company.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + ListTile? attachmentTile = ShowAttachmentsItem( context, InvenTreeCompany.MODEL_TYPE, diff --git a/lib/widget/company/manufacturer_part_detail.dart b/lib/widget/company/manufacturer_part_detail.dart index 9cc6bc2..57a7e48 100644 --- a/lib/widget/company/manufacturer_part_detail.dart +++ b/lib/widget/company/manufacturer_part_detail.dart @@ -1,6 +1,8 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/inventree/attachment.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/l10.dart"; import "package:inventree/api.dart"; @@ -8,6 +10,8 @@ import "package:inventree/app_colors.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; @@ -31,6 +35,9 @@ class _ManufacturerPartDisplayState extends RefreshableState { _ManufacturerPartDisplayState(); + int parameterCount = 0; + int attachmentCount = 0; + @override String getAppBarTitle() => L10().manufacturerPart; @@ -42,7 +49,34 @@ class _ManufacturerPartDisplayState if (!result) { Navigator.of(context).pop(); + return; } + + InvenTreeParameter() + .countParameters( + InvenTreeManufacturerPart.MODEL_TYPE, + widget.manufacturerPart.pk, + ) + .then((value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + + InvenTreeAttachment() + .countAttachments( + InvenTreeManufacturerPart.MODEL_TYPE, + widget.manufacturerPart.pk, + ) + .then((value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); } Future editManufacturerPart(BuildContext context) async { @@ -91,11 +125,6 @@ class _ManufacturerPartDisplayState List getTiles(BuildContext context) { List tiles = []; - if (loading) { - tiles.add(progressIndicator()); - return tiles; - } - // Internal Part tiles.add( ListTile( @@ -174,6 +203,31 @@ class _ManufacturerPartDisplayState ); } + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreeManufacturerPart.MODEL_TYPE, + widget.manufacturerPart.pk, + parameterCount, + widget.manufacturerPart.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeManufacturerPart.MODEL_TYPE, + widget.manufacturerPart.pk, + widget.manufacturerPart.MPN, + attachmentCount, + widget.manufacturerPart.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } } diff --git a/lib/widget/company/supplier_part_detail.dart b/lib/widget/company/supplier_part_detail.dart index 77e29ab..ed60748 100644 --- a/lib/widget/company/supplier_part_detail.dart +++ b/lib/widget/company/supplier_part_detail.dart @@ -2,6 +2,9 @@ import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/attachment.dart"; +import "package:inventree/inventree/parameter.dart"; +import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/link_icon.dart"; import "package:inventree/app_colors.dart"; @@ -11,6 +14,7 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/company.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -35,6 +39,9 @@ class _SupplierPartDisplayState extends RefreshableState { _SupplierPartDisplayState(); + int parameterCount = 0; + int attachmentCount = 0; + @override String getAppBarTitle() => L10().supplierPart; @@ -97,7 +104,34 @@ class _SupplierPartDisplayState if (!result) { Navigator.of(context).pop(); + return; } + + InvenTreeParameter() + .countParameters( + InvenTreeSupplierPart.MODEL_TYPE, + widget.supplierPart.pk, + ) + .then((value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + + InvenTreeAttachment() + .countAttachments( + InvenTreeSupplierPart.MODEL_TYPE, + widget.supplierPart.pk, + ) + .then((value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); } /* @@ -286,6 +320,31 @@ class _SupplierPartDisplayState ); } + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreeSupplierPart.MODEL_TYPE, + widget.supplierPart.pk, + parameterCount, + widget.supplierPart.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeSupplierPart.MODEL_TYPE, + widget.supplierPart.pk, + widget.supplierPart.SKU, + attachmentCount, + widget.supplierPart.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + return tiles; } } diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 0829e06..d309a4b 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -8,6 +8,7 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/purchase_order.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/attachment.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/model.dart"; @@ -22,6 +23,7 @@ import "package:inventree/widget/order/po_line_list.dart"; import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/notes_widget.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; @@ -51,6 +53,7 @@ class _PurchaseOrderDetailState int completedLines = 0; int attachmentCount = 0; + int parameterCount = 0; bool showCameraShortcut = true; bool supportProjectCodes = false; @@ -300,6 +303,16 @@ class _PurchaseOrderDetailState } } + InvenTreeParameter() + .countParameters(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk) + .then((int value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + InvenTreeAttachment() .countAttachments(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk) .then((int value) { @@ -570,6 +583,18 @@ class _PurchaseOrderDetailState ), ); + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreePurchaseOrder.MODEL_TYPE, + widget.order.pk, + parameterCount, + widget.order.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + ListTile? attachmentTile = ShowAttachmentsItem( context, InvenTreePurchaseOrder.MODEL_TYPE, diff --git a/lib/widget/order/sales_order_detail.dart b/lib/widget/order/sales_order_detail.dart index 30692f2..79a3620 100644 --- a/lib/widget/order/sales_order_detail.dart +++ b/lib/widget/order/sales_order_detail.dart @@ -5,12 +5,14 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/sales_order.dart"; import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/inventree/sales_order.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/order/so_extra_line_list.dart"; import "package:inventree/widget/order/so_line_list.dart"; import "package:inventree/widget/order/so_shipment_list.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; @@ -43,6 +45,7 @@ class _SalesOrderDetailState extends RefreshableState { bool showCameraShortcut = true; bool supportsProjectCodes = false; int attachmentCount = 0; + int parameterCount = 0; @override String getAppBarTitle() { @@ -271,6 +274,16 @@ class _SalesOrderDetailState extends RefreshableState { true, ); + InvenTreeParameter() + .countParameters(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk) + .then((int value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + InvenTreeAttachment() .countAttachments(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk) .then((int value) { @@ -497,6 +510,18 @@ class _SalesOrderDetailState extends RefreshableState { ), ); + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreeSalesOrder.MODEL_TYPE, + widget.order.pk, + parameterCount, + widget.order.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + ListTile? attachmentTile = ShowAttachmentsItem( context, InvenTreeSalesOrder.MODEL_TYPE, diff --git a/lib/widget/part/part_parameter_widget.dart b/lib/widget/parameter_widget.dart similarity index 58% rename from lib/widget/part/part_parameter_widget.dart rename to lib/widget/parameter_widget.dart index c4df189..07a38fc 100644 --- a/lib/widget/part/part_parameter_widget.dart +++ b/lib/widget/parameter_widget.dart @@ -1,8 +1,12 @@ import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api.dart"; +import "package:inventree/app_colors.dart"; import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/l10.dart"; -import "package:inventree/inventree/part.dart"; +import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -10,16 +14,18 @@ import "package:inventree/widget/refreshable_state.dart"; /* * Widget for displaying a list of parameters associated with a given Part instance */ -class PartParameterWidget extends StatefulWidget { - const PartParameterWidget(this.part); +class ParameterWidget extends StatefulWidget { + const ParameterWidget(this.modelType, this.modelId, this.editable) : super(); - final InvenTreePart part; + final String modelType; + final int modelId; + final bool editable; @override _ParameterWidgetState createState() => _ParameterWidgetState(); } -class _ParameterWidgetState extends RefreshableState { +class _ParameterWidgetState extends RefreshableState { _ParameterWidgetState(); @override @@ -34,9 +40,16 @@ class _ParameterWidgetState extends RefreshableState { @override Widget getBody(BuildContext context) { - Map filters = {"part": widget.part.pk.toString()}; + Map filters = { + "model_type": widget.modelType, + "model_id": widget.modelId.toString(), + }; - return Column(children: [Expanded(child: PaginatedParameterList(filters))]); + return Column( + children: [ + Expanded(child: PaginatedParameterList(filters, widget.editable)), + ], + ); } } @@ -44,9 +57,11 @@ class _ParameterWidgetState extends RefreshableState { * Widget for displaying a paginated list of Part parameters */ class PaginatedParameterList extends PaginatedSearchWidget { - const PaginatedParameterList(Map filters) + const PaginatedParameterList(Map filters, this.editable) : super(filters: filters); + final bool editable; + @override String get searchTitle => L10().parameters; @@ -75,7 +90,7 @@ class _PaginatedParameterState int offset, Map params, ) async { - final page = await InvenTreePartParameter().listPaginated( + final page = await InvenTreeParameter().listPaginated( limit, offset, filters: params, @@ -84,7 +99,7 @@ class _PaginatedParameterState return page; } - Future editParameter(InvenTreePartParameter parameter) async { + Future editParameter(InvenTreeParameter parameter) async { // Checkbox values are handled separately if (parameter.is_checkbox) { return; @@ -101,7 +116,7 @@ class _PaginatedParameterState @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePartParameter parameter = model as InvenTreePartParameter; + InvenTreeParameter parameter = model as InvenTreeParameter; String title = parameter.name; @@ -116,7 +131,7 @@ class _PaginatedParameterState ? Switch( value: parameter.as_bool, onChanged: (bool value) { - if (parameter.canEdit) { + if (widget.editable) { showLoadingOverlay(); parameter.update(values: {"data": value.toString()}).then(( value, @@ -131,10 +146,47 @@ class _PaginatedParameterState onTap: parameter.is_checkbox ? null : () async { - if (parameter.canEdit) { + if (widget.editable) { editParameter(parameter); } }, ); } } + +/* + * Return a ListTile to display parameters for the specified model + */ +ListTile? ShowParametersItem( + BuildContext context, + String modelType, + int modelId, + int parameterCount, + bool editable, +) { + // Note: Currently cannot add parameters from the app, + // So, if there are no parameters, do not show the item + if (parameterCount == 0) { + return null; + } + + if (!InvenTreeAPI().supportsModernParameters) { + return null; + } + + return ListTile( + title: Text(L10().parameters), + leading: Icon(TablerIcons.list_details, color: COLOR_ACTION), + trailing: LinkIcon( + text: parameterCount > 0 ? parameterCount.toString() : null, + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ParameterWidget(modelType, modelId, editable), + ), + ); + }, + ); +} diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 30b697c..73a299f 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -5,6 +5,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/barcode/barcode.dart"; import "package:inventree/inventree/attachment.dart"; +import "package:inventree/inventree/parameter.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; @@ -16,10 +17,10 @@ import "package:inventree/preferences.dart"; import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/link_icon.dart"; +import "package:inventree/widget/parameter_widget.dart"; import "package:inventree/widget/part/bom_list.dart"; import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/notes_widget.dart"; -import "package:inventree/widget/part/part_parameter_widget.dart"; import "package:inventree/widget/part/part_pricing.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/part/category_display.dart"; @@ -50,13 +51,11 @@ class _PartDisplayState extends RefreshableState { InvenTreeStockLocation? defaultLocation; - int parameterCount = 0; - bool allowLabelPrinting = false; - bool showParameters = false; bool showBom = false; bool showPricing = false; + int parameterCount = 0; int attachmentCount = 0; int bomCount = 0; int usedInCount = 0; @@ -153,10 +152,6 @@ class _PartDisplayState extends RefreshableState { INV_PART_SHOW_PRICING, true, ); - showParameters = await InvenTreeSettingsManager().getBool( - INV_PART_SHOW_PARAMETERS, - true, - ); showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); allowLabelPrinting = await InvenTreeSettingsManager().getBool( INV_ENABLE_LABEL_PRINTING, @@ -213,15 +208,30 @@ class _PartDisplayState extends RefreshableState { } // Request the number of attachments - InvenTreeAttachment() - .countAttachments(InvenTreePart.MODEL_TYPE, part.pk) - .then((int value) { - if (mounted) { - setState(() { - attachmentCount = value; - }); - } - }); + if (api.supportsModernAttachments) { + InvenTreeAttachment() + .countAttachments(InvenTreePart.MODEL_TYPE, part.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } + + // Request the number of parameters + if (api.supportsModernParameters) { + InvenTreeParameter() + .countParameters(InvenTreePart.MODEL_TYPE, part.pk) + .then((int value) { + if (mounted) { + setState(() { + parameterCount = value; + }); + } + }); + } // If show pricing information? if (showPricing) { @@ -599,6 +609,18 @@ class _PartDisplayState extends RefreshableState { ), ); + ListTile? parameterTile = ShowParametersItem( + context, + InvenTreePart.MODEL_TYPE, + part.pk, + parameterCount, + part.canEdit, + ); + + if (parameterTile != null) { + tiles.add(parameterTile); + } + ListTile? attachmentTile = ShowAttachmentsItem( context, InvenTreePart.MODEL_TYPE, @@ -705,10 +727,6 @@ class _PartDisplayState extends RefreshableState { List getTabIcons(BuildContext context) { List icons = [Tab(text: L10().details), Tab(text: L10().stock)]; - if (showParameters) { - icons.add(Tab(text: L10().parameters)); - } - return icons; } @@ -721,11 +739,6 @@ class _PartDisplayState extends RefreshableState { ), PaginatedStockItemList({"part": part.pk.toString()}), ]; - - if (showParameters) { - tabs.add(PaginatedParameterList({"part": part.pk.toString()})); - } - return tabs; } } From 571ff1880f91983db03e8098a5f20f58ec9b6703 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 6 Dec 2025 11:24:17 +1100 Subject: [PATCH 734/746] New translations app_en.arb (Chinese Simplified) (#739) --- lib/l10n/zh_CN/app_zh_CN.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index edb54e2..876f122 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "条形码扫描已暂停", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "点击或按住以暂停扫描", "@barcodeScanPause": {}, "barcodeScanAssign": "扫描以分配条形码", "@barcodeScanAssign": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "关键词", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "标签打印机", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "选择标签打印机", "@labelSelectDriver": {}, "labelPrinting": "打印标签", "@labelPrinting": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "创建新库存地点", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "默认库存地点", "@locationDefault": {}, "locationNotSet": "没有指定仓储位置", "@locationNotSet": {}, From 8c15bdafdf9aeb03be2c43e2b68794d345dbca96 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 19 Dec 2025 09:52:38 +1100 Subject: [PATCH 735/746] New Crowdin updates (#740) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Dutch) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (German) * New translations app_en.arb (Turkish) * New translations app_en.arb (Italian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Romanian) --- lib/l10n/de_DE/app_de_DE.arb | 30 +++++------ lib/l10n/hu_HU/app_hu_HU.arb | 52 +++++++++--------- lib/l10n/it_IT/app_it_IT.arb | 6 +-- lib/l10n/nl_NL/app_nl_NL.arb | 52 +++++++++--------- lib/l10n/ro_RO/app_ro_RO.arb | 16 +++--- lib/l10n/sv_SE/app_sv_SE.arb | 30 +++++------ lib/l10n/tr_TR/app_tr_TR.arb | 72 ++++++++++++------------- lib/l10n/uk_UA/app_uk_UA.arb | 102 +++++++++++++++++------------------ 8 files changed, 180 insertions(+), 180 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index dc075ef..e0bb95c 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode-Scannen angehalten", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Tippen um das Scannen zu pausieren", "@barcodeScanPause": {}, "barcodeScanAssign": "Scannen um Barcode zuzuweisen", "@barcodeScanAssign": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Schlüsselwörter", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Etikettendrucker Treiber", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Etikettendrucker Treiber auswählen", "@labelSelectDriver": {}, "labelPrinting": "Etikettendruck", "@labelPrinting": {}, @@ -944,29 +944,29 @@ "@shipment": {}, "shipments": "Lieferungen", "@shipments": {}, - "shipmentsPending": "Ausstehende Sendungen", + "shipmentsPending": "Ausstehende Lieferungen", "@shipmentsPending": {}, "shipmentAdd": "Lieferung hinzufügen", "@shipmentAdd": {}, - "shipmentCheck": "Sendung prüfen", + "shipmentCheck": "Lieferung überprüfen", "@shipmentCheck": {}, - "shipmentCheckDetail": "Diese Sendung als geprüft markieren", + "shipmentCheckDetail": "Diese Lieferung als geprüft markieren", "@shipmentCheckDetail": {}, - "shipmentChecked": "Sendung geprüft", + "shipmentChecked": "Lieferung überprüft", "@shipmentChecked": {}, "shipmentDate": "Versanddatum", "@shipmentDate": {}, - "shipmentEdit": "Sendung bearbeiten", + "shipmentEdit": "Lieferung bearbeiten", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Sendungsreferenz", "@shipmentReference": {}, "shipmentSend": "Lieferung versenden", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Lieferung ungeprüft markieren", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Diese Lieferung als ungeprüft markieren", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Lieferung Aktualisiert", "@shipmentUpdated": {}, "shipped": "Versandt", "@shipped": {}, @@ -1102,7 +1102,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Taschenlampe umschalten", "@toggleTorch": {}, "tokenError": "Token-Fehler", "@tokenError": {}, @@ -1182,7 +1182,7 @@ "@priceRange": {}, "priceOverrideMin": "Mindestpreis überschreiben", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Maximalen Preis ignorieren", "@priceOverrideMax": {}, "salePrice": "Verkaufspreis", "@salePrice": {}, @@ -1198,7 +1198,7 @@ "@variantCost": {}, "overallPricing": "Gesamt Preise", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Preisgestaltung ignorieren", "@pricingOverrides": {}, "currency": "Währung", "@currency": {}, diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 3286dfa..509d9d2 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Készlet foglalása", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Lefoglalt Készlet", "@allocatedStock": {}, "appReleaseNotes": "Kiadási közlemények", "@appReleaseNotes": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Vonalkód olvasás megállítva", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Érintse meg a szkennelés szüneteltetéséhez", "@barcodeScanPause": {}, "barcodeScanAssign": "Kódolvasás a hozzárendeléshez", "@barcodeScanAssign": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Törlés sikeres", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Szállítási Dátum", "@deliveryDate": {}, "description": "Leírás", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Szállítmányok Mutatása", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Függőben lévő szállítmányok megjelenítése a kezdőképernyőn", "@homeShowShipmentsDescription": {}, "homeShowSo": "Vevői rendelések megmutatása", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Számla", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Számlaszám", "@invoiceNumber": {}, "issue": "Kiküldés", "@issue": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Kulcsszavak", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Címke Meghajtó", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Címkenyomtató Meghajtó Kiválasztása", "@labelSelectDriver": {}, "labelPrinting": "Címke nyomtatás", "@labelPrinting": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Új készlet hely létrehozása", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Alapértelmezett Hely", "@locationDefault": {}, "locationNotSet": "Nincs megadva hely", "@locationNotSet": {}, @@ -544,7 +544,7 @@ "@missingData": {}, "name": "Név", "@name": {}, - "no": "No", + "no": "Nem", "@no": {}, "notApplicable": "N/A", "@notApplicable": {}, @@ -660,7 +660,7 @@ "@password": {}, "passwordEmpty": "Jelszó nem lehet üres", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Függőben", "@pending": {}, "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", "@permissionAccountDenied": {}, @@ -940,33 +940,33 @@ "@serverNotConnected": {}, "serverNotSelected": "Nincs kiszolgáló választva", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Szállítmány", "@shipment": {}, "shipments": "Szállítmányok", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Függőben Lévő Szállítmányok", "@shipmentsPending": {}, "shipmentAdd": "Szállítmány hozzáadása", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Szállítmány Ellenőrzése", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Jelölje meg ezt a szállítmányt ellenőrzöttként", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Szállítmány Ellenőrizve", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Szállítmány Dátuma", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Szállítmány Szerkesztése", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Szállítmány Hivatkozás", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Szállítmány Küldése", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Szállítmány Ellenőrzés Visszavonása", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Jelölje meg ezt a szállítmányt nem ellenőrzöttként", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Szállítmány Frissítve", "@shipmentUpdated": {}, "shipped": "Kiszállítva", "@shipped": {}, @@ -1112,7 +1112,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Teljes ár", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Nyomkövetési Szám", "@trackingNumber": {}, "transfer": "Áthelyezés", "@transfer": { @@ -1174,7 +1174,7 @@ "@viewSupplierPart": {}, "website": "Weboldal", "@website": {}, - "yes": "Yes", + "yes": "Igen", "@yes": {}, "price": "Ár", "@price": {}, diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index db6286a..ecbe8b1 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Scansione codice a barre in pausa", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Tocca per mettere in pausa la scansione", "@barcodeScanPause": {}, "barcodeScanAssign": "Scansiona per assegnare codice a barre", "@barcodeScanAssign": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Parole Chiave", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Driver Etichetta", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Seleziona Il Driver Della Stampante Etichette", "@labelSelectDriver": {}, "labelPrinting": "Etichetta in stampa", "@labelPrinting": {}, diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index d8eab7d..ba45758 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Voorraad Toewijzen", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Toegewezen voorraad", "@allocatedStock": {}, "appReleaseNotes": "App release notities weergeven", "@appReleaseNotes": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barcode scannen gepauzeerd", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Klik om scannen te pauzeren", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan om streepjescode toe te wijzen", "@barcodeScanAssign": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Succesvol verwijderd", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Leveringsdatum", "@deliveryDate": {}, "description": "Omschrijving", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Verzending weergeven", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Toon Leveringen in afwachting op het startscherm", "@homeShowShipmentsDescription": {}, "homeShowSo": "Toon Verkooporders", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Factuur", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Factuur nummer", "@invoiceNumber": {}, "issue": "Probleem", "@issue": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Trefwoorden", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Label printer", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Selecteer Label Printer Driver", "@labelSelectDriver": {}, "labelPrinting": "Label afdrukken", "@labelPrinting": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Creëer nieuwe voorraadlocatie", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Standaard locatie", "@locationDefault": {}, "locationNotSet": "Geen locatie opgegeven", "@locationNotSet": {}, @@ -544,9 +544,9 @@ "@missingData": {}, "name": "Naam", "@name": {}, - "no": "No", + "no": "Nee", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "N.v.t. ", "@notApplicable": {}, "notConnected": "Niet verbonden", "@notConnected": {}, @@ -660,7 +660,7 @@ "@password": {}, "passwordEmpty": "Wachtwoord mag niet leeg zijn", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "In behandeling", "@pending": {}, "permissionAccountDenied": "U heeft niet de vereiste rechten om deze actie uit te voeren", "@permissionAccountDenied": {}, @@ -940,33 +940,33 @@ "@serverNotConnected": {}, "serverNotSelected": "Server niet geselecteerd", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Levering", "@shipment": {}, "shipments": "Verzendingen", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Leveringen in behandeling", "@shipmentsPending": {}, "shipmentAdd": "Verzending toevoegen", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Controleer Levering", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Markeer deze levering als gecontroleerd", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Levering gecontroleerd", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Leverings Datum", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Wijzig levering", "@shipmentEdit": {}, "shipmentReference": "Shipment Reference", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Verzending versturen", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Verzending uitvinken", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Markeer deze levering als niet gecontroleerd", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Verzending bijgewerkt", "@shipmentUpdated": {}, "shipped": "Verzonden", "@shipped": {}, @@ -1112,7 +1112,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Totaalprijs", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Traceernummer", "@trackingNumber": {}, "transfer": "Verplaats", "@transfer": { @@ -1174,7 +1174,7 @@ "@viewSupplierPart": {}, "website": "Website", "@website": {}, - "yes": "Yes", + "yes": "Ja", "@yes": {}, "price": "Prijs", "@price": {}, diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index ff74b98..6f07c0d 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Scanare cod de bare întreruptă", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Atingeți pentru a întrerupe scanarea", "@barcodeScanPause": {}, "barcodeScanAssign": "Scanează pentru a atribui cod de bare", "@barcodeScanAssign": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Cuvinte cheie", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Etichetează șofer", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Selectați șofer de imprimante etichetă", "@labelSelectDriver": {}, "labelPrinting": "Printare etichete", "@labelPrinting": {}, @@ -822,17 +822,17 @@ "@response504": {}, "response505": "Versiunea HTTP nu este suportată", "@response505": {}, - "responseData": "Response data", + "responseData": "Date Răspuns", "@responseData": {}, - "responseInvalid": "Invalid Response Code", + "responseInvalid": "Cod de răspuns nevalid", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "Răspuns necunoscut", "@responseUnknown": {}, - "result": "Result", + "result": "Rezultat", "@result": { "description": "" }, - "returned": "Returned", + "returned": "Returnat", "@returned": {}, "salesOrder": "Sales Order", "@salesOrder": {}, diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index ae837a4..88d8b85 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Streckkodsskanning pausad", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Tryck för att pausa skanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Skanna för att tilldela streckkod", "@barcodeScanAssign": {}, @@ -228,7 +228,7 @@ "@delete": {}, "deleteFailed": "Borttagning misslyckades", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Är du säker på att du vill radera denna bild?", "@deleteImageConfirmation": {}, "deleteImageTooltip": "Radera bild", "@deleteImageTooltip": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Borttagning lyckad", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Leveransdatum", "@deliveryDate": {}, "description": "Beskrivning", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Visa knappen för inköpsorder på startskärmen", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Visa leveranser", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Visa väntande leveranser på startskärmen", "@homeShowShipmentsDescription": {}, "homeShowSo": "Visa försäljningsorder", "@homeShowSo": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Skapa ny lagerplats", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Förvald plats", "@locationDefault": {}, "locationNotSet": "Ingen plats specificerad", "@locationNotSet": {}, @@ -564,9 +564,9 @@ "@noResults": {}, "noImageAvailable": "Ingen bild tillgänglig", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Ingen prisinformation tillgänglig", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Inga prisuppgifter hittades för denna artikel", "@noPricingDataFound": {}, "noSubcategories": "Inga underkategorier", "@noSubcategories": {}, @@ -630,7 +630,7 @@ "@partsNone": {}, "partNoResults": "Inga artiklar som matchar sökfrågan", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Artikelpris", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, @@ -762,7 +762,7 @@ "@reference": {}, "refresh": "Uppdatera", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Rotera 90° medurs", "@rotateClockwise": {}, "refreshing": "Uppdaterar", "@refreshing": {}, @@ -940,7 +940,7 @@ "@serverNotConnected": {}, "serverNotSelected": "Servern är inte vald", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Försändelse", "@shipment": {}, "shipments": "Frakt", "@shipments": {}, @@ -954,7 +954,7 @@ "@shipmentCheckDetail": {}, "shipmentChecked": "Shipment Checked", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Leveransdatum", "@shipmentDate": {}, "shipmentEdit": "Edit Shipment", "@shipmentEdit": {}, @@ -1112,7 +1112,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "Totalpris", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Sändningsnummer", "@trackingNumber": {}, "transfer": "Överföring", "@transfer": { @@ -1184,11 +1184,11 @@ "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Försäljningspris", "@salePrice": {}, "saleHistory": "Sale History", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Leverantörspriser", "@supplierPricing": {}, "bomCost": "BOM Cost", "@bomCost": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index dfffe0e..464d390 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -48,7 +48,7 @@ "@allocateStock": {}, "allocatedStock": "Tahsis Edilen Stok", "@allocatedStock": {}, - "appReleaseNotes": "Uygulama yayınlama notlarını göster", + "appReleaseNotes": "Uygulama yayınlama notlarını görüntüle", "@appReleaseNotes": {}, "appSettings": "Uygulama Ayarları", "@appSettings": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Barkod tarama duraklatıldı", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Taramayı duraklatmak için dokunun", "@barcodeScanPause": {}, "barcodeScanAssign": "Atanmış barkodu tara", "@barcodeScanAssign": {}, @@ -116,7 +116,7 @@ "@barcodeScanDelayDetail": {}, "barcodeScanGeneral": "Bir InvenTree barkodu tara", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Stok ögelerini bu konum içine tara", + "barcodeScanInItems": "Stok kalemlerini bu konumun içine tara", "@barcodeScanInItems": {}, "barcodeScanLocation": "Stok konumu tara", "@barcodeScanLocation": {}, @@ -128,7 +128,7 @@ "@barcodeScanIntoLocationSuccess": {}, "barcodeScanIntoLocationFailure": "Madde taranmış değil", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Stok öğesi tara", + "barcodeScanItem": "Stok kalemi tara", "@barcodeScanItem": {}, "barcodeTones": "Barkod Tonları", "@barcodeTones": {}, @@ -144,9 +144,9 @@ "@bom": {}, "bomEnable": "Malzeme Listesini Görüntüle", "@bomEnable": {}, - "build": "Oluştur", + "build": "Yap", "@build": {}, - "building": "Oluşturma", + "building": "Yapılıyor", "@building": {}, "cameraCreationError": "Kamera Kontrolcüsü Açılamadı", "@cameraCreationError": {}, @@ -278,7 +278,7 @@ "@editPart": { "description": "edit part" }, - "editItem": "Parçayı Düzenle", + "editItem": "Stok kalemi düzenle", "@editItem": {}, "editLineItem": "Satır Ögesini Düzenle", "@editLineItem": {}, @@ -348,7 +348,7 @@ "@filterInStockDetail": {}, "filterSerialized": "Sıralandırılmış", "@filterSerialized": {}, - "filterSerializedDetail": "Sıralandırılmış stok ürünkerini göster", + "filterSerializedDetail": "Seri numaralı stok kalemlerini göster", "@filterSerializedDetail": {}, "filterTemplate": "Şablon", "@filterTemplate": {}, @@ -414,7 +414,7 @@ "@imageUploadSuccess": {}, "inactive": "Pasif", "@inactive": {}, - "inactiveCompany": "Bu şirket inaktif olarak imlendi", + "inactiveCompany": "Bu şirket pasif olarak imlendi", "@inactiveCompany": {}, "inactiveDetail": "Bu parça pasif olarak işaretlendi", "@inactiveDetail": {}, @@ -434,7 +434,7 @@ "@info": {}, "inProduction": "Yapım Aşamasında", "@inProduction": {}, - "inProductionDetail": "Bu ürün üretim aşamasında", + "inProductionDetail": "Bu stok kalemi üretimdedir", "@inProductionDetail": {}, "internalPart": "İç Parça", "@internalPart": {}, @@ -448,7 +448,7 @@ "@invalidPartCategory": {}, "invalidStockLocation": "Geçersiz Stok Konumu", "@invalidStockLocation": {}, - "invalidStockItem": "Geçersiz Stok Parçası", + "invalidStockItem": "Geçersiz Stok Kalemi", "@invalidStockItem": {}, "invalidSupplierPart": "Geçersiz Tedarikçi Parçası", "@invalidSupplierPart": {}, @@ -474,7 +474,7 @@ "@keywords": {}, "labelDriver": "Label Driver", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Etiket Yazıcı Sürücüsü Seçin", "@labelSelectDriver": {}, "labelPrinting": "Etiket Yazdırma", "@labelPrinting": {}, @@ -492,7 +492,7 @@ "@languageDefault": {}, "languageSelect": "Dil Seçin", "@languageSelect": {}, - "lastStocktake": "Son stok tutma", + "lastStocktake": "Son Stok Sayımı", "@lastStocktake": {}, "lastUpdated": "Son güncelleme", "@lastUpdated": {}, @@ -506,7 +506,7 @@ "@lineItems": {}, "lineItemUpdated": "Satır ögesi güncellendi", "@lineItemUpdated": {}, - "locateItem": "Stok ögesi bul", + "locateItem": "Stok kalemi bul", "@locateItem": {}, "locateLocation": "Stok konumu bul", "@locateLocation": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Yeni stok konumu oluştur", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Varsayılan Konum", "@locationDefault": {}, "locationNotSet": "Belirtilmiş konum yok", "@locationNotSet": {}, @@ -602,7 +602,7 @@ "@packageName": {}, "parameters": "Parametreler", "@parameters": {}, - "parametersSettingDetail": "Parça parametrelerini göster", + "parametersSettingDetail": "Parça parametrelerini görüntüle", "@parametersSettingDetail": {}, "parent": "Üst", "@parent": {}, @@ -712,7 +712,7 @@ "@purchaseOrderConfirmScan": {}, "purchaseOrderConfirmScanDetail": "Taranan Ürünlerin Detaylarını Onayla", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Satın Alma Emirlerini Etkinleştir", + "purchaseOrderEnable": "Satın Alma Siparişlerini Etkinleştir", "@purchaseOrderEnable": {}, "purchaseOrderEnableDetail": "Satın Alma Emirlerinin İşlevselliğini Etkinleştir", "@purchaseOrderEnableDetail": {}, @@ -728,7 +728,7 @@ "@purchaseOrderEdit": {}, "purchaseOrderSettings": "Satın Alma Emri Ayarları", "@purchaseOrderSettings": {}, - "purchaseOrders": "Satınalma Siparişleri", + "purchaseOrders": "Satın Alma Siparişleri", "@purchaseOrders": {}, "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", "@purchaseOrderUpdated": {}, @@ -756,7 +756,7 @@ "@receivedFilterDetail": {}, "receiveItem": "Alınan Öğeler", "@receiveItem": {}, - "receivedItem": "Alınan stok parçaları", + "receivedItem": "Alınan stok kalemleri", "@receivedItem": {}, "reference": "Referans", "@reference": {}, @@ -838,7 +838,7 @@ "@salesOrder": {}, "salesOrders": "Satış Siparişleri", "@salesOrders": {}, - "salesOrderEnable": "Satış Emirlerini Etkinleştir", + "salesOrderEnable": "Satış Siparişlerini Etkinleştir", "@salesOrderEnable": {}, "salesOrderEnableDetail": "Satış Siparişlerinin İşlevselliğini Etkinleştir", "@salesOrderEnableDetail": {}, @@ -860,7 +860,7 @@ }, "scanBarcode": "Barkod Tara", "@scanBarcode": {}, - "scanSupplierPart": "Sağlayıcı parça barkodunu tara", + "scanSupplierPart": "Tedarikçi parça barkodunu tara", "@scanSupplierPart": {}, "scanIntoLocation": "Konuma Tara", "@scanIntoLocation": {}, @@ -998,25 +998,25 @@ "@stockItems": {}, "stockItemCreate": "Yeni Stok Kalemi", "@stockItemCreate": {}, - "stockItemCreateDetail": "Bu konuma yeni stok kalemi oluştur", + "stockItemCreateDetail": "Bu konumda yeni stok kalemi oluştur", "@stockItemCreateDetail": {}, "stockItemDelete": "Stok parçasını sil", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Bu stock ögesini silmek istediğinize emin misiniz?", + "stockItemDeleteConfirm": "Bu stok kalemini silmek istediğinize emin misiniz?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Stok parçası silinemedi", + "stockItemDeleteFailure": "Stok kalemi silinemedi", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stok ögesi silindi", + "stockItemDeleteSuccess": "Stok kalemi silindi", "@stockItemDeleteSuccess": {}, "stockItemHistory": "Stok Geçmişi", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Geçmiş stok takip bilgisini göster", + "stockItemHistoryDetail": "Geçmiş stok takip bilgisini görüntüle", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stok ögesi aktarıldı", + "stockItemTransferred": "Stok kalemi aktarıldı", "@stockItemTransferred": {}, - "stockItemUpdated": "Stok ögesi güncellendi", + "stockItemUpdated": "Stok kalemi güncellendi", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "Kullanılabilir stok ögesi yok", + "stockItemsNotAvailable": "Stok kalemi bulunmamaktadır", "@stockItemsNotAvailable": {}, "stockItemNotes": "Stok Kalemi Notları", "@stockItemNotes": {}, @@ -1056,11 +1056,11 @@ "@supplier": {}, "supplierPart": "Tedarikçi Parçası", "@supplierPart": {}, - "supplierPartEdit": "Sağlayıcı Parçasını Düzenle", + "supplierPartEdit": "Tedarikçi Parçasını Düzenle", "@supplierPartEdit": {}, - "supplierPartNumber": "Sağlayıcı Parça Numarası", + "supplierPartNumber": "Tedarikçi Parça Numarası", "@supplierPartNumber": {}, - "supplierPartUpdated": "Sağlayıcı Parçası Güncellendi", + "supplierPartUpdated": "Tedarikçi Parçası Güncellendi", "@supplierPartUpdated": {}, "supplierParts": "Tedarikçi Parçaları", "@supplierParts": {}, @@ -1086,7 +1086,7 @@ "@testResults": { "description": "" }, - "testResultsDetail": "Stok ögesi test sonuçlarını görüntüle", + "testResultsDetail": "Stok kalemi test sonuçlarını görüntüle", "@testResultsDetail": {}, "testResultAdd": "Test Sonucu Ekle", "@testResultAdd": {}, @@ -1166,7 +1166,7 @@ "@valueCannotBeEmpty": {}, "valueRequired": "Değer gereklidir", "@valueRequired": {}, - "variants": "Türevler", + "variants": "Varyantlar", "@variants": {}, "version": "Sürüm", "@version": {}, @@ -1188,13 +1188,13 @@ "@salePrice": {}, "saleHistory": "Satış Geçmişi", "@saleHistory": {}, - "supplierPricing": "Sağlayıcı Fiyatlandırması", + "supplierPricing": "Tedarikçi Fiyatlandırması", "@supplierPricing": {}, "bomCost": "BoM Maliyeti", "@bomCost": {}, "internalCost": "Dahili Maliyet", "@internalCost": {}, - "variantCost": "Türev Maliyeti", + "variantCost": "Varyant Maliyeti", "@variantCost": {}, "overallPricing": "Genel Fiyatlandırma", "@overallPricing": {}, diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 5eb5c48..da21c3a 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -46,7 +46,7 @@ "@aspectRatioSquare": {}, "allocateStock": "Виділити запас", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Виділений Запас", "@allocatedStock": {}, "appReleaseNotes": "Показати примітки до випуску", "@appReleaseNotes": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Сканування штрих-кодів призупинено", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Торкніться або утримуйте, щоб призупинити сканування", "@barcodeScanPause": {}, "barcodeScanAssign": "Сканувати щоб призначити штрих-код", "@barcodeScanAssign": {}, @@ -228,11 +228,11 @@ "@delete": {}, "deleteFailed": "Помилка видалення", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Ви дійсно хочете видалити це зображення?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Видалити Зображення", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Видалити Зображення", "@deleteImage": {}, "deletePart": "Видалити деталь", "@deletePart": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "Операція видалення пройшла успішно", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Дата Доставки", "@deliveryDate": {}, "description": "Опис", "@description": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "Показувати кнопку замовлення на домашньому екрані", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Показати відправлення", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Показати відкладені відправлення на головному екрані", "@homeShowShipmentsDescription": {}, "homeShowSo": "Показати замовлення", "@homeShowSo": {}, @@ -454,15 +454,15 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Неправильна комбінація імені користувача та пароля", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Інвойс", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Номер Інвойсу", "@invoiceNumber": {}, - "issue": "Issue", + "issue": "Видача", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Дата Видачі", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Оформити Замовлення", "@issueOrder": {}, "itemInLocation": "Товар вже на місці", "@itemInLocation": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "Ключові слова", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Драйвер Етикеток", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Вибрати Драйвер Принтера Етикеток", "@labelSelectDriver": {}, "labelPrinting": "Друк Ярликів", "@labelPrinting": {}, @@ -482,9 +482,9 @@ "@labelPrintingDetail": {}, "labelTemplate": "Шаблон Ярлика", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Вибрати Шаблон Етикетки", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Вибрати Принтер Етикеток", "@labelSelectPrinter": {}, "language": "Мова", "@language": {}, @@ -492,19 +492,19 @@ "@languageDefault": {}, "languageSelect": "Вибір мови", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Остання інвентаризація", "@lastStocktake": {}, "lastUpdated": "Останнє оновлення", "@lastUpdated": {}, "level": "Рівень", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Додати Позицію", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Позиція", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "Позиції", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Позицію оновлено", "@lineItemUpdated": {}, "locateItem": "Знайти елемент запасів", "@locateItem": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "Створити нове розташування на складі", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Розташування за замовчуванням", "@locationDefault": {}, "locationNotSet": "Розташування не вказано", "@locationNotSet": {}, @@ -544,9 +544,9 @@ "@missingData": {}, "name": "Назва", "@name": {}, - "no": "No", + "no": "Ні", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "Н/Д", "@notApplicable": {}, "notConnected": "Не під’єднано", "@notConnected": {}, @@ -564,19 +564,19 @@ "@noResults": {}, "noImageAvailable": "Немає доступного зображення", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Ціни не вказано", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Для цієї деталі не знайдено даних про ціну", "@noPricingDataFound": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Немає Підкатегорій", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Немає доступних підкатегорій", "@noSubcategoriesAvailable": {}, "numberInvalid": "Некоректний номер", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "У замовленні", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Позиції в поточних замовленнях", "@onOrderDetails": {}, "orientation": "Орієнтація екрана", "@orientation": {}, @@ -632,7 +632,7 @@ "@partNoResults": {}, "partPricing": "Ціна деталі", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Відображати інформацію про ціни на деталь", "@pricingSettingDetail": {}, "partSettings": "Налаштування позиції", "@partSettings": {}, @@ -652,7 +652,7 @@ "@partDetails": {}, "partNotes": "Примітки до позиції", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Наявність На Складі", "@partStock": { "description": "part stock" }, @@ -660,7 +660,7 @@ "@password": {}, "passwordEmpty": "Пароль не може бути порожнім", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "В очікуванні", "@pending": {}, "permissionAccountDenied": "Ваш обліковий запис не має необхідних прав для виконання цієї дії", "@permissionAccountDenied": {}, @@ -712,27 +712,27 @@ "@purchaseOrderConfirmScan": {}, "purchaseOrderConfirmScanDetail": "Підтвердити подробиці при скануванні в позицій", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Увімкнути Закупівлю", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Увімкнути функціонал закупівлі", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Швидкий Доступ до Камери", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Увімкнути ярлик для завантаження зображень на екрані закупівель", "@purchaseOrderShowCameraDetail": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "Замовлення на Закупівлю", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Нове Замовлення на Закупівлю", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "Редагувати Замовлення на Закупівлю", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Налаштування замовлення на закупівлю", "@purchaseOrderSettings": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "Закупівлі", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "Замовлення на закупівлю оновлено", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "Закупівельна Ціна", "@purchasePrice": {}, "quantity": "Кількість", "@quantity": { @@ -740,7 +740,7 @@ }, "quantityAvailable": "Доступна кількість", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Кількість не вказана", "@quantityEmpty": {}, "quantityInvalid": "Некоректна кількість", "@quantityInvalid": {}, @@ -752,13 +752,13 @@ "@queryNoResults": {}, "received": "Отримано", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Показувати отримані позиції", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Прийняти Позицію", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "Отримана Складська Позиція", "@receivedItem": {}, - "reference": "Reference", + "reference": "Номер документа", "@reference": {}, "refresh": "Оновити", "@refresh": {}, @@ -766,7 +766,7 @@ "@rotateClockwise": {}, "refreshing": "Оновлення", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Відхилено", "@rejected": {}, "releaseNotes": "Замітки до випуску", "@releaseNotes": {}, From bf19ace3e93754c86d70b6cd9e0151cecf72896e Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 7 Jan 2026 10:38:10 +1100 Subject: [PATCH 736/746] New Crowdin updates (#742) * New translations app_en.arb (Turkish) * New translations app_en.arb (Persian) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Turkish) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Turkish) * New translations app_en.arb (Danish) * New translations app_en.arb (Danish) * New translations app_en.arb (Danish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Polish) * New translations app_en.arb (Romanian) * New translations app_en.arb (Romanian) * New translations app_en.arb (Danish) * New translations app_en.arb (Romanian) --- lib/l10n/da_DK/app_da_DK.arb | 936 +++++++++++++++++------------------ lib/l10n/es_MX/app_es_MX.arb | 6 +- lib/l10n/fa_IR/app_fa_IR.arb | 126 ++--- lib/l10n/pl_PL/app_pl_PL.arb | 2 +- lib/l10n/ro_RO/app_ro_RO.arb | 330 ++++++------ lib/l10n/tr_TR/app_tr_TR.arb | 110 ++-- lib/l10n/zh_CN/app_zh_CN.arb | 4 +- 7 files changed, 757 insertions(+), 757 deletions(-) diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 697846b..c05efb3 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -42,11 +42,11 @@ "@aspectRatio3x2": {}, "aspectRatio4x3": "4:3", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "Firkantet (1:1)", "@aspectRatioSquare": {}, "allocateStock": "Tildel lager", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "Allokeret Lager", "@allocatedStock": {}, "appReleaseNotes": "Vis app-udgivelsesnoter", "@appReleaseNotes": {}, @@ -54,9 +54,9 @@ "@appSettings": {}, "appSettingsDetails": "Konfigurer InvenTree app-indstillinger", "@appSettingsDetails": {}, - "assignedToMe": "Assigned to Me", + "assignedToMe": "Tildelt til Mig", "@assignedToMe": {}, - "assignedToMeDetail": "Show orders which are assigned to me", + "assignedToMeDetail": "Vis ordrer som er tildelt mig", "@assignedToMeDetail": {}, "attachments": "Vedhæftede filer", "@attachments": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "Stregkode skanning på pause", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "Tryk for at pause scanning", "@barcodeScanPause": {}, "barcodeScanAssign": "Scan for at tildele stregkode", "@barcodeScanAssign": {}, @@ -112,135 +112,135 @@ "@barcodeScanControllerDetail": {}, "barcodeScanDelay": "Forsinkelse Af Stregkode", "@barcodeScanDelay": {}, - "barcodeScanDelayDetail": "Delay between barcode scans", + "barcodeScanDelayDetail": "Forsinkelse mellem stregkode scanninger", "@barcodeScanDelayDetail": {}, - "barcodeScanGeneral": "Scan an InvenTree barcode", + "barcodeScanGeneral": "Scan en InvenTree stregkode", "@barcodeScanGeneral": {}, - "barcodeScanInItems": "Scan stock items into this location", + "barcodeScanInItems": "Scan lagervare ind på denne lokation", "@barcodeScanInItems": {}, - "barcodeScanLocation": "Scan stock location", + "barcodeScanLocation": "Scan lager lokation", "@barcodeScanLocation": {}, - "barcodeScanSingle": "Single Scan Mode", + "barcodeScanSingle": "Enkelt Scan Tilstand", "@barcodeScanSingle": {}, - "barcodeScanSingleDetail": "Pause barcode scanner after each scan", + "barcodeScanSingleDetail": "Sæt stregkodeskanneren på pause efter hver scanning", "@barcodeScanSingleDetail": {}, - "barcodeScanIntoLocationSuccess": "Scanned into location", + "barcodeScanIntoLocationSuccess": "Scannet ind i lokation", "@barcodeScanIntoLocationSuccess": {}, - "barcodeScanIntoLocationFailure": "Item not scanned in", + "barcodeScanIntoLocationFailure": "Element er ikke scannet ind", "@barcodeScanIntoLocationFailure": {}, - "barcodeScanItem": "Scan stock item", + "barcodeScanItem": "Scan lagervare", "@barcodeScanItem": {}, - "barcodeTones": "Barcode Tones", + "barcodeTones": "Stregkodetoner", "@barcodeTones": {}, - "barcodeUnassign": "Unassign Barcode", + "barcodeUnassign": "Frigiv Stregkode", "@barcodeUnassign": {}, - "barcodeUnknown": "Barcode is not recognized", + "barcodeUnknown": "Stregkode ikke genkendt", "@barcodeUnknown": {}, - "batchCode": "Batch Code", + "batchCode": "Batch kode", "@batchCode": {}, - "billOfMaterials": "Bill of Materials", + "billOfMaterials": "Stykliste", "@billOfMaterials": {}, - "bom": "BOM", + "bom": "Stykliste", "@bom": {}, - "bomEnable": "Display Bill of Materials", + "bomEnable": "Vis Stykliste", "@bomEnable": {}, - "build": "Build", + "build": "Byg", "@build": {}, - "building": "Building", + "building": "Bygger", "@building": {}, - "cameraCreationError": "Could not open camera controller", + "cameraCreationError": "Kunne ikke åbne kameracontrolleren", "@cameraCreationError": {}, - "cameraInternal": "Internal Camera", + "cameraInternal": "Internt Kamera", "@cameraInternal": {}, - "cameraInternalDetail": "Use internal camera to read barcodes", + "cameraInternalDetail": "Brug internt kamera til at læse stregkoder", "@cameraInternalDetail": {}, - "cancel": "Cancel", + "cancel": "Annuller", "@cancel": { "description": "Cancel" }, - "cancelOrder": "Cancel Order", + "cancelOrder": "Annuller ordre", "@cancelOrder": {}, - "category": "Category", + "category": "Kategori", "@category": {}, - "categoryCreate": "New Category", + "categoryCreate": "Ny kategori", "@categoryCreate": {}, - "categoryCreateDetail": "Create new part category", + "categoryCreateDetail": "Opret ny del kategori", "@categoryCreateDetail": {}, - "categoryUpdated": "Part category updated", + "categoryUpdated": "Del kategori opdateret", "@categoryUpdated": {}, - "company": "Company", + "company": "Firma", "@company": {}, - "companyAdd": "Add Company", + "companyAdd": "Tilføj firma", "@companyAdd": {}, - "companyEdit": "Edit Company", + "companyEdit": "Rediger virksomhed", "@companyEdit": {}, - "companyNoResults": "No companies matching query", + "companyNoResults": "Ingen virksomheder, der matcher forespørgsel", "@companyNoResults": {}, - "companyUpdated": "Company details updated", + "companyUpdated": "Virksomhedsoplysninger opdateret", "@companyUpdated": {}, - "companies": "Companies", + "companies": "Firmaer", "@companies": {}, - "complete": "Complete", + "complete": "Færdiggjort", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "Fuldfør ordre", "@completeOrder": {}, - "completionDate": "Completion Date", + "completionDate": "Færdiggørelsesdato", "@completionDate": {}, - "configureServer": "Configure server settings", + "configureServer": "Konfigurer serverindstillinger", "@configureServer": {}, - "confirmScan": "Confirm Transfer", + "confirmScan": "Bekræft overførsel", "@confirmScan": {}, - "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "confirmScanDetail": "Bekræft lageroverførsel detaljer ved scanning stregkoder", "@confirmScanDetail": {}, - "connectionRefused": "Connection Refused", + "connectionRefused": "Forbindelse Afvist", "@connectionRefused": {}, - "count": "Count", + "count": "Antal", "@count": { "description": "Count" }, - "countStock": "Count Stock", + "countStock": "Tæl Lager", "@countStock": { "description": "Count Stock" }, - "credits": "Credits", + "credits": "Anerkendelser", "@credits": {}, - "crop": "Crop", + "crop": "Beskær", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "Beskær billede", "@cropImage": {}, - "customer": "Customer", + "customer": "Kunde", "@customer": {}, - "customers": "Customers", + "customers": "Kunder", "@customers": {}, - "customerReference": "Customer Reference", + "customerReference": "Kundens Reference", "@customerReference": {}, - "damaged": "Damaged", + "damaged": "Beskadiget", "@damaged": {}, - "colorScheme": "Color Scheme", + "colorScheme": "Farveskema", "@colorScheme": {}, - "colorSchemeDetail": "Select color scheme", + "colorSchemeDetail": "Vælg farveskema", "@colorSchemeDetail": {}, - "darkMode": "Dark Mode", + "darkMode": "Mørk tilstand", "@darkMode": {}, - "darkModeEnable": "Enable dark mode", + "darkModeEnable": "Aktiver mørk tilstand", "@darkModeEnable": {}, - "delete": "Delete", + "delete": "Slet", "@delete": {}, - "deleteFailed": "Delete operation failed", + "deleteFailed": "Sletning fejlede", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "Er du sikker på at du vil slette dette billede?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "Slet billede", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "Slet billede", "@deleteImage": {}, - "deletePart": "Delete Part", + "deletePart": "Slet Del", "@deletePart": {}, - "deletePartDetail": "Remove this part from the database", + "deletePartDetail": "Fjern denne del fra databasen", "@deletePartDetail": {}, "deleteSuccess": "Sletning lykkedes", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "Leveringsdato", "@deliveryDate": {}, "description": "Beskrivelse", "@description": {}, @@ -254,9 +254,9 @@ }, "documentation": "Dokumentation", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "Download fuldført", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "Fejl ved download af billede", "@downloadError": {}, "downloading": "Overfører fil", "@downloading": {}, @@ -264,7 +264,7 @@ "@edit": { "description": "edit" }, - "editAttachment": "Edit Attachment", + "editAttachment": "Rediger Vedhæftning", "@editAttachment": {}, "editCategory": "Rediger kategori", "@editCategory": {}, @@ -282,91 +282,91 @@ "@editItem": {}, "editLineItem": "Rediger Linjeelement", "@editLineItem": {}, - "email": "Email", + "email": "E-mail", "@email": {}, "enterPassword": "Indtast adgangskode", "@enterPassword": {}, "enterUsername": "Indtast brugernavn", "@enterUsername": {}, - "error": "Error", + "error": "Fejl", "@error": { "description": "Error" }, - "errorCreate": "Error creating database entry", + "errorCreate": "Fejl under oprettelse af database post", "@errorCreate": {}, - "errorDelete": "Error deleting database entry", + "errorDelete": "Fejl ved sletning af databasepost", "@errorDelete": {}, - "errorDetails": "Error Details", + "errorDetails": "Fejldetaljer", "@errorDetails": {}, - "errorFetch": "Error fetching data from server", + "errorFetch": "Fejl ved hentning af data fra server", "@errorFetch": {}, - "errorUserRoles": "Error requesting user roles from server", + "errorUserRoles": "Fejl ved forespørgsel af brugerroller fra server", "@errorUserRoles": {}, - "errorPluginInfo": "Error requesting plugin data from server", + "errorPluginInfo": "Fejl ved forespørgsel af plugin data fra server", "@errorPluginInfo": {}, - "errorReporting": "Error Reporting", + "errorReporting": "Fejlrapportering", "@errorReporting": {}, - "errorReportUpload": "Upload Error Reports", + "errorReportUpload": "Upload Fejlrapporter", "@errorReportUpload": {}, - "errorReportUploadDetails": "Upload anonymous error reports and crash logs", + "errorReportUploadDetails": "Upload anonyme fejlrapporter og nedbrudslogs", "@errorReportUploadDetails": {}, - "expiryDate": "Expiry Date", + "expiryDate": "Udløbsdato", "@expiryDate": {}, - "expiryExpired": "Expired", + "expiryExpired": "Udløbet", "@expiryExpired": {}, - "expiryStale": "Stale", + "expiryStale": "Forældet", "@expiryStale": {}, - "extraLineItem": "Extra Line Item", + "extraLineItem": "Ekstra linjepost", "@extraLineItem": {}, - "extraLineItems": "Extra Line Items", + "extraLineItems": "Ekstra linjeposter", "@extraLineItems": {}, "feedback": "Feedback", "@feedback": {}, - "feedbackError": "Error submitting feedback", + "feedbackError": "Indsendelse af feedback mislykkedes", "@feedbackError": {}, - "feedbackSuccess": "Feedback submitted", + "feedbackSuccess": "Feedback indsendt", "@feedbackSuccess": {}, "filterActive": "Aktiv", "@filterActive": {}, - "filterActiveDetail": "Show active parts", + "filterActiveDetail": "Vis aktive dele", "@filterActiveDetail": {}, - "filterAssembly": "Assembled", + "filterAssembly": "Samlede", "@filterAssembly": {}, - "filterAssemblyDetail": "Show assembled parts", + "filterAssemblyDetail": "Vis samledele", "@filterAssemblyDetail": {}, - "filterComponent": "Component", + "filterComponent": "Komponent", "@filterComponent": {}, - "filterComponentDetail": "Show component parts", + "filterComponentDetail": "Vis komponentdele", "@filterComponentDetail": {}, - "filterExternal": "External", + "filterExternal": "Ekstern", "@filterExternal": {}, - "filterExternalDetail": "Show stock in external locations", + "filterExternalDetail": "Vis lager på eksterne lokationer", "@filterExternalDetail": {}, "filterInStock": "På Lager", "@filterInStock": {}, - "filterInStockDetail": "Show parts which have stock", + "filterInStockDetail": "Vis dele som har lagerbeholdning", "@filterInStockDetail": {}, - "filterSerialized": "Serialized", + "filterSerialized": "Serialiseret", "@filterSerialized": {}, - "filterSerializedDetail": "Show serialized stock items", + "filterSerializedDetail": "Vis serialiserede lagervarer", "@filterSerializedDetail": {}, - "filterTemplate": "Template", + "filterTemplate": "Skabelon", "@filterTemplate": {}, - "filterTemplateDetail": "Show template parts", + "filterTemplateDetail": "Vis skabelon dele", "@filterTemplateDetail": {}, - "filterTrackable": "Trackable", + "filterTrackable": "Sporbar", "@filterTrackable": {}, - "filterTrackableDetail": "Show trackable parts", + "filterTrackableDetail": "Vis sporbare dele", "@filterTrackableDetail": {}, "filterVirtual": "Virtuel", "@filterVirtual": {}, - "filterVirtualDetail": "Show virtual parts", + "filterVirtualDetail": "Vis virtuelle dele", "@filterVirtualDetail": {}, - "filteringOptions": "Filtering Options", + "filteringOptions": "Filtreringsindstillinger", "@filteringOptions": {}, - "formatException": "Format Exception", + "formatException": "Format Undtagelse", "@formatException": {}, - "formatExceptionJson": "JSON data format exception", + "formatExceptionJson": "Undtagelse fra JSON-dataformat", "@formatExceptionJson": {}, "formError": "Formular Fejl", "@formError": {}, @@ -384,51 +384,51 @@ "@homeShowPo": {}, "homeShowPoDescription": "Vis indkøbsordreknap på startskærmen", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "Vis Forsendelser", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "Vis afventende forsendelser på startskærmen", "@homeShowShipmentsDescription": {}, - "homeShowSo": "Show Sales Orders", + "homeShowSo": "Vis Salgs ordrer", "@homeShowSo": {}, - "homeShowSoDescription": "Show sales order button on home screen", + "homeShowSoDescription": "Vis salgsknap på startskærmen", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Subscribed Parts", + "homeShowSubscribed": "Abonnerede Dele", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "homeShowSubscribedDescription": "Vis abonnerede dele på startskærmen", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "Vis Leverandører", "@homeShowSuppliers": {}, - "homeShowSuppliersDescription": "Show suppliers button on home screen", + "homeShowSuppliersDescription": "Vis leverandørknap på startskærmen", "@homeShowSupplierDescription": {}, - "homeShowManufacturers": "Show Manufacturers", + "homeShowManufacturers": "Vis Producenter", "@homeShowManufacturers": {}, - "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "homeShowManufacturersDescription": "Vis producent-knap på startskærmen", "@homeShowManufacturersDescription": {}, - "homeShowCustomers": "Show Customers", + "homeShowCustomers": "Vis Kunder", "@homeShowCustomers": {}, - "homeShowCustomersDescription": "Show customers button on home screen", + "homeShowCustomersDescription": "Vis kunde-knap på startskærmen", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Image upload failed", + "imageUploadFailure": "Upload af billede fejlede", "@imageUploadFailure": {}, - "imageUploadSuccess": "Image uploaded", + "imageUploadSuccess": "Billede uploadet", "@imageUploadSuccess": {}, "inactive": "Inaktiv", "@inactive": {}, - "inactiveCompany": "This company is marked as inactive", + "inactiveCompany": "Virksomheden er markeret som inaktiv", "@inactiveCompany": {}, - "inactiveDetail": "This part is marked as inactive", + "inactiveDetail": "Denne del er markeret som inaktiv", "@inactiveDetail": {}, - "includeSubcategories": "Include Subcategories", + "includeSubcategories": "Inkluder underkategorier", "@includeSubcategories": {}, - "includeSubcategoriesDetail": "Show results from subcategories", + "includeSubcategoriesDetail": "Vis resultater fra underkategorier", "@includeSubcategoriesDetail": {}, - "includeSublocations": "Include Sublocations", + "includeSublocations": "Inkluder underlokationer", "@includeSublocations": {}, - "includeSublocationsDetail": "Show results from sublocations", + "includeSublocationsDetail": "Vis resultater fra underkategorier", "@includeSublocationsDetail": {}, - "incompleteDetails": "Incomplete profile details", + "incompleteDetails": "Ukomplette profiloplysninger", "@incompleteDetails": {}, - "internalPartNumber": "Internal Part Number", + "internalPartNumber": "Internt Delnummer", "@internalPartNumber": {}, "info": "Info", "@info": {}, @@ -438,9 +438,9 @@ "@inProductionDetail": {}, "internalPart": "Intern Del", "@internalPart": {}, - "invalidHost": "Invalid hostname", + "invalidHost": "Ugyldigt hostnavn", "@invalidHost": {}, - "invalidHostDetails": "Provided hostname is not valid", + "invalidHostDetails": "Det angivne hostnavn er ikke gyldigt", "@invalidHostDetails": {}, "invalidPart": "Ugyldig Del", "@invalidPart": {}, @@ -454,754 +454,754 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "Ugyldigt brugernavn/adgangskode-kombination", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "Faktura", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "Fakturanummer", "@invoiceNumber": {}, - "issue": "Issue", + "issue": "Problem", "@issue": {}, - "issueDate": "Issue Date", + "issueDate": "Udstedelsesdato", "@issueDate": {}, - "issueOrder": "Issue Order", + "issueOrder": "Udstede Ordre", "@issueOrder": {}, - "itemInLocation": "Item already in location", + "itemInLocation": "Element allerede på placering", "@itemInLocation": {}, - "itemDeleted": "Item has been removed", + "itemDeleted": "Element er blevet fjernet", "@itemDeleted": {}, - "itemUpdated": "Item updated", + "itemUpdated": "Element opdateret", "@itemUpdated": {}, - "keywords": "Keywords", + "keywords": "Nøgleord", "@keywords": {}, "labelDriver": "Label Driver", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "Vælg Label Printer Driver", "@labelSelectDriver": {}, - "labelPrinting": "Label Printing", + "labelPrinting": "Label Udskriver", "@labelPrinting": {}, - "labelPrintingDetail": "Enable label printing", + "labelPrintingDetail": "Aktiver label udskrivning", "@labelPrintingDetail": {}, - "labelTemplate": "Label Template", + "labelTemplate": "Label Skabelon", "@labelTemplate": {}, - "labelSelectTemplate": "Select Label Template", + "labelSelectTemplate": "Vælg Label Skabelon", "@labelSelectTemplate": {}, - "labelSelectPrinter": "Select Label Printer", + "labelSelectPrinter": "Vælg Label Printer", "@labelSelectPrinter": {}, - "language": "Language", + "language": "Sprog", "@language": {}, - "languageDefault": "Default system language", + "languageDefault": "Standard systemsprog", "@languageDefault": {}, - "languageSelect": "Select Language", + "languageSelect": "Vælg sprog", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", + "lastStocktake": "Sidste lageroptagelse", "@lastStocktake": {}, - "lastUpdated": "Last Updated", + "lastUpdated": "Senest opdateret", "@lastUpdated": {}, - "level": "Level", + "level": "Niveau", "@level": {}, - "lineItemAdd": "Add Line Item", + "lineItemAdd": "Tilføj Linjeelement", "@lineItemAdd": {}, - "lineItem": "Line Item", + "lineItem": "Linje Element", "@lineItem": {}, - "lineItems": "Line Items", + "lineItems": "Linjeelementer", "@lineItems": {}, - "lineItemUpdated": "Line item updated", + "lineItemUpdated": "Linje element opdateret", "@lineItemUpdated": {}, - "locateItem": "Locate stock item", + "locateItem": "Find lagervare", "@locateItem": {}, - "locateLocation": "Locate stock location", + "locateLocation": "Find lager lokation", "@locateLocation": {}, - "locationCreate": "New Location", + "locationCreate": "Ny lokation", "@locationCreate": {}, - "locationCreateDetail": "Create new stock location", + "locationCreateDetail": "Opret ny lagerlokation", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "Standard lokation", "@locationDefault": {}, - "locationNotSet": "No location specified", + "locationNotSet": "Ingen lokation specificeret", "@locationNotSet": {}, - "locationUpdated": "Stock location updated", + "locationUpdated": "Lager lokation opdateret", "@locationUpdated": {}, - "login": "Login", + "login": "Log ind", "@login": {}, - "loginEnter": "Enter login details", + "loginEnter": "Indtast login detaljer", "@loginEnter": {}, - "loginEnterDetails": "Username and password are not stored locally", + "loginEnterDetails": "Brugernavn og adgangskode er ikke gemt lokalt", "@loginEnterDetails": {}, "link": "Link", "@link": {}, - "lost": "Lost", + "lost": "Mistet", "@lost": {}, - "manufacturerPart": "Manufacturer Part", + "manufacturerPart": "Producent Del", "@manufacturerPart": {}, - "manufacturerPartEdit": "Edit Manufacturer Part", + "manufacturerPartEdit": "Rediger Producent Del", "@manufacturerPartEdit": {}, - "manufacturerPartNumber": "Manufacturer Part Number", + "manufacturerPartNumber": "Producent Delnummer", "@manufacturerPartNumber": {}, - "manufacturer": "Manufacturer", + "manufacturer": "Producent", "@manufacturer": {}, - "manufacturers": "Manufacturers", + "manufacturers": "Producenter", "@manufacturers": {}, - "missingData": "Missing Data", + "missingData": "Mangler data", "@missingData": {}, - "name": "Name", + "name": "Navn", "@name": {}, - "no": "No", + "no": "Nej", "@no": {}, "notApplicable": "N/A", "@notApplicable": {}, - "notConnected": "Not Connected", + "notConnected": "Ikke Forbundet", "@notConnected": {}, - "notes": "Notes", + "notes": "Noter", "@notes": { "description": "Notes" }, - "notifications": "Notifications", + "notifications": "Notifikationer", "@notifications": {}, - "notificationsEmpty": "No unread notifications", + "notificationsEmpty": "Ingen ulæste notifikationer", "@notificationsEmpty": {}, - "noResponse": "No Response from Server", + "noResponse": "Intet svar fra server", "@noResponse": {}, - "noResults": "No Results", + "noResults": "Ingen Resultater", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "Intet billede tilgængeligt", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Ingen priser tilgængelig", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Ingen prisdata fundet for denne del", "@noPricingDataFound": {}, - "noSubcategories": "No Subcategories", + "noSubcategories": "Ingen Underkategorier", "@noSubcategories": {}, - "noSubcategoriesAvailable": "No subcategories available", + "noSubcategoriesAvailable": "Ingen underkategorier tilgængelige", "@noSubcategoriesAvailable": {}, - "numberInvalid": "Invalid number", + "numberInvalid": "Ugyldigt nummer", "@numberInvalid": {}, - "onOrder": "On Order", + "onOrder": "På bestilling", "@onOrder": {}, - "onOrderDetails": "Items currently on order", + "onOrderDetails": "Elementer i øjeblikket på ordre", "@onOrderDetails": {}, - "orientation": "Screen Orientation", + "orientation": "Skærm Orientering", "@orientation": {}, - "orientationDetail": "Screen orientation (requires restart)", + "orientationDetail": "Skærm orientering (kræver genstart)", "@orientationDetail": {}, - "orientationLandscape": "Landscape", + "orientationLandscape": "Landskab", "@orientationLandscape": {}, - "orientationPortrait": "Portrait", + "orientationPortrait": "Portræt", "@orientationPortrait": {}, "orientationSystem": "System", "@orientationSystem": {}, - "outstanding": "Outstanding", + "outstanding": "Udestående", "@outstanding": {}, - "outstandingOrderDetail": "Show outstanding orders", + "outstandingOrderDetail": "Vis udestående ordrer", "@outstandingOrderDetail": {}, - "overdue": "Overdue", + "overdue": "Overskredet", "@overdue": {}, - "overdueDetail": "Show overdue orders", + "overdueDetail": "Vis forfaldne ordre", "@overdueDetail": {}, - "packaging": "Packaging", + "packaging": "Emballage", "@packaging": {}, - "packageName": "Package Name", + "packageName": "Pakkenavn", "@packageName": {}, - "parameters": "Parameters", + "parameters": "Parametre", "@parameters": {}, - "parametersSettingDetail": "Display part parameters", + "parametersSettingDetail": "Vis delparametre", "@parametersSettingDetail": {}, - "parent": "Parent", + "parent": "Overordnet", "@parent": {}, - "parentCategory": "Parent Category", + "parentCategory": "Overordnet kategori", "@parentCategory": {}, - "parentLocation": "Parent Location", + "parentLocation": "Overordnet Placering", "@parentLocation": {}, - "part": "Part", + "part": "Del", "@part": { "description": "Part (single)" }, - "partCreate": "New Part", + "partCreate": "Ny Del", "@partCreate": {}, - "partCreateDetail": "Create new part in this category", + "partCreateDetail": "Opret ny del i denne kategori", "@partCreateDetail": {}, - "partEdited": "Part updated", + "partEdited": "Del opdateret", "@partEdited": {}, - "parts": "Parts", + "parts": "Dele", "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Part not marked as salable", + "partNotSalable": "Del ikke markeret som salgbart", "@partNotSalable": {}, - "partsNone": "No Parts", + "partsNone": "Ingen Dele", "@partsNone": {}, - "partNoResults": "No parts matching query", + "partNoResults": "Ingen dele matcher forespørgsel", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Del Prisfastsættelse", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Vis delprisinformation", "@pricingSettingDetail": {}, - "partSettings": "Part Settings", + "partSettings": "Del Indstillinger", "@partSettings": {}, - "partsStarred": "Subscribed Parts", + "partsStarred": "Abonnerede Dele", "@partsStarred": {}, - "partsStarredNone": "No starred parts available", + "partsStarredNone": "Ingen markerede dele til rådighed", "@partsStarredNone": {}, - "partSuppliers": "Part Suppliers", + "partSuppliers": "Del Leverandører", "@partSuppliers": {}, - "partCategory": "Part Category", + "partCategory": "Del Kategori", "@partCategory": {}, - "partCategoryTopLevel": "Top level part category", + "partCategoryTopLevel": "Top niveau del kategori", "@partCategoryTopLevel": {}, - "partCategories": "Part Categories", + "partCategories": "Del Kategorier", "@partCategories": {}, - "partDetails": "Part Details", + "partDetails": "Del Detaljer", "@partDetails": {}, - "partNotes": "Part Notes", + "partNotes": "Del Noter", "@partNotes": {}, - "partStock": "Part Stock", + "partStock": "Del Lagerbeholdning", "@partStock": { "description": "part stock" }, - "password": "Password", + "password": "Adgangskode", "@password": {}, - "passwordEmpty": "Password cannot be empty", + "passwordEmpty": "Adgangskode kan ikke være tom", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "Afventende", "@pending": {}, - "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "permissionAccountDenied": "Din konto har ikke de nødvendige tilladelser til at udføre denne handling", "@permissionAccountDenied": {}, - "permissionRequired": "Permission Required", + "permissionRequired": "Tilladelse påkrævet", "@permissionRequired": {}, - "phone": "Phone", + "phone": "Telefon", "@phone": {}, - "printLabel": "Print Label", + "printLabel": "Udskriv label", "@printLabel": {}, "plugin": "Plugin", "@plugin": {}, "pluginPrinter": "Printer", "@pluginPrinter": {}, - "pluginSupport": "Plugin Support Enabled", + "pluginSupport": "Plugin Support Aktiveret", "@pluginSupport": {}, - "pluginSupportDetail": "The server supports custom plugins", + "pluginSupportDetail": "Serveren understøtter brugerdefinerede plugins", "@pluginSupportDetail": {}, - "printLabelFailure": "Label printing failed", + "printLabelFailure": "Label udskrivning mislykkedes", "@printLabelFailure": {}, - "printLabelSuccess": "Label sent to printer", + "printLabelSuccess": "Label sendt til printer", "@printLabelSuccess": {}, - "profile": "Profile", + "profile": "Profil", "@profile": {}, - "profileAdd": "Add Server Profile", + "profileAdd": "Tilføj Serverprofil", "@profileAdd": {}, - "profileConnect": "Connect to Server", + "profileConnect": "Opretter forbindelse til server", "@profileConnect": {}, - "profileEdit": "Edit Server Profile", + "profileEdit": "Rediger serverprofil", "@profileEdit": {}, - "profileDelete": "Delete Server Profile", + "profileDelete": "Slet Server Profil", "@profileDelete": {}, - "profileLogout": "Logout Profile", + "profileLogout": "Log Af Profil", "@profileLogout": {}, - "profileName": "Profile Name", + "profileName": "Profilnavn", "@profileName": {}, - "profileNone": "No profiles available", + "profileNone": "Ingen profiler til rådighed", "@profileNone": {}, - "profileNotSelected": "No Profile Selected", + "profileNotSelected": "Ingen Profil Valgt", "@profileNotSelected": {}, - "profileSelect": "Select InvenTree Server", + "profileSelect": "Vælg InvenTree Server", "@profileSelect": {}, - "profileSelectOrCreate": "Select server or create a new profile", + "profileSelectOrCreate": "Vælg server eller opret ny profil", "@profileSelectOrCreate": {}, - "profileTapToCreate": "Tap to create or select a profile", + "profileTapToCreate": "Tryk for at oprette eller vælge en profil", "@profileTapToCreate": {}, - "projectCode": "Project Code", + "projectCode": "Projektkode", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", + "purchaseOrderConfirmScan": "Bekræft Scanningsdata", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "purchaseOrderConfirmScanDetail": "Bekræft detaljer ved ind scanning af elementer", "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", + "purchaseOrderEnable": "Aktive Indkøbsordrer", "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", + "purchaseOrderEnableDetail": "Aktiver salgsordre funktionalitet", "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", + "purchaseOrderShowCamera": "Genvej Til Kamera", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "purchaseOrderShowCameraDetail": "Aktiver genvej til billedupload på købsordre skærmen", "@purchaseOrderShowCameraDetail": {}, - "purchaseOrder": "Purchase Order", + "purchaseOrder": "Købsordre", "@purchaseOrder": {}, - "purchaseOrderCreate": "New Purchase Order", + "purchaseOrderCreate": "Ny købsordre", "@purchaseOrderCreate": {}, - "purchaseOrderEdit": "Edit Purchase Order", + "purchaseOrderEdit": "Rediger Købsordre", "@purchaseOrderEdit": {}, - "purchaseOrderSettings": "Purchase order settings", + "purchaseOrderSettings": "Indstillinger for indkøbsordre", "@purchaseOrderSettings": {}, - "purchaseOrders": "Purchase Orders", + "purchaseOrders": "Indkøbsordrer", "@purchaseOrders": {}, - "purchaseOrderUpdated": "Purchase order updated", + "purchaseOrderUpdated": "Købsordre opdateret", "@purchaseOrderUpdated": {}, - "purchasePrice": "Purchase Price", + "purchasePrice": "Købspris", "@purchasePrice": {}, - "quantity": "Quantity", + "quantity": "Antal", "@quantity": { "description": "Quantity" }, - "quantityAvailable": "Quantity Available", + "quantityAvailable": "Antal Tilgængelig", "@quantityAvailable": {}, - "quantityEmpty": "Quantity is empty", + "quantityEmpty": "Antal er tomt", "@quantityEmpty": {}, - "quantityInvalid": "Quantity is invalid", + "quantityInvalid": "Antal er ugyldigt", "@quantityInvalid": {}, - "quantityPositive": "Quantity must be positive", + "quantityPositive": "Antallet skal være positivt", "@quantityPositive": {}, - "queryEmpty": "Enter search query", + "queryEmpty": "Indtast søgestreng", "@queryEmpty": {}, - "queryNoResults": "No results for query", + "queryNoResults": "Ingen resultater fundet", "@queryNoResults": {}, - "received": "Received", + "received": "Modtaget", "@received": {}, - "receivedFilterDetail": "Show received items", + "receivedFilterDetail": "Vis modtagne elementer", "@receivedFilterDetail": {}, - "receiveItem": "Receive Item", + "receiveItem": "Modtage Element", "@receiveItem": {}, - "receivedItem": "Received Stock Item", + "receivedItem": "Modtaget Lagervare", "@receivedItem": {}, "reference": "Reference", "@reference": {}, - "refresh": "Refresh", + "refresh": "Genindlæs", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "Roter 90° med uret", "@rotateClockwise": {}, - "refreshing": "Refreshing", + "refreshing": "Genindlæser", "@refreshing": {}, - "rejected": "Rejected", + "rejected": "Afvist", "@rejected": {}, "releaseNotes": "Release Notes", "@releaseNotes": {}, - "remove": "Remove", + "remove": "Fjern", "@remove": { "description": "remove" }, - "removeStock": "Remove Stock", + "removeStock": "Fjern Lagervarer", "@removeStock": { "description": "remove stock" }, - "reportBug": "Report Bug", + "reportBug": "Rapporter fejl", "@reportBug": {}, - "reportBugDescription": "Submit bug report (requires GitHub account)", + "reportBugDescription": "Indsend fejlrapport (kræver GitHub konto)", "@reportBugDescription": {}, - "responsible": "Responsible", + "responsible": "Ansvarlig", "@responsible": {}, - "results": "Results", + "results": "Resultater", "@results": {}, - "request": "Request", + "request": "Anmodning", "@request": {}, - "requestFailed": "Request Failed", + "requestFailed": "Anmodning fejlede", "@requestFailed": {}, - "requestSuccessful": "Request successful", + "requestSuccessful": "Anmodning succesfuld", "@requestSuccessful": {}, - "requestingData": "Requesting Data", + "requestingData": "Anmoder Data", "@requestingData": {}, - "required": "Required", + "required": "Påkrævet", "@required": { "description": "This field is required" }, - "response400": "Bad Request", + "response400": "Dårlig anmodning", "@response400": {}, - "response401": "Unauthorized", + "response401": "Uautoriseret", "@response401": {}, - "response403": "Permission Denied", + "response403": "Adgang nægtet", "@response403": {}, - "response404": "Resource Not Found", + "response404": "Ressource Ikke Fundet", "@response404": {}, - "response405": "Method Not Allowed", + "response405": "Metode ikke tilladt", "@response405": {}, - "response429": "Too Many Requests", + "response429": "For Mange Anmodninger", "@response429": {}, - "response500": "Internal Server Error", + "response500": "Intern serverfejl", "@response500": {}, - "response501": "Not Implemented", + "response501": "Ikke implementeret", "@response501": {}, - "response502": "Bad Gateway", + "response502": "Dårlig Gateway", "@response502": {}, - "response503": "Service Unavailable", + "response503": "Service er utilgængelig", "@response503": {}, "response504": "Gateway Timeout", "@response504": {}, - "response505": "HTTP Version Not Supported", + "response505": "HTTP-version understøttes ikke", "@response505": {}, - "responseData": "Response data", + "responseData": "Svardata", "@responseData": {}, - "responseInvalid": "Invalid Response Code", + "responseInvalid": "Ugyldig Svar Kode", "@responseInvalid": {}, - "responseUnknown": "Unknown Response", + "responseUnknown": "Ukendt Svar", "@responseUnknown": {}, - "result": "Result", + "result": "Resultat", "@result": { "description": "" }, - "returned": "Returned", + "returned": "Returneret", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Salgsordrer", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "Salgsordrer", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Aktiver Salgsordrer", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Aktiver salgsordre funktionalitet", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Genvej Til Kamera", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Aktiver genvej til billedupload til salgsordre på skærmen", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Indstillinger for salgsordre", "@salesOrderSettings": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Ny salgsordre", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Rediger Salgsordre", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Salgs ordre opdateret", "@salesOrderUpdated": {}, - "save": "Save", + "save": "Gem", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "Scan stregkode", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scan leverandørdel stregkode", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "Scan Til Placering", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Skan dette element til placering", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Ekstern Scanner", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Brug ekstern scanner til at læse stregkoder (kiletilstand)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Scan Modtagne Dele", "@scanReceivedParts": {}, - "search": "Search", + "search": "Søg", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Søger", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "Søg efter lokation", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "Søg efter dele", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "Søg Lager", "@searchStock": {}, - "select": "Select", + "select": "Vælg", "@select": {}, - "selectFile": "Select File", + "selectFile": "Vælg fil", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Vælg billede", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Vælg en placering", "@selectLocation": {}, "send": "Send", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Serienummer", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Serienummer", "@serialNumbers": {}, "server": "Server", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Serveradresse", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Kræver API-version", "@serverApiRequired": {}, "serverApiVersion": "Server API Version", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Autentificeringsfejl", "@serverAuthenticationError": {}, - "serverCertificateError": "Cerficate Error", + "serverCertificateError": "Certifikatfejl", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Server HTTPS certifikat er ugyldigt", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Forbundet til server", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Opretter forbindelse til server", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Kunne ikke forbinde til server", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Serveren kan ikke være tom", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Serverfejl", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Server detaljer", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "Server svar mangler obligatoriske felter", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Gammel Server Version", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Server indstillinger", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Server skal starte med http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Indstillinger", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Server Instans", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Server ikke forbundet", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Server ikke valgt", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Forsendelse", "@shipment": {}, - "shipments": "Shipments", + "shipments": "Forsendelser", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Afventer Forsendelser", "@shipmentsPending": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Tilføj Forsendelse", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Tjek Forsendelse", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Marker denne forsendelse som kontrolleret", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Forsendelse Kontrolleret", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Afsendelsesdato", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Rediger Forsendelse", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Forsendelse Reference", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Send Forsendelse", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Afmarkér Forsendelse", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Marker denne forsendelse som afmarkeret", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Forsendelse Opdateret", "@shipmentUpdated": {}, - "shipped": "Shipped", + "shipped": "Afsendt", "@shipped": {}, - "sku": "SKU", + "sku": "Lagerbeholdning", "@sku": {}, - "sounds": "Sounds", + "sounds": "Lyde", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Afspil hørbar tone ved stregkodehandling", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Afspil akustisk tone ved serverfejl", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Startdato", "@startDate": {}, "status": "Status", "@status": {}, - "statusCode": "Status Code", + "statusCode": "Status Kode", "@statusCode": {}, - "stock": "Stock", + "stock": "Lager", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Aktuel disponibel lagermængde", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "Lagervarer", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "Lagervarer", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "Ny Lagervare", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "Opret ny lagervare på denne lokation", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "Slet Lagervare", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Er du sikker på, at du vil slette denne lagervare?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "Kunne ikke slette lagervare", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "Lagervare slettet", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "Lager Historik", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Vis historisk lagersporings information", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "Lagervare overført", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "Lagervare opdateret", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "Ingen lagervarer tilgængelige", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "Lager Vare Noter", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "Lagervare opdateret", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "Lagervare opdatering mislykkedes", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "Lagerlokationer", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "Lagerlokationer", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "Top niveau lager lokation", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Brug Streng HTTPS", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Håndhæve streng kontrol af HTTPS-certifikater", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "Underkategori", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "Underkategorier", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "Under lokation", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "Under lokationer", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "Ingen under lokationer", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "Ingen under lokationer tilgængelige", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "Indsend feedback", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "Leveret Dele", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "Leverandør", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Leverandør Del", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Rediger Leverandør Del", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Leverandør Delnummer", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Leverandør Del Opdateret", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Leverandør Dele", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "Leverandør", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "Leverandør Reference", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Skift Kamera", "@switchCamera": {}, - "takePicture": "Take Picture", + "takePicture": "Tag billede", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "Måldato", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "Overordnet Skabelon Del", "@templatePart": {}, - "testName": "Test Name", + "testName": "Test navn", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "Test bestået eller fejlet", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "Påkrævede Test", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "Testresultater", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Vis testresultater for lagervarer", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "Tilføj Testresultat", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "Ingen Testresultater", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "Ingen testresultater tilgængelige", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "Fejl under upload af testresultat", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "Test resultat uploadet", "@testResultUploadPass": {}, "timeout": "Timeout", "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Tænd/sluk lys", "@toggleTorch": {}, - "tokenError": "Token Error", + "tokenError": "Token Fejl", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "Mangler Token", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "Adgangstoken mangler fra svar", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Total Pris", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Sporingsnummer", "@trackingNumber": {}, - "transfer": "Transfer", + "transfer": "Overfør", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "Overfør Lager", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "Overfør element til en anden lokation", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Overføre lager lokation", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Overfør denne lager lokation til en anden", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "Oversæt", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "Hjælp med at oversætte InvenTree appen", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Utilgængelig", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Elementet er ikke tilgængeligt", "@unavailableDetail": {}, - "unitPrice": "Unit Price", + "unitPrice": "Enhedspris", "@unitPrice": {}, - "units": "Units", + "units": "Enheder", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "Ukendt Svar", "@unknownResponse": {}, "upload": "Upload", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "File upload mislykkedes", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "Fil uploadet", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Upload billede", "@uploadImage": {}, - "usedIn": "Used In", + "usedIn": "Brugt I", "@usedIn": {}, - "usedInDetails": "Assemblies which require this part", + "usedInDetails": "Samlinger som kræver denne del", "@usedInDetails": {}, - "username": "Username", + "username": "Brugernavn", "@username": {}, - "usernameEmpty": "Username cannot be empty", + "usernameEmpty": "Brugernavn kan ikke være tomt", "@usernameEmpty": {}, - "value": "Value", + "value": "Værdi", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "Værdien kan ikke være tom", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "Værdi er påkrævet", "@valueRequired": {}, - "variants": "Variants", + "variants": "Varianter", "@variants": {}, "version": "Version", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "Vis Leverandør Del", "@viewSupplierPart": {}, - "website": "Website", + "website": "Hjemmeside", "@website": {}, - "yes": "Yes", + "yes": "Ja", "@yes": {}, - "price": "Price", + "price": "Pris", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Prisklasse", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Tilsidesættelse af minimumspris", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Tilsidesættelse af maksimalpris", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Salgspris", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Salgs Historik", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Leverandør Pris", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Stykliste Pris", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Intern Omkostning", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Variant Pris", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Samlet prisfastsættelse", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Tilsidesætter Prisfastsættelse", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Valuta", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Prispauser", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 4f0ec84..1197082 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -962,7 +962,7 @@ "@shipmentReference": {}, "shipmentSend": "Send Shipment", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Deseleccionar Envío", "@shipmentUncheck": {}, "shipmentUncheckDetail": "Mark this shipment as unchecked", "@shipmentUncheckDetail": {}, @@ -1068,7 +1068,7 @@ "@suppliers": {}, "supplierReference": "Referencia del proveedor", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Cambiar Cámara", "@switchCamera": {}, "takePicture": "Tomar una foto", "@takePicture": {}, @@ -1148,7 +1148,7 @@ "@uploadFailed": {}, "uploadSuccess": "Archivo subido", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Subir Imagen", "@uploadImage": {}, "usedIn": "Usado en", "@usedIn": {}, diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 02358b0..ceb836d 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -36,17 +36,17 @@ "@appDetails": {}, "allocated": "اختصاص داده شده", "@allocated": {}, - "aspectRatio16x9": "16:9", + "aspectRatio16x9": "۱۶ به ۹", "@aspectRatio16x9": {}, - "aspectRatio3x2": "3:2", + "aspectRatio3x2": "۳ به ۲", "@aspectRatio3x2": {}, - "aspectRatio4x3": "4:3", + "aspectRatio4x3": "۴ به ۳", "@aspectRatio4x3": {}, - "aspectRatioSquare": "Square (1:1)", + "aspectRatioSquare": "مربعی (۱ به ۱)", "@aspectRatioSquare": {}, "allocateStock": "موجودی اختصاص داده شده", "@allocateStock": {}, - "allocatedStock": "Allocated Stock", + "allocatedStock": "موجودی اختصاص داده شده", "@allocatedStock": {}, "appReleaseNotes": "نمایش یادداشت های انتشار برنامه", "@appReleaseNotes": {}, @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "اسکن بارکد متوقف شد", "@barodeScanPaused": {}, - "barcodeScanPause": "Tap to pause scanning", + "barcodeScanPause": "برای توقف اسکن لمس کنید", "@barcodeScanPause": {}, "barcodeScanAssign": "برای اختصاص بارکد اسکن کنید", "@barcodeScanAssign": {}, @@ -180,9 +180,9 @@ "@companyUpdated": {}, "companies": "شرکت‌ها", "@companies": {}, - "complete": "Complete", + "complete": "تکمیل", "@complete": {}, - "completeOrder": "Complete Order", + "completeOrder": "تکمیل سفارش", "@completeOrder": {}, "completionDate": "تاریخ تکمیل", "@completionDate": {}, @@ -204,9 +204,9 @@ }, "credits": "اعتبارات", "@credits": {}, - "crop": "Crop", + "crop": "برش", "@crop": {}, - "cropImage": "Crop Image", + "cropImage": "برش تصویر", "@cropImage": {}, "customer": "مشتری", "@customer": {}, @@ -228,11 +228,11 @@ "@delete": {}, "deleteFailed": "عملیات حذف ناموفق بوده است", "@deleteFailed": {}, - "deleteImageConfirmation": "Are you sure you want to delete this image?", + "deleteImageConfirmation": "آیا مطمئن هستید که میخواهید این تصویر را حذف کنید؟", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Delete Image", + "deleteImageTooltip": "حذف تصویر", "@deleteImageTooltip": {}, - "deleteImage": "Delete Image", + "deleteImage": "حذف تصویر", "@deleteImage": {}, "deletePart": "حذف قسمت", "@deletePart": {}, @@ -240,7 +240,7 @@ "@deletePartDetail": {}, "deleteSuccess": "عملیات حذف با موفقیت انجام شد", "@deleteSuccess": {}, - "deliveryDate": "Delivery Date", + "deliveryDate": "تاریخ تحویل", "@deliveryDate": {}, "description": "توضیحات", "@description": {}, @@ -254,9 +254,9 @@ }, "documentation": "مستندات", "@documentation": {}, - "downloadComplete": "Download Complete", + "downloadComplete": "دانلود انجام شد", "@downloadComplete": {}, - "downloadError": "Error downloading image", + "downloadError": "خطای دانلود تصویر", "@downloadError": {}, "downloading": "در حال دانلود فایل", "@downloading": {}, @@ -282,7 +282,7 @@ "@editItem": {}, "editLineItem": "ویرایش ایتم خط", "@editLineItem": {}, - "email": "Email", + "email": "پست الکترونیکی", "@email": {}, "enterPassword": "رمز عبور را وارد کنید", "@enterPassword": {}, @@ -384,9 +384,9 @@ "@homeShowPo": {}, "homeShowPoDescription": "نمایش دکمه سفارش خرید در صفحه خانه", "@homeShowPoDescription": {}, - "homeShowShipments": "Show Shipments", + "homeShowShipments": "نمایش محموله", "@homeShowShipments": {}, - "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "homeShowShipmentsDescription": "نمایش محموله در انتظار ارسال بر روی صفحه اصلی", "@homeShowShipmentsDescription": {}, "homeShowSo": "نمایش سفارش های فروش", "@homeShowSo": {}, @@ -454,9 +454,9 @@ "@invalidSupplierPart": {}, "invalidUsernamePassword": "ترکیب نام کاربری / رمز عبور نامعتبر", "@invalidUsernamePassword": {}, - "invoice": "Invoice", + "invoice": "صورت‌حساب", "@invoice": {}, - "invoiceNumber": "Invoice Number", + "invoiceNumber": "شماره صورت‌حساب", "@invoiceNumber": {}, "issue": "موضوع", "@issue": {}, @@ -472,9 +472,9 @@ "@itemUpdated": {}, "keywords": "کلمات کلیدی", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "درایور چاپگر برچسب", "@labelDriver": {}, - "labelSelectDriver": "Select Label Printer Driver", + "labelSelectDriver": "انتخاب درایور چاپگر برچسب", "@labelSelectDriver": {}, "labelPrinting": "چاپ لیبل", "@labelPrinting": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "مکان سهام جدید ایجاد کنید", "@locationCreateDetail": {}, - "locationDefault": "Default Location", + "locationDefault": "مکان پیش‌فرض", "@locationDefault": {}, "locationNotSet": "هیچ مکانی مشخص نشده است", "@locationNotSet": {}, @@ -544,9 +544,9 @@ "@missingData": {}, "name": "نام", "@name": {}, - "no": "No", + "no": "خیر", "@no": {}, - "notApplicable": "N/A", + "notApplicable": "موجود نیست", "@notApplicable": {}, "notConnected": "متصل نیست", "@notConnected": {}, @@ -562,11 +562,11 @@ "@noResponse": {}, "noResults": "بدون نتیجه", "@noResults": {}, - "noImageAvailable": "No image available", + "noImageAvailable": "هیچ تصویری موجود نیست", "@noImageAvailable": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "هیچ قیمتی موجود نیست", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "هیچ اطلاعات قیمتی برای این قطعه یافت نشد", "@noPricingDataFound": {}, "noSubcategories": "بدون زیر دسته بندی", "@noSubcategories": {}, @@ -630,9 +630,9 @@ "@partsNone": {}, "partNoResults": "هیچ قطعه ای مطابق با جست و جو یافت نشد", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "قیمت‌گذاری قطعات", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "نمایش اطلاعات قیمت‌گذاری قطعات", "@pricingSettingDetail": {}, "partSettings": "تنظیمات قطعه", "@partSettings": {}, @@ -660,13 +660,13 @@ "@password": {}, "passwordEmpty": "رمز عبور نمی تواند خالی باشد", "@passwordEmpty": {}, - "pending": "Pending", + "pending": "در حال بررسی", "@pending": {}, "permissionAccountDenied": "حساب شما مجوزهای لازم برای انجام این عمل را ندارد", "@permissionAccountDenied": {}, "permissionRequired": "نیازمند مجوز", "@permissionRequired": {}, - "phone": "Phone", + "phone": "تماس", "@phone": {}, "printLabel": "پرینت برچسب", "@printLabel": {}, @@ -762,7 +762,7 @@ "@reference": {}, "refresh": "تازه سازی", "@refresh": {}, - "rotateClockwise": "Rotate 90° clockwise", + "rotateClockwise": "چرخش °90 درجه در جهت عقربه های ساعت", "@rotateClockwise": {}, "refreshing": "در حال تازه سازی", "@refreshing": {}, @@ -940,33 +940,33 @@ "@serverNotConnected": {}, "serverNotSelected": "سرور انتخاب نشده است", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "محموله", "@shipment": {}, "shipments": "محموله ها", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "محموله در انتظار ارسال", "@shipmentsPending": {}, "shipmentAdd": "افزودن محموله", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "بررسی محموله", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "این محموله را بررسی شده علامت گذاری کن", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "محموله بررسی شده", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "تاریخ ارسال", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "تغییر محموله", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "کد محموله", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "ارسال محموله", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "محموله بررسی نشده", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "این محموله را بررسی نشده علامت گذاری کن", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "محموله به روز رسانی شد", "@shipmentUpdated": {}, "shipped": "ارسال شده", "@shipped": {}, @@ -1112,7 +1112,7 @@ "@tokenMissingFromResponse": {}, "totalPrice": "قیمت کل", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "کد رهگیری", "@trackingNumber": {}, "transfer": "انتقال", "@transfer": { @@ -1148,7 +1148,7 @@ "@uploadFailed": {}, "uploadSuccess": "فایل اپلود شد", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "بارگذاری تصویر", "@uploadImage": {}, "usedIn": "استفاده شده در", "@usedIn": {}, @@ -1174,34 +1174,34 @@ "@viewSupplierPart": {}, "website": "وب سایت", "@website": {}, - "yes": "Yes", + "yes": "بله", "@yes": {}, - "price": "Price", + "price": "قیمت", "@price": {}, - "priceRange": "Price Range", + "priceRange": "بازه‌ قیمت", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "قیمت دستی مینیمم", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "قیمت دستی ماکزیمم", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "قیمت حراج", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "تاریخچه حراج", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "قیمت تامین کننده", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "هزینه تمام شده", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "هزینه داخلی", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "هزینه متغیر", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "قیمت نهایی", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "قیمت دستی", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "واحد پول", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "کاهش قیمت", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index ac7a6c2..5aa8e5c 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -1202,6 +1202,6 @@ "@pricingOverrides": {}, "currency": "Waluta", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Widełki cenowe", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 6f07c0d..adfed52 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -834,374 +834,374 @@ }, "returned": "Returnat", "@returned": {}, - "salesOrder": "Sales Order", + "salesOrder": "Comenzi de Vânzare", "@salesOrder": {}, - "salesOrders": "Sales Orders", + "salesOrders": "Comenzi de Vânzare", "@salesOrders": {}, - "salesOrderEnable": "Enable Sales Orders", + "salesOrderEnable": "Activează Comenzile de Vânzări", "@salesOrderEnable": {}, - "salesOrderEnableDetail": "Enable sales order functionality", + "salesOrderEnableDetail": "Activați funcționalitatea comenzilor de vânzare", "@salesOrderEnableDetail": {}, - "salesOrderShowCamera": "Camera Shortcut", + "salesOrderShowCamera": "Scurtătura Cameră", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "salesOrderShowCameraDetail": "Activează scurtătura de încărcare a imaginilor pe ecranul comenzii de vânzare", "@salesOrderShowCameraDetail": {}, - "salesOrderSettings": "Sales order settings", + "salesOrderSettings": "Setările comenzii de vânzare", "@salesOrderSettings": {}, - "salesOrderCreate": "New Sales Order", + "salesOrderCreate": "Comandă de vânzări nouă", "@saleOrderCreate": {}, - "salesOrderEdit": "Edit Sales Order", + "salesOrderEdit": "Editează Comanda de Vânzare", "@salesOrderEdit": {}, - "salesOrderUpdated": "Sales order updated", + "salesOrderUpdated": "Comanda de vanzare actualizată", "@salesOrderUpdated": {}, - "save": "Save", + "save": "Salvaţi", "@save": { "description": "Save" }, - "scanBarcode": "Scan Barcode", + "scanBarcode": "Scanați codul de bare", "@scanBarcode": {}, - "scanSupplierPart": "Scan supplier part barcode", + "scanSupplierPart": "Scanare cod de bare furnizor", "@scanSupplierPart": {}, - "scanIntoLocation": "Scan Into Location", + "scanIntoLocation": "Scanare în locație", "@scanIntoLocation": {}, - "scanIntoLocationDetail": "Scan this item into location", + "scanIntoLocationDetail": "Scanează acest articol în locație", "@scanIntoLocationDetail": {}, - "scannerExternal": "External Scanner", + "scannerExternal": "Scanner extern", "@scannerExternal": {}, - "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "scannerExternalDetail": "Utilizează scanerul extern pentru a citi codurile de bare (modul wedge)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Scan Received Parts", + "scanReceivedParts": "Scanați capitolele primite", "@scanReceivedParts": {}, - "search": "Search", + "search": "Caută", "@search": { "description": "search" }, - "searching": "Searching", + "searching": "Căutare", "@searching": {}, - "searchLocation": "Search for location", + "searchLocation": "Căutați locația", "@searchLocation": {}, - "searchParts": "Search Parts", + "searchParts": "Caută componente", "@searchParts": {}, - "searchStock": "Search Stock", + "searchStock": "Căutare Stoc", "@searchStock": {}, - "select": "Select", + "select": "Selectează", "@select": {}, - "selectFile": "Select File", + "selectFile": "Selectează fișier", "@selectFile": {}, - "selectImage": "Select Image", + "selectImage": "Selectează imagine", "@selectImage": {}, - "selectLocation": "Select a location", + "selectLocation": "Selectați o locație", "@selectLocation": {}, - "send": "Send", + "send": "Trimite", "@send": {}, - "serialNumber": "Serial Number", + "serialNumber": "Număr de serie", "@serialNumber": {}, - "serialNumbers": "Serial Numbers", + "serialNumbers": "Număr de serie", "@serialNumbers": {}, "server": "Server", "@server": {}, - "serverAddress": "Server Address", + "serverAddress": "Adresă server", "@serverAddress": {}, - "serverApiRequired": "Required API Version", + "serverApiRequired": "Versiunea API necesară", "@serverApiRequired": {}, - "serverApiVersion": "Server API Version", + "serverApiVersion": "Versiune API server", "@serverApiVersion": {}, - "serverAuthenticationError": "Authentication Error", + "serverAuthenticationError": "Eroare autentificare", "@serverAuthenticationError": {}, "serverCertificateError": "Cerficate Error", "@serverCertificateError": {}, - "serverCertificateInvalid": "Server HTTPS certificate is invalid", + "serverCertificateInvalid": "Certificatul HTTPS al serverului nu este valid", "@serverCertificateInvalid": {}, - "serverConnected": "Connected to Server", + "serverConnected": "Conectare la server", "@serverConnected": {}, - "serverConnecting": "Connecting to server", + "serverConnecting": "Se conecteaza la server", "@serverConnecting": {}, - "serverCouldNotConnect": "Could not connect to server", + "serverCouldNotConnect": "Nu s-a putut conecta la server", "@serverCouldNotConnect": {}, - "serverEmpty": "Server cannot be empty", + "serverEmpty": "Serverul nu poate fi gol", "@serverEmpty": {}, - "serverError": "Server Error", + "serverError": "Eroare de server", "@serverError": {}, - "serverDetails": "Server Details", + "serverDetails": "Detalii despre server", "@serverDetails": {}, - "serverMissingData": "Server response missing required fields", + "serverMissingData": "Răspuns server lipsă câmpuri obligatorii", "@serverMissingData": {}, - "serverOld": "Old Server Version", + "serverOld": "Versiunea veche a serverului", "@serverOld": {}, - "serverSettings": "Server Settings", + "serverSettings": "Setări server", "@serverSettings": {}, - "serverStart": "Server must start with http[s]", + "serverStart": "Serverul trebuie să înceapă cu http[s]", "@serverStart": {}, - "settings": "Settings", + "settings": "Setări", "@settings": {}, - "serverInstance": "Server Instance", + "serverInstance": "Instanță server", "@serverInstance": {}, - "serverNotConnected": "Server not connected", + "serverNotConnected": "Serverul nu este conectat", "@serverNotConnected": {}, - "serverNotSelected": "Server not selected", + "serverNotSelected": "Serverul nu este selectat", "@serverNotSelected": {}, - "shipment": "Shipment", + "shipment": "Expediere", "@shipment": {}, - "shipments": "Shipments", + "shipments": "Livrări", "@shipments": {}, - "shipmentsPending": "Pending Shipments", + "shipmentsPending": "Livrări în așteptare", "@shipmentsPending": {}, - "shipmentAdd": "Add Shipment", + "shipmentAdd": "Adaugă livrare", "@shipmentAdd": {}, - "shipmentCheck": "Check Shipment", + "shipmentCheck": "Verifica livrare", "@shipmentCheck": {}, - "shipmentCheckDetail": "Mark this shipment as checked", + "shipmentCheckDetail": "Marchează livrarea ca verificată", "@shipmentCheckDetail": {}, - "shipmentChecked": "Shipment Checked", + "shipmentChecked": "Livrare verificată", "@shipmentChecked": {}, - "shipmentDate": "Shipment Date", + "shipmentDate": "Data livrării", "@shipmentDate": {}, - "shipmentEdit": "Edit Shipment", + "shipmentEdit": "Editare livrare", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Referință livrare", "@shipmentReference": {}, - "shipmentSend": "Send Shipment", + "shipmentSend": "Livrare Trimisa", "@shipmentSend": {}, - "shipmentUncheck": "Uncheck Shipment", + "shipmentUncheck": "Debifează livrare", "@shipmentUncheck": {}, - "shipmentUncheckDetail": "Mark this shipment as unchecked", + "shipmentUncheckDetail": "Marchează livrarea ca nebifat", "@shipmentUncheckDetail": {}, - "shipmentUpdated": "Shipment Updated", + "shipmentUpdated": "Livrare actualizată", "@shipmentUpdated": {}, - "shipped": "Shipped", + "shipped": "Livrat", "@shipped": {}, "sku": "SKU", "@sku": {}, - "sounds": "Sounds", + "sounds": "Sunete", "@sounds": {}, - "soundOnBarcodeAction": "Play audible tone on barcode action", + "soundOnBarcodeAction": "Redă ton sonor la acțiunea codului de bare", "@soundOnBarcodeAction": {}, - "soundOnServerError": "Play audible tone on server error", + "soundOnServerError": "Redă sunetul sonor la eroarea serverului", "@soundOnServerError": {}, - "startDate": "Start Date", + "startDate": "Data inceput", "@startDate": {}, "status": "Status", "@status": {}, "statusCode": "Status Code", "@statusCode": {}, - "stock": "Stock", + "stock": "Stoc", "@stock": { "description": "stock" }, - "stockDetails": "Current available stock quantity", + "stockDetails": "Stoc disponibil curent", "@stockDetails": {}, - "stockItem": "Stock Item", + "stockItem": "Articol Stoc", "@stockItem": { "description": "stock item title" }, - "stockItems": "Stock Items", + "stockItems": "Articol Stoc", "@stockItems": {}, - "stockItemCreate": "New Stock Item", + "stockItemCreate": "Element nou în stoc", "@stockItemCreate": {}, - "stockItemCreateDetail": "Create new stock item in this location", + "stockItemCreateDetail": "Crează element nou în stoc în această locație", "@stockItemCreateDetail": {}, - "stockItemDelete": "Delete Stock Item", + "stockItemDelete": "Şterge elementul din stoc", "@stockItemDelete": {}, - "stockItemDeleteConfirm": "Are you sure you want to delete this stock item?", + "stockItemDeleteConfirm": "Sunteţi sigur că doriţi să ştergeţi acest articol din stoc?", "@stockItemDeleteConfirm": {}, - "stockItemDeleteFailure": "Could not delete stock item", + "stockItemDeleteFailure": "Nu s-a putut șterge articolul din stoc", "@stockItemDeleteFailure": {}, - "stockItemDeleteSuccess": "Stock item deleted", + "stockItemDeleteSuccess": "Articol șters", "@stockItemDeleteSuccess": {}, - "stockItemHistory": "Stock History", + "stockItemHistory": "Istoric Stoc", "@stockItemHistory": {}, - "stockItemHistoryDetail": "Display historical stock tracking information", + "stockItemHistoryDetail": "Afişează informaţii istorice de urmărire stoc", "@stockItemHistoryDetail": {}, - "stockItemTransferred": "Stock item transferred", + "stockItemTransferred": "Articol stoc transferat", "@stockItemTransferred": {}, - "stockItemUpdated": "Stock item updated", + "stockItemUpdated": "Articol stoc actualizat", "@stockItemUpdated": {}, - "stockItemsNotAvailable": "No stock items available", + "stockItemsNotAvailable": "Nu sunt articole disponibile în stoc", "@stockItemsNotAvailable": {}, - "stockItemNotes": "Stock Item Notes", + "stockItemNotes": "Note element de stoc", "@stockItemNotes": {}, - "stockItemUpdateSuccess": "Stock item updated", + "stockItemUpdateSuccess": "Articol stoc actualizat", "@stockItemUpdateSuccess": {}, - "stockItemUpdateFailure": "Stock item update failed", + "stockItemUpdateFailure": "Actualizarea articolului stoc a eșuat", "@stockItemUpdateFailure": {}, - "stockLocation": "Stock Location", + "stockLocation": "Locația stocului", "@stockLocation": { "description": "stock location" }, - "stockLocations": "Stock Locations", + "stockLocations": "Locația stocului", "@stockLocations": {}, - "stockTopLevel": "Top level stock location", + "stockTopLevel": "Locație stoc nivel superior", "@stockTopLevel": {}, - "strictHttps": "Use Strict HTTPS", + "strictHttps": "Folosește HTTPS Strict", "@strictHttps": {}, - "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "strictHttpsDetails": "Impune controlul strict al certificatelor HTTP", "@strictHttpsDetails": {}, - "subcategory": "Subcategory", + "subcategory": "Subcategorie", "@subcategory": {}, - "subcategories": "Subcategories", + "subcategories": "Subcategorii", "@subcategories": {}, - "sublocation": "Sublocation", + "sublocation": "Sublocare", "@sublocation": {}, - "sublocations": "Sublocations", + "sublocations": "Sublocare", "@sublocations": {}, - "sublocationNone": "No Sublocations", + "sublocationNone": "Fără sublocări", "@sublocationNone": {}, - "sublocationNoneDetail": "No sublocations available", + "sublocationNoneDetail": "Nu există sublocații disponibile", "@sublocationNoneDetail": {}, - "submitFeedback": "Submit Feedback", + "submitFeedback": "Trimiteți feedback", "@submitFeedback": {}, - "suppliedParts": "Supplied Parts", + "suppliedParts": "Piese furnizate", "@suppliedParts": {}, - "supplier": "Supplier", + "supplier": "Furnizor", "@supplier": {}, - "supplierPart": "Supplier Part", + "supplierPart": "Piesă Furnizor", "@supplierPart": {}, - "supplierPartEdit": "Edit Supplier Part", + "supplierPartEdit": "Editați articol furnizorului", "@supplierPartEdit": {}, - "supplierPartNumber": "Supplier Part Number", + "supplierPartNumber": "Cod furnizor", "@supplierPartNumber": {}, - "supplierPartUpdated": "Supplier Part Updated", + "supplierPartUpdated": "Cod furnizor actualizat", "@supplierPartUpdated": {}, - "supplierParts": "Supplier Parts", + "supplierParts": "Piese Furnizor", "@supplierParts": {}, - "suppliers": "Suppliers", + "suppliers": "Furnizori", "@suppliers": {}, - "supplierReference": "Supplier Reference", + "supplierReference": "Cod furnizor", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Comutați Camera", "@switchCamera": {}, - "takePicture": "Take Picture", + "takePicture": "Faceți o fotografie", "@takePicture": {}, - "targetDate": "Target Date", + "targetDate": "Data țintă", "@targetDate": {}, - "templatePart": "Parent Template Part", + "templatePart": "Capitol șablon părinte", "@templatePart": {}, - "testName": "Test Name", + "testName": "Nume test", "@testName": {}, - "testPassedOrFailed": "Test passed or failed", + "testPassedOrFailed": "Testul a trecut sau a eșuat", "@testPassedOrFailed": {}, - "testsRequired": "Required Tests", + "testsRequired": "Teste necesare", "@testsRequired": {}, - "testResults": "Test Results", + "testResults": "Rezultatele testului", "@testResults": { "description": "" }, - "testResultsDetail": "Display stock item test results", + "testResultsDetail": "Afișează rezultatele testului produsului în stoc", "@testResultsDetail": {}, - "testResultAdd": "Add Test Result", + "testResultAdd": "Adăugare rezultat test", "@testResultAdd": {}, - "testResultNone": "No Test Results", + "testResultNone": "Niciun rezultat de test", "@testResultNone": {}, - "testResultNoneDetail": "No test results available", + "testResultNoneDetail": "Nici un rezultat de test disponibil", "@testResultNoneDetail": {}, - "testResultUploadFail": "Error uploading test result", + "testResultUploadFail": "Eroare încărcare rezultat test", "@testResultUploadFail": {}, - "testResultUploadPass": "Test result uploaded", + "testResultUploadPass": "Rezultat test încărcat", "@testResultUploadPass": {}, "timeout": "Timeout", "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Comutare lanternă", "@toggleTorch": {}, - "tokenError": "Token Error", + "tokenError": "Eroare token", "@tokenError": {}, - "tokenMissing": "Missing Token", + "tokenMissing": "Token lipsă", "@tokenMissing": {}, - "tokenMissingFromResponse": "Access token missing from response", + "tokenMissingFromResponse": "Token-ul de acces lipsește din răspuns", "@tokenMissingFromResponse": {}, - "totalPrice": "Total Price", + "totalPrice": "Preț total", "@totalPrice": {}, - "trackingNumber": "Tracking Number", + "trackingNumber": "Număr de urmărire", "@trackingNumber": {}, "transfer": "Transfer", "@transfer": { "description": "transfer" }, - "transferStock": "Transfer Stock", + "transferStock": "Transfera stoc", "@transferStock": { "description": "transfer stock" }, - "transferStockDetail": "Transfer item to a different location", + "transferStockDetail": "Transferați articolul într-o locație diferită", "@transferStockDetail": {}, - "transferStockLocation": "Transfer Stock Location", + "transferStockLocation": "Transfer locație stoc", "@transferStockLocation": {}, - "transferStockLocationDetail": "Transfer this stock location into another", + "transferStockLocationDetail": "Transferați această locație a stocului în alta", "@transferStockLocationDetail": {}, - "translate": "Translate", + "translate": "Traduceți", "@translate": {}, - "translateHelp": "Help translate the InvenTree app", + "translateHelp": "Ajută la traducerea aplicației InvenTree", "@translateHelp": {}, - "unavailable": "Unavailable", + "unavailable": "Indisponibil", "@unavailable": {}, - "unavailableDetail": "Item is not available", + "unavailableDetail": "Articolul nu este disponibil", "@unavailableDetail": {}, - "unitPrice": "Unit Price", + "unitPrice": "Preţ Unitar", "@unitPrice": {}, - "units": "Units", + "units": "Unități", "@units": {}, - "unknownResponse": "Unknown Response", + "unknownResponse": "Răspuns necunoscut", "@unknownResponse": {}, - "upload": "Upload", + "upload": "Încărcaţi", "@upload": {}, - "uploadFailed": "File upload failed", + "uploadFailed": "Încărcare fișier eșuată", "@uploadFailed": {}, - "uploadSuccess": "File uploaded", + "uploadSuccess": "Fişier încărcat", "@uploadSuccess": {}, - "uploadImage": "Upload Image", + "uploadImage": "Încărcare imagine", "@uploadImage": {}, - "usedIn": "Used In", + "usedIn": "Folosite în", "@usedIn": {}, - "usedInDetails": "Assemblies which require this part", + "usedInDetails": "Ansambluri care necesită aceast articol", "@usedInDetails": {}, "username": "Nume utilizator", "@username": {}, "usernameEmpty": "Numele de utilizator nu poate fi gol", "@usernameEmpty": {}, - "value": "Value", + "value": "Valoare", "@value": { "description": "value" }, - "valueCannotBeEmpty": "Value cannot be empty", + "valueCannotBeEmpty": "Valoarea nu poate fi goală", "@valueCannotBeEmpty": {}, - "valueRequired": "Value is required", + "valueRequired": "Valoarea este obligatorie", "@valueRequired": {}, - "variants": "Variants", + "variants": "Variante", "@variants": {}, - "version": "Version", + "version": "Verisune", "@version": {}, - "viewSupplierPart": "View Supplier Part", + "viewSupplierPart": "Vezi capitol furnizor", "@viewSupplierPart": {}, "website": "Website", "@website": {}, - "yes": "Yes", + "yes": "Da", "@yes": {}, - "price": "Price", + "price": "Preț", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Interval de preț", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Suprascriere Preț Minim", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Suprascriere de preț maximă", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Preț de vânzare", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Istoric vanzari", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Prețurile furnizorului", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Cost BOM", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Cost intern", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Cost variantă", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Preț general", "@overallPricing": {}, - "pricingOverrides": "Pricing Overrides", + "pricingOverrides": "Suprascrieri preturi", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Monedă", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Reduceri de preț", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 464d390..2281a9a 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -10,7 +10,7 @@ }, "about": "Hakkında", "@about": {}, - "accountDetails": "Hesap Detayları", + "accountDetails": "Hesap Ayrıntıları", "@accountDetails": {}, "actions": "Eylemler", "@actions": { @@ -34,7 +34,7 @@ "@appCredits": {}, "appDetails": "Uygulama Ayrıntıları", "@appDetails": {}, - "allocated": "Tahsis edildi", + "allocated": "Tahsis Edildi", "@allocated": {}, "aspectRatio16x9": "16:9", "@aspectRatio16x9": {}, @@ -44,7 +44,7 @@ "@aspectRatio4x3": {}, "aspectRatioSquare": "Kare (1:1)", "@aspectRatioSquare": {}, - "allocateStock": "Tahsisli stok", + "allocateStock": "Stoku Tahsis Et", "@allocateStock": {}, "allocatedStock": "Tahsis Edilen Stok", "@allocatedStock": {}, @@ -60,7 +60,7 @@ "@assignedToMeDetail": {}, "attachments": "Ekler", "@attachments": {}, - "attachImage": "Resim ekle", + "attachImage": "Görsel Ekle", "@attachImage": { "description": "Attach an image" }, @@ -98,7 +98,7 @@ "@barcodeNotAssigned": {}, "barcodeScanPart": "Parça barkodnu tara", "@barcodeScanPart": {}, - "barcodeReceivePart": "Tesellüm barkodunu tara", + "barcodeReceivePart": "Parçayı teslim almak için barkodu tarayın", "@barcodeReceivePart": {}, "barcodeScanPaused": "Barkod tarama duraklatıldı", "@barodeScanPaused": {}, @@ -138,15 +138,15 @@ "@barcodeUnknown": {}, "batchCode": "Grup kodu", "@batchCode": {}, - "billOfMaterials": "Fatura materyalleri", + "billOfMaterials": "Ürün Ağacı", "@billOfMaterials": {}, "bom": "BOM", "@bom": {}, - "bomEnable": "Malzeme Listesini Görüntüle", + "bomEnable": "Ürün Ağacını Görüntüle", "@bomEnable": {}, - "build": "Yap", + "build": "Üret", "@build": {}, - "building": "Yapılıyor", + "building": "Üretiliyor", "@building": {}, "cameraCreationError": "Kamera Kontrolcüsü Açılamadı", "@cameraCreationError": {}, @@ -176,7 +176,7 @@ "@companyEdit": {}, "companyNoResults": "Sorguyla eşleşen şirket yok", "@companyNoResults": {}, - "companyUpdated": "Firma bilgileri güncellendi", + "companyUpdated": "Şirket bilgileri güncellendi", "@companyUpdated": {}, "companies": "Şirketler", "@companies": {}, @@ -206,7 +206,7 @@ "@credits": {}, "crop": "Kırp", "@crop": {}, - "cropImage": "Resmi Kırp", + "cropImage": "Görseli Kırp", "@cropImage": {}, "customer": "Müşteri", "@customer": {}, @@ -228,11 +228,11 @@ "@delete": {}, "deleteFailed": "Silme işlemi başarısız", "@deleteFailed": {}, - "deleteImageConfirmation": "Bu resmi silmek istediğinizden emin misiniz?", + "deleteImageConfirmation": "Bu görseli silmek istediğinize emin misiniz?", "@deleteImageConfirmation": {}, - "deleteImageTooltip": "Görüntüyü Sil", + "deleteImageTooltip": "Görseli Sil", "@deleteImageTooltip": {}, - "deleteImage": "Resmi sil", + "deleteImage": "Görseli sil", "@deleteImage": {}, "deletePart": "Parça Sil", "@deletePart": {}, @@ -244,11 +244,11 @@ "@deliveryDate": {}, "description": "Açıklama", "@description": {}, - "destination": "Varış Yeri", + "destination": "Hedef", "@destination": {}, "destroyed": "Yok edildi", "@destroyed": {}, - "details": "Detaylar", + "details": "Ayrıntılar", "@details": { "description": "details" }, @@ -280,7 +280,7 @@ }, "editItem": "Stok kalemi düzenle", "@editItem": {}, - "editLineItem": "Satır Ögesini Düzenle", + "editLineItem": "Satırı Düzenle", "@editLineItem": {}, "email": "E-posta", "@email": {}, @@ -316,9 +316,9 @@ "@expiryExpired": {}, "expiryStale": "Eskimiş", "@expiryStale": {}, - "extraLineItem": "Fazladan Satır Ögesi", + "extraLineItem": "Ek Kalem", "@extraLineItem": {}, - "extraLineItems": "Fazladan Satır Ögeleri", + "extraLineItems": "Ek Kalemler", "@extraLineItems": {}, "feedback": "Geri Bildirim", "@feedback": {}, @@ -392,9 +392,9 @@ "@homeShowSo": {}, "homeShowSoDescription": "Satış siparişleri tuşunu giriş ekranında göster", "@homeShowSoDescription": {}, - "homeShowSubscribed": "Parça bildirimlerine abone ol", + "homeShowSubscribed": "Takip Edilen Parçalar", "@homeShowSubscribed": {}, - "homeShowSubscribedDescription": "Abone olunan bölümleri ana ekranda göster", + "homeShowSubscribedDescription": "Takip edilen parçaları ana ekranda göster", "@homeShowSubscsribedDescription": {}, "homeShowSuppliers": "Tedarikçileri Göster", "@homeShowSuppliers": {}, @@ -408,13 +408,13 @@ "@homeShowCustomers": {}, "homeShowCustomersDescription": "Müşteri butonunu ana ekranda göster", "@homeShowCustomersDescription": {}, - "imageUploadFailure": "Fotoğraf yükleme başarısız", + "imageUploadFailure": "Görsel yükleme başarısız", "@imageUploadFailure": {}, - "imageUploadSuccess": "Resim yüklendi", + "imageUploadSuccess": "Görsel yüklendi", "@imageUploadSuccess": {}, "inactive": "Pasif", "@inactive": {}, - "inactiveCompany": "Bu şirket pasif olarak imlendi", + "inactiveCompany": "Bu şirket pasif olarak işaretlendi", "@inactiveCompany": {}, "inactiveDetail": "Bu parça pasif olarak işaretlendi", "@inactiveDetail": {}, @@ -432,7 +432,7 @@ "@internalPartNumber": {}, "info": "Bilgi", "@info": {}, - "inProduction": "Yapım Aşamasında", + "inProduction": "Üretimde", "@inProduction": {}, "inProductionDetail": "Bu stok kalemi üretimdedir", "@inProductionDetail": {}, @@ -462,7 +462,7 @@ "@issue": {}, "issueDate": "Sorun Tarihi", "@issueDate": {}, - "issueOrder": "Sipariş Ver", + "issueOrder": "Sipariş Düzenle", "@issueOrder": {}, "itemInLocation": "Parça zaten konumda", "@itemInLocation": {}, @@ -472,13 +472,13 @@ "@itemUpdated": {}, "keywords": "Anahtar kelimeler", "@keywords": {}, - "labelDriver": "Label Driver", + "labelDriver": "Etiket Sürücü", "@labelDriver": {}, "labelSelectDriver": "Etiket Yazıcı Sürücüsü Seçin", "@labelSelectDriver": {}, "labelPrinting": "Etiket Yazdırma", "@labelPrinting": {}, - "labelPrintingDetail": "Etiket yazdırmayı aktifleştir", + "labelPrintingDetail": "Etiket yazdırmayı etkinleştir", "@labelPrintingDetail": {}, "labelTemplate": "Etiket Şablonu", "@labelTemplate": {}, @@ -496,15 +496,15 @@ "@lastStocktake": {}, "lastUpdated": "Son güncelleme", "@lastUpdated": {}, - "level": "Düzey", + "level": "Seviye", "@level": {}, - "lineItemAdd": "Satır Ögesi Ekle", + "lineItemAdd": "Satır Ekle", "@lineItemAdd": {}, - "lineItem": "Parça Sırası", + "lineItem": "Satır", "@lineItem": {}, - "lineItems": "Parçalar Sırası", + "lineItems": "Satırlar", "@lineItems": {}, - "lineItemUpdated": "Satır ögesi güncellendi", + "lineItemUpdated": "Satır güncellendi", "@lineItemUpdated": {}, "locateItem": "Stok kalemi bul", "@locateItem": {}, @@ -562,7 +562,7 @@ "@noResponse": {}, "noResults": "Sonuç Yok", "@noResults": {}, - "noImageAvailable": "Kullanılabilir resim yok", + "noImageAvailable": "Görsel yok", "@noImageAvailable": {}, "noPricingAvailable": "Fiyatlandırma mevcut değil", "@noPricingAvailable": {}, @@ -588,9 +588,9 @@ "@orientationPortrait": {}, "orientationSystem": "Sistem", "@orientationSystem": {}, - "outstanding": "Beklemede", + "outstanding": "Açık", "@outstanding": {}, - "outstandingOrderDetail": "Bekleyen siparişleri göster", + "outstandingOrderDetail": "Açık siparişleri göster", "@outstandingOrderDetail": {}, "overdue": "Gecikmede", "@overdue": {}, @@ -624,7 +624,7 @@ "@parts": { "description": "Part (multiple)" }, - "partNotSalable": "Parça satılabilir olarak imlenmemiş", + "partNotSalable": "Parça satılabilir olarak işaretli değil", "@partNotSalable": {}, "partsNone": "Parça Yok", "@partsNone": {}, @@ -636,7 +636,7 @@ "@pricingSettingDetail": {}, "partSettings": "Parça Ayarları", "@partSettings": {}, - "partsStarred": "Sürekli Gelen parçalar", + "partsStarred": "Takip Edilen Parçalar", "@partsStarred": {}, "partsStarredNone": "Yıldızlı parça yok", "@partsStarredNone": {}, @@ -648,7 +648,7 @@ "@partCategoryTopLevel": {}, "partCategories": "Parça Kategorileri", "@partCategories": {}, - "partDetails": "Parça detayları", + "partDetails": "Parça Ayrıntıları", "@partDetails": {}, "partNotes": "Parça notları", "@partNotes": {}, @@ -710,7 +710,7 @@ "@projectCode": {}, "purchaseOrderConfirmScan": "Tarama Verisini Onayla", "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Taranan Ürünlerin Detaylarını Onayla", + "purchaseOrderConfirmScanDetail": "Kalemleri tararken ayrıntıları onayla", "@purchaseOrderConfirmScanDetail": {}, "purchaseOrderEnable": "Satın Alma Siparişlerini Etkinleştir", "@purchaseOrderEnable": {}, @@ -718,7 +718,7 @@ "@purchaseOrderEnableDetail": {}, "purchaseOrderShowCamera": "Kamera Kısayolu", "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Satın alma emirleri ekranında fotoğraf yükleme kısayolunu etkinleştir", + "purchaseOrderShowCameraDetail": "Satın alma siparişi ekranında görsel yükleme kısayolunu etkinleştir", "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Satınalma Siparişi", "@purchaseOrder": {}, @@ -750,13 +750,13 @@ "@queryEmpty": {}, "queryNoResults": "Sorgu için sonuç yok", "@queryNoResults": {}, - "received": "Alınan", + "received": "Teslim Alındı", "@received": {}, - "receivedFilterDetail": "Alınan ögeleri göster", + "receivedFilterDetail": "Teslim alınan kalemleri göster", "@receivedFilterDetail": {}, - "receiveItem": "Alınan Öğeler", + "receiveItem": "Kalemi Teslim Al", "@receiveItem": {}, - "receivedItem": "Alınan stok kalemleri", + "receivedItem": "Teslim alınan stok kalemleri", "@receivedItem": {}, "reference": "Referans", "@reference": {}, @@ -844,7 +844,7 @@ "@salesOrderEnableDetail": {}, "salesOrderShowCamera": "Kamera Kısayolu", "@salesOrderShowCamera": {}, - "salesOrderShowCameraDetail": "Satış emirleri ekranında fotoğraf yükleme kısayolunu etkinleştir", + "salesOrderShowCameraDetail": "Satış siparişi ekranında görsel yükleme kısayolunu etkinleştir", "@salesOrderShowCameraDetail": {}, "salesOrderSettings": "Satış emirleri ayarları", "@salesOrderSettings": {}, @@ -870,7 +870,7 @@ "@scannerExternal": {}, "scannerExternalDetail": "Barkodları okumak için harici tarayıcı kullan (keyboard wedge modu)", "@scannerExternalDetail": {}, - "scanReceivedParts": "Alınan Parçaları Tara", + "scanReceivedParts": "Teslim Alınan Parçaları Tara", "@scanReceivedParts": {}, "search": "Ara", "@search": { @@ -888,7 +888,7 @@ "@select": {}, "selectFile": "Dosya Seç", "@selectFile": {}, - "selectImage": "Resim Seç", + "selectImage": "Görsel Seç", "@selectImage": {}, "selectLocation": "Bir yer seçin", "@selectLocation": {}, @@ -922,7 +922,7 @@ "@serverEmpty": {}, "serverError": "Sunucu Hatası", "@serverError": {}, - "serverDetails": "Sunucu Detayları", + "serverDetails": "Sunucu Ayrıntıları", "@serverDetails": {}, "serverMissingData": "Sunucu yanıtında gerekli alanlar eksik", "@serverMissingData": {}, @@ -948,11 +948,11 @@ "@shipmentsPending": {}, "shipmentAdd": "Gönderi Ekle", "@shipmentAdd": {}, - "shipmentCheck": "Teslimatı Kontrol Et", + "shipmentCheck": "Sevkiyatı Kontrol Et", "@shipmentCheck": {}, - "shipmentCheckDetail": "Bu teslimatı kontrol edildi olarak işaretle", + "shipmentCheckDetail": "Bu sevkiyatı kontrol edildi olarak işaretle", "@shipmentCheckDetail": {}, - "shipmentChecked": "Teslimat Kontrol Edildi", + "shipmentChecked": "Sevkiyat Kontrol Edildi", "@shipmentChecked": {}, "shipmentDate": "Teslimat Tarihi", "@shipmentDate": {}, @@ -962,7 +962,7 @@ "@shipmentReference": {}, "shipmentSend": "Teslimatı Gönder", "@shipmentSend": {}, - "shipmentUncheck": "Teslimat İşaretini Kaldır", + "shipmentUncheck": "Sevkiyat Kontrolünü Kaldır", "@shipmentUncheck": {}, "shipmentUncheckDetail": "Bu teslimatı kontrol edilmedi olarak işaretle", "@shipmentUncheckDetail": {}, @@ -1148,7 +1148,7 @@ "@uploadFailed": {}, "uploadSuccess": "Dosya yüklendi", "@uploadSuccess": {}, - "uploadImage": "Resim Yükleyin", + "uploadImage": "Görsel Yükle", "@uploadImage": {}, "usedIn": "Burada Kullanıldı", "@usedIn": {}, @@ -1202,6 +1202,6 @@ "@pricingOverrides": {}, "currency": "Para Birimi", "@currency": {}, - "priceBreaks": "Fiyat Aralığı", + "priceBreaks": "Fiyat Kademeleri", "@priceBreaks": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 876f122..26cdce4 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -102,7 +102,7 @@ "@barcodeReceivePart": {}, "barcodeScanPaused": "条形码扫描已暂停", "@barodeScanPaused": {}, - "barcodeScanPause": "点击或按住以暂停扫描", + "barcodeScanPause": "点击以暂停扫描", "@barcodeScanPause": {}, "barcodeScanAssign": "扫描以分配条形码", "@barcodeScanAssign": {}, @@ -514,7 +514,7 @@ "@locationCreate": {}, "locationCreateDetail": "创建新库存地点", "@locationCreateDetail": {}, - "locationDefault": "默认库存地点", + "locationDefault": "默认位置", "@locationDefault": {}, "locationNotSet": "没有指定仓储位置", "@locationNotSet": {}, From 225c40f9a678661149187f15c67e4a056d8d2698 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 10 Jan 2026 09:23:00 +1100 Subject: [PATCH 737/746] New Crowdin updates (#744) * New translations app_en.arb (Dutch) * New translations app_en.arb (German) --- lib/l10n/de_DE/app_de_DE.arb | 6 +++--- lib/l10n/nl_NL/app_nl_NL.arb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index e0bb95c..83e0bdc 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -546,7 +546,7 @@ "@name": {}, "no": "Nein", "@no": {}, - "notApplicable": "nicht verfügbar", + "notApplicable": "Nicht Anwendbar", "@notApplicable": {}, "notConnected": "Nicht verbunden", "@notConnected": {}, @@ -1180,9 +1180,9 @@ "@price": {}, "priceRange": "Preisspanne", "@priceRange": {}, - "priceOverrideMin": "Mindestpreis überschreiben", + "priceOverrideMin": "Mindestpreis ignorieren", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximalen Preis ignorieren", + "priceOverrideMax": "Maximalpreis ignorieren", "@priceOverrideMax": {}, "salePrice": "Verkaufspreis", "@salePrice": {}, diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index ba45758..f789d4a 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -958,7 +958,7 @@ "@shipmentDate": {}, "shipmentEdit": "Wijzig levering", "@shipmentEdit": {}, - "shipmentReference": "Shipment Reference", + "shipmentReference": "Referentie verzending", "@shipmentReference": {}, "shipmentSend": "Verzending versturen", "@shipmentSend": {}, From a4631cda7ab10d9635687765fc21bb25536e6718 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 14 Jan 2026 15:15:21 +1100 Subject: [PATCH 738/746] List filtering fix (#746) * Bug fix for API forms without URL - Ensure submitted data is returned * Translate search fields * Update release notes * Remove debug message * dart format --- assets/release_notes.md | 1 + lib/api_form.dart | 11 +++++------ lib/l10n/app_en.arb | 12 ++++++++++++ lib/widget/paginator.dart | 8 ++++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index cbde004..e4e571c 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Fixes bug which launched camera twice when uploading an attachment +- Fixed bug related to list sorting and filtering ### 0.21.1 - November 2025 --- diff --git a/lib/api_form.dart b/lib/api_form.dart index 429c71d..7201b7d 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1011,17 +1011,16 @@ Future launchApiForm( APIFormWidgetState? formHandler, IconData icon = TablerIcons.device_floppy, }) async { - showLoadingOverlay(); - // List of fields defined by the server Map serverFields = {}; if (url.isNotEmpty) { + showLoadingOverlay(); var options = await InvenTreeAPI().options(url); + hideLoadingOverlay(); // Invalid response from server if (!options.isValid()) { - hideLoadingOverlay(); return; } @@ -1030,8 +1029,6 @@ Future launchApiForm( if (serverFields.isEmpty) { // User does not have permission to perform this action showSnackIcon(L10().response403, icon: TablerIcons.user_x); - - hideLoadingOverlay(); return; } } @@ -1075,6 +1072,8 @@ Future launchApiForm( formFields.add(field); } + showLoadingOverlay(); + // Grab existing data for each form field for (var field in formFields) { await field.loadInitialData(); @@ -1430,7 +1429,7 @@ class APIFormWidgetState extends State { // Perhaps we just want to process the data? if (widget.url.isEmpty) { // Hide the form - handleSuccess(data, {}); + handleSuccess(data, data); return; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 905be19..cab9260 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1298,6 +1298,18 @@ "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "Search Parts", "@searchParts": {}, diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index c525de5..e18957e 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -152,19 +152,19 @@ abstract class PaginatedSearchState Map fields = { "ordering_field": { "type": "choice", - "label": "Ordering Field", + "label": L10().searchOrderingField, "required": true, "choices": _opts, "value": _field, }, "ordering_order": { "type": "choice", - "label": "Ordering Direction", + "label": L10().searchOrderingDirection, "required": true, "value": _order, "choices": [ - {"value": "+", "display_name": "Ascending"}, - {"value": "-", "display_name": "Descending"}, + {"value": "+", "display_name": L10().searchOrderingAscending}, + {"value": "-", "display_name": L10().searchOrderingDescending}, ], }, }; From 80f62091b1d4bc5ae3d96616126606a8c1b3a6f7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 14 Jan 2026 22:12:04 +1100 Subject: [PATCH 739/746] Bump version number (#747) --- assets/release_notes.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e4e571c..e989e79 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,4 +1,4 @@ -### x.xx.x - Month Year +### 0.21.2 - January 2026 --- - Fixes bug which launched camera twice when uploading an attachment diff --git a/pubspec.yaml b/pubspec.yaml index bf7987f..129d635 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.21.1+107 +version: 0.21.2+108 environment: sdk: ^3.8.1 From 9002fb78d304b45f17d21eb5cd5ce3c08a7701dc Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jan 2026 09:57:18 +1100 Subject: [PATCH 740/746] New Crowdin updates (#748) * New translations app_en.arb (Turkish) * New translations app_en.arb (Romanian) * New translations app_en.arb (Danish) * New translations app_en.arb (Polish) * New translations app_en.arb (Japanese) * New translations app_en.arb (Dutch) * New translations app_en.arb (German) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (French) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 8 ++++++++ lib/l10n/bg_BG/app_bg_BG.arb | 8 ++++++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 8 ++++++++ lib/l10n/da_DK/app_da_DK.arb | 8 ++++++++ lib/l10n/de_DE/app_de_DE.arb | 8 ++++++++ lib/l10n/el_GR/app_el_GR.arb | 8 ++++++++ lib/l10n/es_ES/app_es_ES.arb | 8 ++++++++ lib/l10n/es_MX/app_es_MX.arb | 8 ++++++++ lib/l10n/et_EE/app_et_EE.arb | 8 ++++++++ lib/l10n/fa_IR/app_fa_IR.arb | 8 ++++++++ lib/l10n/fi_FI/app_fi_FI.arb | 8 ++++++++ lib/l10n/fr_FR/app_fr_FR.arb | 8 ++++++++ lib/l10n/he_IL/app_he_IL.arb | 8 ++++++++ lib/l10n/hi_IN/app_hi_IN.arb | 8 ++++++++ lib/l10n/hu_HU/app_hu_HU.arb | 8 ++++++++ lib/l10n/id_ID/app_id_ID.arb | 8 ++++++++ lib/l10n/it_IT/app_it_IT.arb | 8 ++++++++ lib/l10n/ja_JP/app_ja_JP.arb | 8 ++++++++ lib/l10n/ko_KR/app_ko_KR.arb | 8 ++++++++ lib/l10n/lt_LT/app_lt_LT.arb | 8 ++++++++ lib/l10n/lv_LV/app_lv_LV.arb | 8 ++++++++ lib/l10n/nl_NL/app_nl_NL.arb | 8 ++++++++ lib/l10n/no_NO/app_no_NO.arb | 8 ++++++++ lib/l10n/pl_PL/app_pl_PL.arb | 8 ++++++++ lib/l10n/pt_BR/app_pt_BR.arb | 8 ++++++++ lib/l10n/pt_PT/app_pt_PT.arb | 8 ++++++++ lib/l10n/ro_RO/app_ro_RO.arb | 8 ++++++++ lib/l10n/ru_RU/app_ru_RU.arb | 8 ++++++++ lib/l10n/sk_SK/app_sk_SK.arb | 8 ++++++++ lib/l10n/sl_SI/app_sl_SI.arb | 8 ++++++++ lib/l10n/sr_CS/app_sr_CS.arb | 8 ++++++++ lib/l10n/sv_SE/app_sv_SE.arb | 8 ++++++++ lib/l10n/th_TH/app_th_TH.arb | 8 ++++++++ lib/l10n/tr_TR/app_tr_TR.arb | 8 ++++++++ lib/l10n/uk_UA/app_uk_UA.arb | 8 ++++++++ lib/l10n/vi_VN/app_vi_VN.arb | 8 ++++++++ lib/l10n/zh_CN/app_zh_CN.arb | 8 ++++++++ lib/l10n/zh_TW/app_zh_TW.arb | 8 ++++++++ 38 files changed, 304 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 1f8c94e..af1cb2a 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 01a6299..0a11bd2 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index ccd9d94..37150c8 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Hledat umístění", "@searchLocation": {}, + "searchOrderingField": "Pole pro řazení", + "@searchOrderingField": {}, + "searchOrderingDirection": "Směr řazení", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Vzestupně", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Sestupně", + "@searchOrderingDescending": {}, "searchParts": "Hledat díly", "@searchParts": {}, "searchStock": "Hledat zásoby", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index c05efb3..c78e5e0 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Søg efter lokation", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Søg efter dele", "@searchParts": {}, "searchStock": "Søg Lager", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 83e0bdc..66e5dc8 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Lagerort suchen", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Teile suchen", "@searchParts": {}, "searchStock": "Bestand durchsuchen", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 436d4f7..7e697ae 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Αναζήτηση τοποθεσίας", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Αναζήτηση εξαρτημάτων", "@searchParts": {}, "searchStock": "Αναζήτηση αποθέματος", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index ef947d4..0fcb849 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Buscar ubicación", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Buscar piezas", "@searchParts": {}, "searchStock": "Buscar Stock", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index 1197082..1ea7ace 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Buscar ubicación", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Buscar partes", "@searchParts": {}, "searchStock": "Buscar inventario", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index b6847d8..3616a21 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index ceb836d..8cc41e9 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "جست و جو موقعیت", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "جست و جو قطعه ها", "@searchParts": {}, "searchStock": "جست و جو موجودی", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 26ba3e3..ea2c362 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Etsi osia", "@searchParts": {}, "searchStock": "Etsi varastosta", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 929c962..9831dcb 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Rechercher un emplacement", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Rechercher de pièces", "@searchParts": {}, "searchStock": "Rechercher un stock", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 2273108..c508c93 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "חפש מיקום", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "חיפוש פריטים", "@searchParts": {}, "searchStock": "חפש מלאי", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index c0c3cbb..6c8fde6 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 509d9d2..0144f68 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Hely keresése", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Alkatrészek keresése", "@searchParts": {}, "searchStock": "Készlet keresése", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 2346557..7cce4a5 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Caro Lokasi", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Cari Part", "@searchParts": {}, "searchStock": "Cari Persediaan", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index ecbe8b1..6683476 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Cerca Ubicazione", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Cerca Articoli", "@searchParts": {}, "searchStock": "Cerca Scorte", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 88722da..baffd2c 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "在庫場所を検索", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "パーツの検索", "@searchParts": {}, "searchStock": "在庫を検索", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 390183d..f1e2e9b 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index dbb63e9..ecdf8de 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index 064ec61..7a792ed 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index f789d4a..bc9c2c9 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Zoeken naar locatie", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Zoek Onderdelen", "@searchParts": {}, "searchStock": "Zoek Voorraad", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index d9e3196..68a6db4 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Søk etter plassering", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Søk i deler", "@searchParts": {}, "searchStock": "Søk i lagerbeholdning", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index 5aa8e5c..af85d05 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Wyszukaj lokalizację", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Szukaj części", "@searchParts": {}, "searchStock": "Szukaj zapasów", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 991ea1d..85866f9 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Procurar um Local", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Procurar Peças", "@searchParts": {}, "searchStock": "Procurar o Estoque", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 4fc3583..87997d3 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index adfed52..2753c0c 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Căutați locația", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Caută componente", "@searchParts": {}, "searchStock": "Căutare Stoc", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 8eb938f..b22d092 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Искать по месту", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Найти номенклатуру", "@searchParts": {}, "searchStock": "Поиск в наличии", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index ef1ac29..e60c333 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 1414c2c..e0c78b1 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index e48713c..75d28b4 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 88d8b85..7ff3063 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Sök efter plats", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Sök efter artiklar", "@searchParts": {}, "searchStock": "Sök i lager", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index af0ca84..ada0c69 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 2281a9a..9f6b03f 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Konum için Ara", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Parçaları Ara", "@searchParts": {}, "searchStock": "Stok Ara", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index da21c3a..8201634 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Search for location", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Search Parts", "@searchParts": {}, "searchStock": "Search Stock", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 77777c0..b981e99 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "Vị trí tìm kiếm", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "Tìm kiếm phụ tùng", "@searchParts": {}, "searchStock": "Tìm kiếm có sẵn", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 26cdce4..2f7c498 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "搜索仓储位置", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "搜索零件", "@searchParts": {}, "searchStock": "搜索库存", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index f0ba7e5..b0871e1 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -880,6 +880,14 @@ "@searching": {}, "searchLocation": "搜索倉儲位置", "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, "searchParts": "搜索零件", "@searchParts": {}, "searchStock": "搜索庫存", From 74f468dc1b3469ff48a184d078522d347c727df8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jan 2026 13:20:24 +1100 Subject: [PATCH 741/746] Default filters (#749) * Bug fix for filters - Fix key shadowing * Adjust default filters for stock list * Adjust default filter values * Add "active" filter for stock items * Code formatting --- assets/release_notes.md | 6 ++++++ lib/inventree/model.dart | 2 -- lib/widget/order/purchase_order_list.dart | 1 + lib/widget/order/sales_order_list.dart | 1 + lib/widget/paginator.dart | 15 +++++++++------ lib/widget/part/part_list.dart | 1 + lib/widget/stock/stock_list.dart | 7 ++++++- 7 files changed, 24 insertions(+), 9 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index e989e79..2027c93 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,9 @@ +### x.xx.x - Month Year +--- + +- Fix default values for list sorting + + ### 0.21.2 - January 2026 --- diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index f87b2de..25c1708 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -730,8 +730,6 @@ class InvenTreeModel { var response = await api.get(URL, params: params); - print("paginated: ${URL}: ${params}"); - if (!response.isValid()) { return null; } diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart index 4c1b363..85fc668 100644 --- a/lib/widget/order/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -133,6 +133,7 @@ class _PaginatedPurchaseOrderListState "label": L10().outstanding, "help_text": L10().outstandingOrderDetail, "tristate": true, + "default": true, }, "overdue": { "label": L10().overdue, diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart index 2c0ff4a..0a8bfb0 100644 --- a/lib/widget/order/sales_order_list.dart +++ b/lib/widget/order/sales_order_list.dart @@ -115,6 +115,7 @@ class _PaginatedSalesOrderListState "label": L10().outstanding, "help_text": L10().outstandingOrderDetail, "tristate": true, + "default": true, }, "overdue": { "label": L10().overdue, diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index e18957e..4aa6be1 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -47,25 +47,28 @@ abstract class PaginatedSearchState // Return the boolean value of a particular boolean filter Future getFilterValue(String key) async { - key = "${prefix}filter_${key}"; + final String settings_key = "${prefix}filter_${key}"; Map opts = filterOptions[key] ?? {}; bool tristate = (opts["tristate"] ?? true) as bool; - dynamic backup = tristate ? null : opts["default"]; - final result = await InvenTreeSettingsManager().getValue(key, backup); + dynamic backup = tristate ? opts["default"] : opts["default"] ?? false; + final result = await InvenTreeSettingsManager().getValue( + settings_key, + backup, + ); return result; } // Set the boolean value of a particular boolean filter Future setFilterValue(String key, dynamic value) async { - key = "${prefix}filter_${key}"; + final String settings_key = "${prefix}filter_${key}"; if (value == null) { - await InvenTreeSettingsManager().removeValue(key); + await InvenTreeSettingsManager().removeValue(settings_key); } else { - await InvenTreeSettingsManager().setValue(key, value); + await InvenTreeSettingsManager().setValue(settings_key, value); } } diff --git a/lib/widget/part/part_list.dart b/lib/widget/part/part_list.dart index 3f219b5..040de2c 100644 --- a/lib/widget/part/part_list.dart +++ b/lib/widget/part/part_list.dart @@ -74,6 +74,7 @@ class _PaginatedPartListState extends PaginatedSearchState { "label": L10().filterActive, "help_text": L10().filterActiveDetail, "tristate": true, + "default": true, }, "assembly": { "label": L10().filterAssembly, diff --git a/lib/widget/stock/stock_list.dart b/lib/widget/stock/stock_list.dart index 8e6e89d..d969792 100644 --- a/lib/widget/stock/stock_list.dart +++ b/lib/widget/stock/stock_list.dart @@ -75,8 +75,13 @@ class _PaginatedStockItemListState "help_text": L10().filterInStockDetail, "tristate": true, }, + "active": { + "default": true, + "label": L10().filterActive, + "help_text": L10().filterActiveDetail, + }, "cascade": { - "default": false, + "default": true, "label": L10().includeSublocations, "help_text": L10().includeSublocationsDetail, "tristate": false, From 97e4c98e463775e09ada7b2a2b847f840b25f7c5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 20 Jan 2026 09:11:40 +1100 Subject: [PATCH 742/746] Default filters (#755) * Bug fix for filters - Fix key shadowing * Adjust default filters for stock list * Adjust default filter values * Add "active" filter for stock items * Code formatting * Add "default ordering" option * Enable pathstring sorting * dart format --- lib/l10n/app_en.arb | 27 +++++++++++++++------------ lib/widget/paginator.dart | 6 ++++++ lib/widget/part/category_list.dart | 9 ++++++++- lib/widget/stock/location_list.dart | 4 ++++ 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cab9260..4f6560f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -974,6 +974,9 @@ "passwordEmpty": "Password cannot be empty", "@passwordEmpty": {}, + "path": "Path", + "@path": {}, + "pending": "Pending", "@pending": {}, @@ -1046,23 +1049,23 @@ "projectCode": "Project Code", "@projectCode": {}, - "purchaseOrderConfirmScan": "Confirm Scan Data", - "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, - "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", - "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, - "purchaseOrderEnable": "Enable Purchase Orders", - "@purchaseOrderEnable": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, - "purchaseOrderEnableDetail": "Enable purchase order functionality", - "@purchaseOrderEnableDetail": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, - "purchaseOrderShowCamera": "Camera Shortcut", - "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCamera": "Camera Shortcut", + "@purchaseOrderShowCamera": {}, - "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", - "@purchaseOrderShowCameraDetail": {}, + "purchaseOrderShowCameraDetail": "Enable image upload shortcut on purchase order screen", + "@purchaseOrderShowCameraDetail": {}, "purchaseOrder": "Purchase Order", "@purchaseOrder": {}, diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 4aa6be1..123c7ab 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -42,6 +42,9 @@ abstract class PaginatedSearchState // Override in implementing class String get prefix => "prefix_"; + // Default ordering option (can be overridden) + String get defaultOrdering => ""; + // Should be overridden by an implementing subclass Map> get filterOptions => {}; @@ -103,6 +106,9 @@ abstract class PaginatedSearchState if (field != null && orderingOptions.containsKey(field.toString())) { // A valid ordering field has been found return field.toString(); + } else if (defaultOrdering.isNotEmpty) { + // A default ordering value is supplied + return defaultOrdering; } else if (orderingOptions.isNotEmpty) { // By default, return the first specified key return orderingOptions.keys.first; diff --git a/lib/widget/part/category_list.dart b/lib/widget/part/category_list.dart index ced2783..b90f2f6 100644 --- a/lib/widget/part/category_list.dart +++ b/lib/widget/part/category_list.dart @@ -61,9 +61,16 @@ class _PaginatedPartCategoryListState }, }; + @override + String get defaultOrdering => "pathstring"; + @override Map get orderingOptions { - Map options = {"name": L10().name, "level": L10().level}; + Map options = { + "name": L10().name, + "pathstring": L10().path, + "level": L10().level, + }; // Note: API v69 changed 'parts' to 'part_count' if (InvenTreeAPI().apiVersion >= 69) { diff --git a/lib/widget/stock/location_list.dart b/lib/widget/stock/location_list.dart index a27182d..d59c369 100644 --- a/lib/widget/stock/location_list.dart +++ b/lib/widget/stock/location_list.dart @@ -52,10 +52,14 @@ class _PaginatedStockLocationListState @override Map get orderingOptions => { "name": L10().name, + "pathstring": L10().path, "items": L10().stockItems, "level": L10().level, }; + @override + String get defaultOrdering => "pathstring"; + @override Map> get filterOptions => { "cascade": { From 772c88170eef6f358385016ad689582a1985f96e Mon Sep 17 00:00:00 2001 From: Enmanuel Sancho Quintanilla Date: Wed, 21 Jan 2026 15:37:42 -0600 Subject: [PATCH 743/746] Improve Sales Order UX: Stock Location, Customer Filtering & Enhanced List View (#756) * feat(sales-order): Improve UX with location display, customer filtering, and enhanced list - Show stock location when selecting items to allocate in sales orders - Filter inactive customers from customer selection dropdown - Display customer name and order total in sales order list view These changes improve the day-to-day usability for warehouse and field staff by providing more context in key workflows without requiring extra navigation. * Format code --- lib/api_form.dart | 1 + lib/inventree/sales_order.dart | 2 +- lib/widget/order/sales_order_list.dart | 9 ++++++++- lib/widget/order/so_allocation_list.dart | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 7201b7d..9df134c 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -732,6 +732,7 @@ class APIFormField { return ListTile( title: Text(item.partName), + subtitle: Text(item.locationPathString), leading: InvenTreeAPI().getThumbnail(item.partThumbnail), trailing: Text(item.quantityString()), ); diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index 77c3469..82cc074 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -48,7 +48,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { Map> fields = { "reference": {}, "customer": { - "filters": {"is_customer": true}, + "filters": {"is_customer": true, "active": true}, }, "customer_reference": {}, "description": {}, diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart index 0a8bfb0..e05bcf5 100644 --- a/lib/widget/order/sales_order_list.dart +++ b/lib/widget/order/sales_order_list.dart @@ -151,9 +151,16 @@ class _PaginatedSalesOrderListState InvenTreeCompany? customer = order.customer; + // Build subtitle with customer name and optional total price + String subtitle = customer?.name ?? order.description; + if (order.totalPrice != null && order.totalPrice! > 0) { + subtitle += + " • ${order.totalPriceCurrency} ${order.totalPrice!.toStringAsFixed(2)}"; + } + return ListTile( title: Text(order.reference), - subtitle: Text(order.description), + subtitle: Text(subtitle), leading: customer == null ? null : InvenTreeAPI().getThumbnail(customer.thumbnail), diff --git a/lib/widget/order/so_allocation_list.dart b/lib/widget/order/so_allocation_list.dart index 5076f07..88699d0 100644 --- a/lib/widget/order/so_allocation_list.dart +++ b/lib/widget/order/so_allocation_list.dart @@ -55,10 +55,11 @@ class _PaginatedSOAllocationListState InvenTreePart? part = allocation.part; InvenTreeStockItem? stockItem = allocation.stockItem; + InvenTreeStockLocation? location = allocation.location; return ListTile( title: Text(part?.fullname ?? ""), - subtitle: Text(part?.description ?? ""), + subtitle: Text(location?.pathstring ?? L10().locationNotSet), onTap: () async { stockItem?.goToDetailPage(context); }, From c5bf4be3d1a76e7fe1d23f89c144af3006fa73de Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 22 Jan 2026 23:35:09 +1100 Subject: [PATCH 744/746] Support logical and custom status fields for models (#758) * Support logical and custom status fields for models * Update release notes --- assets/release_notes.md | 1 + lib/inventree/model.dart | 18 ++++++++++++++++++ lib/inventree/orders.dart | 4 ---- lib/inventree/stock.dart | 2 -- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 2027c93..72324c1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### x.xx.x - Month Year --- +- Support display of custom status codes - Fix default values for list sorting diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 25c1708..3a39e64 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -334,6 +334,24 @@ class InvenTreeModel { String get description => getString("description"); + int get logicalStatus => getInt("status"); + + int get customStatus => getInt("status_custom_key"); + + // Return the effective status of this object + // If a custom status is defined, return that, otherwise return the logical status + int get status { + if (customStatus > 0) { + return customStatus; + } else { + return logicalStatus; + } + } + + String get statusText => getString("status_text"); + + bool get hasCustomStatus => customStatus > 0 && customStatus != status; + String get notes => getString("notes"); int get parentId => getInt("parent"); diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart index 8ffc478..124ded2 100644 --- a/lib/inventree/orders.dart +++ b/lib/inventree/orders.dart @@ -57,10 +57,6 @@ class InvenTreeOrder extends InvenTreeModel { bool get hasProjectCode => projectCode.isNotEmpty; - int get status => getInt("status"); - - String get statusText => getString("status_text"); - double? get totalPrice { String price = getString("total_price"); diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 4b5bf3b..657a218 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -256,8 +256,6 @@ class InvenTreeStockItem extends InvenTreeModel { }); } - int get status => getInt("status"); - bool get isInStock => getBool("in_stock", backup: true); String get packaging => getString("packaging"); From a1f057667183a73706bc6d4d682af0642cd3ddff Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 22 Jan 2026 23:35:16 +1100 Subject: [PATCH 745/746] Run dart-format on commit (#760) --- .pre-commit-config.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5dd1dc0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,8 @@ +repos: + - repo: local + hooks: + - id: dart-format + name: Dart Format + entry: dart format + language: system + types: [dart] \ No newline at end of file From ae457e82355d939f9388c2c4fbdf9a6f05c6e60e Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 22 Jan 2026 23:35:22 +1100 Subject: [PATCH 746/746] Tweak parameter display size (#759) - Increase size of displayed parameter value --- lib/widget/parameter_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widget/parameter_widget.dart b/lib/widget/parameter_widget.dart index 07a38fc..8bcc360 100644 --- a/lib/widget/parameter_widget.dart +++ b/lib/widget/parameter_widget.dart @@ -142,7 +142,7 @@ class _PaginatedParameterState } }, ) - : Text(parameter.value), + : LargeText(parameter.value), onTap: parameter.is_checkbox ? null : () async {

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 z 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�Yzr=q8;XT*{$OJ-f7rM*Xwn0eo1Ztlnp}p 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≈xJ?;90Y;Nz&csf8`B&>v~WT*_gY(C_UJron5hFU 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 literal 0 HcmV?d00001 From 03aba4b4bf102e49100b325d0a5b9a299aeaa93a Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Jun 2025 08:54:46 +1000 Subject: [PATCH 667/746] New Crowdin updates (#652) * New translations app_en.arb (French) * New translations app_en.arb (German) * New translations app_en.arb (Romanian) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) * New translations app_en.arb (Swedish) * New translations app_en.arb (Persian) --- lib/l10n/ar_SA/app_ar_SA.arb | 4 ++++ lib/l10n/bg_BG/app_bg_BG.arb | 4 ++++ lib/l10n/cs_CZ/app_cs_CZ.arb | 4 ++++ lib/l10n/da_DK/app_da_DK.arb | 4 ++++ lib/l10n/de_DE/app_de_DE.arb | 4 ++++ lib/l10n/el_GR/app_el_GR.arb | 4 ++++ lib/l10n/es_ES/app_es_ES.arb | 4 ++++ lib/l10n/es_MX/app_es_MX.arb | 4 ++++ lib/l10n/et_EE/app_et_EE.arb | 4 ++++ lib/l10n/fa_IR/app_fa_IR.arb | 4 ++++ lib/l10n/fi_FI/app_fi_FI.arb | 4 ++++ lib/l10n/fr_FR/app_fr_FR.arb | 4 ++++ lib/l10n/he_IL/app_he_IL.arb | 4 ++++ lib/l10n/hi_IN/app_hi_IN.arb | 4 ++++ lib/l10n/hu_HU/app_hu_HU.arb | 4 ++++ lib/l10n/id_ID/app_id_ID.arb | 4 ++++ lib/l10n/it_IT/app_it_IT.arb | 4 ++++ lib/l10n/ja_JP/app_ja_JP.arb | 4 ++++ lib/l10n/ko_KR/app_ko_KR.arb | 4 ++++ lib/l10n/lt_LT/app_lt_LT.arb | 4 ++++ lib/l10n/lv_LV/app_lv_LV.arb | 4 ++++ lib/l10n/nl_NL/app_nl_NL.arb | 4 ++++ lib/l10n/no_NO/app_no_NO.arb | 4 ++++ lib/l10n/pl_PL/app_pl_PL.arb | 4 ++++ lib/l10n/pt_BR/app_pt_BR.arb | 4 ++++ lib/l10n/pt_PT/app_pt_PT.arb | 4 ++++ lib/l10n/ro_RO/app_ro_RO.arb | 4 ++++ lib/l10n/ru_RU/app_ru_RU.arb | 4 ++++ lib/l10n/sk_SK/app_sk_SK.arb | 4 ++++ lib/l10n/sl_SI/app_sl_SI.arb | 4 ++++ lib/l10n/sr_CS/app_sr_CS.arb | 4 ++++ lib/l10n/sv_SE/app_sv_SE.arb | 4 ++++ lib/l10n/th_TH/app_th_TH.arb | 4 ++++ lib/l10n/tr_TR/app_tr_TR.arb | 4 ++++ lib/l10n/uk_UA/app_uk_UA.arb | 4 ++++ lib/l10n/vi_VN/app_vi_VN.arb | 4 ++++ lib/l10n/zh_CN/app_zh_CN.arb | 4 ++++ lib/l10n/zh_TW/app_zh_TW.arb | 4 ++++ 38 files changed, 152 insertions(+) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index bdad0b6..3f68ebc 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 58b07a0..3e9ba97 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 94c18ec..247637a 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Kód dodavatele", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Pořídit snímek", "@takePicture": {}, "targetDate": "Cílové datum", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Chyba tokenu", "@tokenError": {}, "tokenMissing": "Chybějící token", diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index 2e835ae..fc96b01 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index 8aa86fa..d4fb72f 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Lieferanten-Referenz", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Foto aufnehmen", "@takePicture": {}, "targetDate": "Zieldatum", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token-Fehler", "@tokenError": {}, "tokenMissing": "Token fehlt", diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index 03c420c..b97937a 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index b86dfb3..e45bb9f 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Referencia del proveedor", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Hacer una foto", "@takePicture": {}, "targetDate": "Fecha objetivo", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Error de Token", "@tokenError": {}, "tokenMissing": "Falta el token", diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index f47da66..c24b543 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Referencia del proveedor", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Tomar una foto", "@takePicture": {}, "targetDate": "Fecha objetivo", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Error de Token", "@tokenError": {}, "tokenMissing": "Falta el token", diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index d782a4c..6eaa0b1 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 5c29a61..0e51eb7 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "مرجع تامین‌ کننده", "@supplierReference": {}, + "switchCamera": "تعویض دوربین", + "@switchCamera": {}, "takePicture": "گرفتن عکس", "@takePicture": {}, "targetDate": "تاریخ هدف", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "روشن خاموش کردن چراغ قوه", + "@toggleTorch": {}, "tokenError": "خطای توکن", "@tokenError": {}, "tokenMissing": "توکن گمشده", diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index 3ea9ab6..af9e7d5 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Ota kuva", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 38250a6..ea28e7e 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Référence du fournisseur", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Prendre une photo", "@takePicture": {}, "targetDate": "Date Cible", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Erreur du jeton", "@tokenError": {}, "tokenMissing": "Jeton manquant", diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 00f0fdc..721cead 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "הפנייה לספק", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "צלם תמונה", "@takePicture": {}, "targetDate": "תאריך יעד", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "שגיאת טוקן", "@tokenError": {}, "tokenMissing": "טוקן חסר", diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 4c3f71b..9a854ad 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index f03f723..50f83b1 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Beszállítói azonosító", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Fotó készítése", "@takePicture": {}, "targetDate": "Cél dátum", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token hiba", "@tokenError": {}, "tokenMissing": "Hiányzó token", diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index 6df4124..c9cf87e 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Ambil Gambar", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index d4c66a9..06047dd 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Riferimento fornitore", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Scatta Foto", "@takePicture": {}, "targetDate": "Data dell'obiettivo", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Errore Token", "@tokenError": {}, "tokenMissing": "Token Mancante", diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index e25df9a..9ddb254 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "サプライヤーを参照", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "画像を撮影", "@takePicture": {}, "targetDate": "目標日", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "トークンエラー", "@tokenError": {}, "tokenMissing": "トークンがありません", diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 6c6b195..2ca6509 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "목표 날짜", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "토큰 오류", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index f5d2e26..8fc041c 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index cca40dc..f54355b 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index c6e3f94..9f2ad83 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Leveranciers Referentie", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Neem een Foto", "@takePicture": {}, "targetDate": "Streefdatum", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Fout", "@tokenError": {}, "tokenMissing": "Ontbrekende Token", diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index a4f5319..a24ad61 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Leverandørreferanse", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Ta bilde", "@takePicture": {}, "targetDate": "Måldato", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token-feil", "@tokenError": {}, "tokenMissing": "Manglende token", diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index b27ea8b..b200931 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Identyfikator Dostawcy", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Zrób zdjęcie", "@takePicture": {}, "targetDate": "Data Docelowa", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Błąd tokenu", "@tokenError": {}, "tokenMissing": "Brakujący token", diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 22b7469..3ccc09b 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Referencia do fornecedor", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Tirar foto", "@takePicture": {}, "targetDate": "Data alvo", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Error de token", "@tokenError": {}, "tokenMissing": "Token indisponivel", diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index f8bb140..1807679 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index 2601e70..e7421e7 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 966b3e9..0181776 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Ссылка на поставщика", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Сделать снимок", "@takePicture": {}, "targetDate": "Целевая дата", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Ошибка токена", "@tokenError": {}, "tokenMissing": "Отсутствует токен", diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 5db3f0a..6598ba4 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 85a96d9..7b2f759 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index 190516f..be72ae9 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index 65a7645..d21097e 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Leverantörens referens", "@supplierReference": {}, + "switchCamera": "Byt Kamera", + "@switchCamera": {}, "takePicture": "Ta bild", "@takePicture": {}, "targetDate": "Måldatum", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Aktivera lampa", + "@toggleTorch": {}, "tokenError": "Token fel", "@tokenError": {}, "tokenMissing": "Token saknas", diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index cf1300b..434106d 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index c7618b6..33c4546 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Tedarikçi Referansı", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Resim Çek", "@takePicture": {}, "targetDate": "Hedeflenen Tarih", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Hatası", "@tokenError": {}, "tokenMissing": "Eksik Token", diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 4985219..4d58c3a 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Supplier Reference", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Take Picture", "@takePicture": {}, "targetDate": "Target Date", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Token Error", "@tokenError": {}, "tokenMissing": "Missing Token", diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 789ab35..7529fb3 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "Tham khảo nhà cung cấp", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "Chụp ảnh", "@takePicture": {}, "targetDate": "Ngày", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "Lỗi Token", "@tokenError": {}, "tokenMissing": "Thiếu mã thông báo", diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index 2678229..d3596b9 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "供应商参考", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "拍照", "@takePicture": {}, "targetDate": "预计日期", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "令牌错误", "@tokenError": {}, "tokenMissing": "缺少令牌", diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 042331e..33b9ae3 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -978,6 +978,8 @@ "@suppliers": {}, "supplierReference": "供應商參考", "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, "takePicture": "拍照", "@takePicture": {}, "targetDate": "預計日期", @@ -1010,6 +1012,8 @@ "@timeout": { "description": "" }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, "tokenError": "令牌錯誤", "@tokenError": {}, "tokenMissing": "缺少令牌", From 13cb2f916492443892a9d8a3a964f11e43a4b22b Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Jun 2025 09:16:32 +1000 Subject: [PATCH 668/746] Docs url fix (#654) * Fix broken docs URL * Update release noets * const tweak --- assets/release_notes.md | 2 ++ lib/settings/about.dart | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index f8405aa..5c8aae7 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,8 @@ ### 0.19.0 - June 2025 --- - Replace barcode scanning library for better performance +- Fix broken documentation link +- Updated translations ### 0.18.1 - April 2025 --- diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 6bbd68e..27a5cd1 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -10,6 +10,8 @@ import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/l10.dart"; import "package:url_launcher/url_launcher.dart"; +const String DOCS_URL = "https://docs.inventree.org/app"; + class InvenTreeAboutWidget extends StatelessWidget { const InvenTreeAboutWidget(this.info) : super(); @@ -39,10 +41,7 @@ class InvenTreeAboutWidget extends StatelessWidget { Future _openDocs() async { - var docsUrl = Uri( - scheme: "https", - host: "docs.inventree.org", - path: "en/latest/app/app/"); + var docsUrl = Uri.parse(DOCS_URL); if (await canLaunchUrl(docsUrl)) { await launchUrl(docsUrl); @@ -192,7 +191,7 @@ class InvenTreeAboutWidget extends StatelessWidget { tiles.add( ListTile( title: Text(L10().documentation), - subtitle: Text("https://docs.inventree.org/app"), + subtitle: Text(DOCS_URL), leading: Icon(TablerIcons.book, color: COLOR_ACTION), onTap: () { _openDocs(); From 13abcae84cf4e43f7d1ee90e2b17f0397525067c Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Jun 2025 10:56:56 +1000 Subject: [PATCH 669/746] Part pricing detail (#655) * Implement part pricing data and new part pricing widget * improve part pricing widget and part pricing data. Add part pricing setting. * Refactor helper func * Tweak translated string * Refactor part pricing page * Update release notes * Fixes * More cleanup --------- Co-authored-by: JarEXE --- assets/release_notes.md | 1 + lib/helpers.dart | 34 ++++- lib/inventree/model.dart | 7 +- lib/inventree/part.dart | 73 +++++++++++ lib/l10n/app_en.arb | 56 +++++++- lib/preferences.dart | 1 + lib/settings/part_settings.dart | 16 +++ lib/widget/part/part_detail.dart | 60 ++++++++- lib/widget/part/part_pricing.dart | 198 +++++++++++++++++++++++++++++ lib/widget/stock/stock_detail.dart | 4 +- 10 files changed, 437 insertions(+), 13 deletions(-) create mode 100644 lib/widget/part/part_pricing.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index 5c8aae7..14d3df3 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,7 @@ ### 0.19.0 - June 2025 --- - Replace barcode scanning library for better performance +- Display part pricing information - Fix broken documentation link - Updated translations diff --git a/lib/helpers.dart b/lib/helpers.dart index 3a35d73..349a821 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -140,8 +140,7 @@ Future openLink(String url) async { */ String renderCurrency(double? amount, String currency, {int decimals = 2}) { - if (amount == null) return "-"; - if (amount.isInfinite || amount.isNaN) return "-"; + if (amount == null || amount.isInfinite || amount.isNaN) return "-"; currency = currency.trim(); @@ -157,3 +156,34 @@ String renderCurrency(double? amount, String currency, {int decimals = 2}) { return value; } +bool isValidNumber(double? value) { + return value != null && !value.isNaN && !value.isInfinite; +} + +/* + * Render a "range" of prices between two values. + */ +String formatPriceRange(double? minPrice, double? maxPrice, { String? currency }) { + + // Account for empty or null values + if (!isValidNumber(minPrice) && !isValidNumber(maxPrice)) { + return "-"; + } + + if (isValidNumber(minPrice) && isValidNumber(maxPrice)) { + // Two values are equal + if (minPrice == maxPrice) { + return renderCurrency(minPrice, currency ?? "USD"); + } else { + return "${renderCurrency(minPrice, currency ?? "USD")} - ${renderCurrency(maxPrice, currency ?? "USD")}"; + } + } + + if (isValidNumber(minPrice)) { + return renderCurrency(minPrice, currency ?? "USD"); + } else if (isValidNumber(maxPrice)) { + return renderCurrency(maxPrice, currency ?? "USD"); + } else { + return "-"; + } +} diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index af5b64b..07b74f8 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -142,7 +142,7 @@ class InvenTreeModel { } // Helper function to get double value from JSON data - double getDouble(String key, {double backup = 0.0, String subKey = ""}) { + double? getDoubleOrNull(String key, {double? backup, String subKey = ""}) { dynamic value = getValue(key, backup: backup, subKey: subKey); if (value == null) { @@ -152,6 +152,11 @@ class InvenTreeModel { return double.tryParse(value.toString()) ?? backup; } + double getDouble(String key, {double backup = 0.0, String subkey = "" }) { + double? value = getDoubleOrNull(key, backup: backup, subKey: subkey); + return value ?? backup; + } + // Helper function to get boolean value from json data bool getBool(String key, {bool backup = false, String subKey = ""}) { dynamic value = getValue(key, backup: backup, subKey: subKey); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 32c8e50..0aeec56 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -5,6 +5,7 @@ import "package:flutter/material.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; +import "package:inventree/inventree/sentry.dart"; import "package:inventree/l10.dart"; import "package:inventree/inventree/stock.dart"; @@ -287,6 +288,28 @@ class InvenTreePart extends InvenTreeModel { }); } + // Request pricing data for this part + Future getPricing() async { + + print("REQUEST PRICING FOR: ${pk}"); + + try { + final response = await InvenTreeAPI().get("/api/part/${pk}/pricing/"); + if (response.isValid()) { + final pricingData = response.data; + + if (pricingData is Map) { + return InvenTreePartPricing.fromJson(pricingData); + } + } + } catch (e, stackTrace) { + print("Exception while fetching pricing data for part $pk: $e"); + sentryReportError("getPricing", e, stackTrace); + } + + return null; + } + int get supplierCount => getInt("suppliers", backup: 0); // Request supplier parts for this part @@ -402,6 +425,8 @@ class InvenTreePart extends InvenTreeModel { bool get isVirtual => getBool("virtual"); + bool get isTemplate => getBool("is_template"); + bool get isTrackable => getBool("trackable"); // Get the IPN (internal part number) for the Part instance @@ -491,6 +516,54 @@ class InvenTreePart extends InvenTreeModel { InvenTreeModel createFromJson(Map json) => InvenTreePart.fromJson(json); } + +class InvenTreePartPricing extends InvenTreeModel { + + InvenTreePartPricing() : super(); + + InvenTreePartPricing.fromJson(Map json) : super.fromJson(json); + + @override + List get rolesRequired => ["part"]; + + @override + InvenTreeModel createFromJson(Map json) => InvenTreePartPricing.fromJson(json); + + // Price data accessors + String get currency => getString("currency", backup: "USD"); + + double? get overallMin => getDoubleOrNull("overall_min"); + double? get overallMax => getDoubleOrNull("overall_max"); + + double? get overrideMin => getDoubleOrNull("override_min"); + double? get overrideMax => getDoubleOrNull("override_max"); + + String get overrideMinCurrency => getString("override_min_currency", backup: currency); + String get overrideMaxCurrency => getString("override_max_currency", backup: currency); + + double? get bomCostMin => getDoubleOrNull("bom_cost_min"); + double? get bomCostMax => getDoubleOrNull("bom_cost_max"); + + double? get purchaseCostMin => getDoubleOrNull("purchase_cost_min"); + double? get purchaseCostMax => getDoubleOrNull("purchase_cost_max"); + + double? get internalCostMin => getDoubleOrNull("internal_cost_min"); + double? get internalCostMax => getDoubleOrNull("internal_cost_max"); + + double? get supplierPriceMin => getDoubleOrNull("supplier_price_min"); + double? get supplierPriceMax => getDoubleOrNull("supplier_price_max"); + + double? get variantCostMin => getDoubleOrNull("variant_cost_min"); + double? get variantCostMax => getDoubleOrNull("variant_cost_max"); + + double? get salePriceMin => getDoubleOrNull("sale_price_min"); + double? get salePriceMax => getDoubleOrNull("sale_price_max"); + + double? get saleHistoryMin => getDoubleOrNull("sale_history_min"); + double? get saleHistoryMax => getDoubleOrNull("sale_history_max"); +} + + /* * Class representing an attachment file against a Part object */ diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0915a4f..11a61b7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -850,6 +850,12 @@ "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "partSettings": "Part Settings", "@partSettings": {}, @@ -1592,5 +1598,53 @@ "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + + "price": "Price", + "@price": {}, + + "priceRange": "Price Range", + "@priceRange": {}, + + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + + "salePrice": "Sale Price", + "@salePrice": {}, + + "saleHistory": "Sale History", + "@saleHistory": {}, + + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + + "bomCost": "BOM Cost", + "@bomCost": {}, + + "internalCost": "Internal Cost", + "@internalCost": {}, + + "variantCost": "Variant Cost", + "@variantCost": {}, + + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + + "currency": "Currency", + "@currency": {}, + + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } diff --git a/lib/preferences.dart b/lib/preferences.dart index 8507cd3..0959ff5 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -30,6 +30,7 @@ const String INV_ENABLE_LABEL_PRINTING = "enableLabelPrinting"; // Part settings const String INV_PART_SHOW_PARAMETERS = "partShowParameters"; const String INV_PART_SHOW_BOM = "partShowBom"; +const String INV_PART_SHOW_PRICING = "partShowPricing"; // Stock settings const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 02952b6..5a8ccd2 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -19,6 +19,7 @@ class _InvenTreePartSettingsState extends State { bool partShowParameters = true; bool partShowBom = true; + bool partShowPricing = true; bool stockShowHistory = false; bool stockShowTests = false; bool stockConfirmScan = false; @@ -33,6 +34,7 @@ class _InvenTreePartSettingsState extends State { Future loadSettings() async { partShowParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); partShowBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); + partShowPricing = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PRICING, true); stockShowHistory = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_HISTORY, false); stockShowTests = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_TESTS, true); stockConfirmScan = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); @@ -81,6 +83,20 @@ class _InvenTreePartSettingsState extends State { }, ), ), + ListTile( + title: Text(L10().partPricing), + subtitle: Text(L10().partPricingSettingDetail), + leading: Icon(TablerIcons.currency_dollar), + trailing: Switch( + value: partShowPricing, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_PART_SHOW_PRICING, value); + setState(() { + partShowPricing = value; + }); + }, + ), + ), Divider(), ListTile( title: Text(L10().stockItemHistory), diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 51c7d01..ca4788e 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -18,6 +18,7 @@ import "package:inventree/widget/part/bom_list.dart"; import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/part/part_parameter_widget.dart"; +import "package:inventree/widget/part/part_pricing.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/refreshable_state.dart"; @@ -52,14 +53,18 @@ class _PartDisplayState extends RefreshableState { int parameterCount = 0; + bool allowLabelPrinting = false; bool showParameters = false; bool showBom = false; + bool showPricing = false; int attachmentCount = 0; int bomCount = 0; int usedInCount = 0; int variantCount = 0; + InvenTreePartPricing? partPricing; + List> labels = []; @override @@ -151,6 +156,12 @@ class _PartDisplayState extends RefreshableState { final bool result = await part.reload(); + // Load page settings from local storage + showPricing = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PRICING, true); + showParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); + showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); + allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + if (!result || part.pk == -1) { // Part could not be loaded, for some reason Navigator.of(context).pop(); @@ -179,9 +190,6 @@ class _PartDisplayState extends RefreshableState { } }); - // Request the number of parameters for this part - showParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); - // Request the number of attachments InvenTreePartAttachment().countAttachments(part.pk).then((int value) { if (mounted) { @@ -191,7 +199,16 @@ class _PartDisplayState extends RefreshableState { } }); - showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); + // If show pricing information? + if (showPricing) { + part.getPricing().then((InvenTreePartPricing? pricing) { + if (mounted) { + setState(() { + partPricing = pricing; + }); + } + }); + } // Request the number of BOM items InvenTreePart().count( @@ -233,7 +250,6 @@ class _PartDisplayState extends RefreshableState { }); List> _labels = []; - bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { @@ -271,8 +287,8 @@ class _PartDisplayState extends RefreshableState { Widget headerTile() { return Card( child: ListTile( - title: Text("${part.fullname}"), - subtitle: Text("${part.description}"), + title: Text(part.fullname), + subtitle: Text(part.description), trailing: Text( part.stockString(), style: TextStyle( @@ -425,6 +441,36 @@ class _PartDisplayState extends RefreshableState { ), ); + if (showPricing && partPricing != null) { + + String pricing = formatPriceRange( + partPricing?.overallMin, + partPricing?.overallMax, + currency: partPricing?.currency + ); + + tiles.add( + ListTile( + title: Text(L10().partPricing), + leading: Icon(TablerIcons.currency_dollar, color: COLOR_ACTION), + trailing: Text( + pricing.isNotEmpty ? pricing : L10().noPricingAvailable, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PartPricingWidget(part: part, partPricing: partPricing), + ), + ); + }, + ), + ); + } + // Tiles for "purchaseable" parts if (part.isPurchaseable) { diff --git a/lib/widget/part/part_pricing.dart b/lib/widget/part/part_pricing.dart new file mode 100644 index 0000000..62e709b --- /dev/null +++ b/lib/widget/part/part_pricing.dart @@ -0,0 +1,198 @@ +import "package:flutter/material.dart"; + +import "package:inventree/inventree/part.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/helpers.dart"; + +class PartPricingWidget extends StatefulWidget { + + const PartPricingWidget({Key? key, required this.part, required this.partPricing}) : super(key: key); + final InvenTreePart part; + final InvenTreePartPricing? partPricing; + + @override + _PartPricingWidgetState createState() => _PartPricingWidgetState(); +} + +class _PartPricingWidgetState extends RefreshableState { + + @override + String getAppBarTitle() { + return L10().partPricing; + } + + @override + List getTiles(BuildContext context) { + + List tiles = [ + Card( + child: ListTile( + title: Text(widget.part.fullname), + subtitle: Text(widget.part.description), + leading: api.getThumbnail(widget.part.thumbnail) + ) + ), + ]; + + if (widget.partPricing == null) { + tiles.add( + ListTile( + title: Text(L10().noPricingAvailable), + subtitle: Text(L10().noPricingDataFound), + ) + ); + + return tiles; + } + + final pricing = widget.partPricing!; + + tiles.add( + ListTile( + title: Text(L10().currency), + trailing: Text(pricing.currency), + ) + ); + + tiles.add( + ListTile( + title: Text(L10().priceRange), + trailing: Text( + formatPriceRange( + pricing.overallMin, + pricing.overallMax, + currency: pricing.currency + ) + ), + ) + ); + + if (pricing.overallMin != null) { + tiles.add( + ListTile( + title: Text(L10().priceOverrideMin), + trailing: Text( + renderCurrency(pricing.overallMin, pricing.overrideMinCurrency) + ) + ) + ); + } + + if (pricing.overrideMax != null) { + tiles.add( + ListTile( + title: Text(L10().priceOverrideMax), + trailing: Text( + renderCurrency(pricing.overallMax, pricing.overrideMaxCurrency) + ) + ) + ); + } + + tiles.add( + ListTile( + title: Text(L10().internalCost), + trailing: Text( + formatPriceRange( + pricing.internalCostMin, + pricing.internalCostMax, + currency: pricing.currency + ) + ), + ) + ); + + if (widget.part.isTemplate) { + tiles.add( + ListTile( + title: Text(L10().variantCost), + trailing: Text( + formatPriceRange( + pricing.variantCostMin, + pricing.variantCostMax, + currency: pricing.currency + ) + ), + ) + ); + } + + if (widget.part.isAssembly) { + tiles.add( + ListTile( + title: Text(L10().bomCost), + trailing: Text( + formatPriceRange( + pricing.bomCostMin, + pricing.bomCostMax, + currency: pricing.currency + ) + ) + ) + ); + } + + if (widget.part.isPurchaseable) { + tiles.add( + ListTile( + title: Text(L10().purchasePrice), + trailing: Text( + formatPriceRange( + pricing.purchaseCostMin, + pricing.purchaseCostMax, + currency: pricing.currency + ) + ), + ) + ); + + tiles.add( + ListTile( + title: Text(L10().supplierPricing), + trailing: Text( + formatPriceRange( + pricing.supplierPriceMin, + pricing.supplierPriceMax, + currency: pricing.currency + ) + ), + ) + ); + } + + if (widget.part.isSalable) { + tiles.add(Divider()); + + tiles.add( + ListTile( + title: Text(L10().salePrice), + trailing: Text( + formatPriceRange( + pricing.salePriceMin, + pricing.salePriceMax, + currency: pricing.currency + ) + ), + ) + ); + + tiles.add( + ListTile( + title: Text(L10().saleHistory), + trailing: Text( + formatPriceRange( + pricing.saleHistoryMin, + pricing.saleHistoryMax, + currency: pricing.currency + ) + ), + ) + ); + } + + return tiles; + } + +} diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index a3006fd..a5ef499 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -515,8 +515,8 @@ class _StockItemDisplayState extends RefreshableState { return Card( child: ListTile( - title: Text("${widget.item.partName}"), - subtitle: Text("${widget.item.partDescription}"), + title: Text(widget.item.partName), + subtitle: Text(widget.item.partDescription), leading: InvenTreeAPI().getThumbnail(widget.item.partImage), trailing: trailing, onTap: () async { From d4ba866e109819a79c4341eab80a2904654a28d1 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Sat, 14 Jun 2025 02:21:05 -0700 Subject: [PATCH 670/746] Use ruff to format Python files (#658) --- find_dart_files.py | 25 ++++++++------- lib/l10n/collect_translations.py | 55 ++++++++++++++++---------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/find_dart_files.py b/find_dart_files.py index a182daa..e71babd 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -10,18 +10,16 @@ Ref: https://github.com/flutter/flutter/issues/27997 from pathlib import Path -if __name__ == '__main__': - - dart_files = Path('lib').rglob('*.dart') +if __name__ == "__main__": + dart_files = Path("lib").rglob("*.dart") with open("test/coverage_helper_test.dart", "w") as f: - f.write("// ignore_for_file: unused_import\n\n") skips = [ - 'generated', - 'l10n', - 'dsn.dart', + "generated", + "l10n", + "dsn.dart", ] for path in dart_files: @@ -32,15 +30,18 @@ if __name__ == '__main__': # Remove leading 'lib\' text path = path[4:] - path = path.replace('\\', '/') + path = path.replace("\\", "/") f.write(f'import "package:inventree/{path}";\n') f.write("\n\n") - f.write("// DO NOT EDIT THIS FILE - it has been auto-generated by 'find_dart_files.py'\n") - f.write("// It has been created to ensure that *all* source file are included in coverage data\n") - - f.write('import "package:test/test.dart";\n\n'); + f.write( + "// DO NOT EDIT THIS FILE - it has been auto-generated by 'find_dart_files.py'\n" + ) + f.write( + "// It has been created to ensure that *all* source file are included in coverage data\n" + ) + f.write('import "package:test/test.dart";\n\n') f.write("// Do not actually test anything!\n") f.write("void main() {}\n") diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index 03148a6..a768632 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -16,6 +16,7 @@ from posixpath import dirname import shutil import re + def process_locale_file(filename, locale_name): """ Process a locale file after copying @@ -26,21 +27,20 @@ def process_locale_file(filename, locale_name): # TODO: Use JSON processing instead of manual # Need to work out unicode issues for this to work - with open(filename, 'r', encoding='utf-8') as input_file: - + with open(filename, "r", encoding="utf-8") as input_file: lines = input_file.readlines() - with open(filename, 'w', encoding='utf-8') as output_file: + with open(filename, "w", encoding="utf-8") as output_file: # Using JSON processing would be simpler here, # but it does not preserve unicode data! for line in lines: - if '@@locale' in line: + if "@@locale" in line: new_line = f' "@@locale": "{locale_name}"' - if ',' in line: - new_line += ',' - - new_line += '\n' + if "," in line: + new_line += "," + + new_line += "\n" line = new_line @@ -55,12 +55,10 @@ def copy_locale_file(path): here = os.path.abspath(os.path.dirname(__file__)) for f in os.listdir(path): - src = os.path.join(path, f) - dst = os.path.join(here, 'collected', f) - - if os.path.exists(src) and os.path.isfile(src) and f.endswith('.arb'): + dst = os.path.join(here, "collected", f) + if os.path.exists(src) and os.path.isfile(src) and f.endswith(".arb"): shutil.copyfile(src, dst) print(f"Copied file '{f}'") @@ -73,7 +71,7 @@ def copy_locale_file(path): locale = r.groups()[0] fallback = f"app_{locale}.arb" - fallback_file = os.path.join(here, 'collected', fallback) + fallback_file = os.path.join(here, "collected", fallback) if not os.path.exists(fallback_file): print(f"Creating fallback file:", fallback_file) @@ -87,18 +85,18 @@ def generate_locale_list(locales): Generate a .dart file which contains all the supported locales, for importing into the project """ - - with open("supported_locales.dart", "w") as output: - output.write("// This file is auto-generated by the 'collect_translations.py' script - do not edit it directly!\n\n") + with open("supported_locales.dart", "w") as output: + output.write( + "// This file is auto-generated by the 'collect_translations.py' script - do not edit it directly!\n\n" + ) output.write('import "package:flutter/material.dart";\n\n') output.write("const List supported_locales = [\n") locales = sorted(locales) for locale in locales: - - if locale.startswith('.'): + if locale.startswith("."): continue splt = locale.split("_") @@ -107,19 +105,21 @@ def generate_locale_list(locales): lc, cc = splt else: lc = locale - cc = '' - - output.write(f' Locale("{lc}", "{cc}"), // Translations available in app_{locale}.arb\n') + cc = "" + + output.write( + f' Locale("{lc}", "{cc}"), // Translations available in app_{locale}.arb\n' + ) output.write("];\n") output.write("") -if __name__ == '__main__': +if __name__ == "__main__": here = os.path.abspath(os.path.dirname(__file__)) # Ensure the 'collected' output directory exists - output_dir = os.path.join(here, 'collected') + output_dir = os.path.join(here, "collected") os.makedirs(output_dir, exist_ok=True) # Remove existing .arb files from output directory @@ -128,12 +128,11 @@ if __name__ == '__main__': for arb in arbs: os.remove(arb) - locales = ['en'] + locales = ["en"] for locale in os.listdir(here): - # Ignore the output directory - if locale == 'collected': + if locale == "collected": continue f = os.path.join(here, locale) @@ -144,8 +143,8 @@ if __name__ == '__main__': # Ensure the translation source file ('app_en.arb') is copied also # Note that this does not require any further processing - src = os.path.join(here, 'app_en.arb') - dst = os.path.join(here, 'collected', 'app_en.arb') + src = os.path.join(here, "app_en.arb") + dst = os.path.join(here, "collected", "app_en.arb") shutil.copyfile(src, dst) From d6515063150cb610c54ed5f8366fcc39f93a7da6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 14 Jun 2025 19:22:57 +1000 Subject: [PATCH 671/746] New Crowdin updates (#657) * New translations app_en.arb (French) * New translations app_en.arb (German) * New translations app_en.arb (Romanian) * New translations app_en.arb (Spanish) * New translations app_en.arb (Arabic) * New translations app_en.arb (Bulgarian) * New translations app_en.arb (Czech) * New translations app_en.arb (Danish) * New translations app_en.arb (Greek) * New translations app_en.arb (Finnish) * New translations app_en.arb (Hebrew) * New translations app_en.arb (Hungarian) * New translations app_en.arb (Italian) * New translations app_en.arb (Japanese) * New translations app_en.arb (Korean) * New translations app_en.arb (Lithuanian) * New translations app_en.arb (Dutch) * New translations app_en.arb (Norwegian) * New translations app_en.arb (Polish) * New translations app_en.arb (Portuguese) * New translations app_en.arb (Russian) * New translations app_en.arb (Slovak) * New translations app_en.arb (Slovenian) * New translations app_en.arb (Swedish) * New translations app_en.arb (Turkish) * New translations app_en.arb (Ukrainian) * New translations app_en.arb (Chinese Simplified) * New translations app_en.arb (Chinese Traditional) * New translations app_en.arb (Vietnamese) * New translations app_en.arb (Portuguese, Brazilian) * New translations app_en.arb (Indonesian) * New translations app_en.arb (Persian) * New translations app_en.arb (Spanish, Mexico) * New translations app_en.arb (Thai) * New translations app_en.arb (Estonian) * New translations app_en.arb (Latvian) * New translations app_en.arb (Hindi) * New translations app_en.arb (Serbian (Latin)) --- lib/l10n/ar_SA/app_ar_SA.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/bg_BG/app_bg_BG.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/cs_CZ/app_cs_CZ.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/da_DK/app_da_DK.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/de_DE/app_de_DE.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/el_GR/app_el_GR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/es_ES/app_es_ES.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/es_MX/app_es_MX.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/et_EE/app_et_EE.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/fa_IR/app_fa_IR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/fi_FI/app_fi_FI.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/fr_FR/app_fr_FR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/he_IL/app_he_IL.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/hi_IN/app_hi_IN.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/hu_HU/app_hu_HU.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/id_ID/app_id_ID.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/it_IT/app_it_IT.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/ja_JP/app_ja_JP.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/ko_KR/app_ko_KR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/lt_LT/app_lt_LT.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/lv_LV/app_lv_LV.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/nl_NL/app_nl_NL.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/no_NO/app_no_NO.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/pl_PL/app_pl_PL.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/pt_BR/app_pt_BR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/pt_PT/app_pt_PT.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/ro_RO/app_ro_RO.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/ru_RU/app_ru_RU.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/sk_SK/app_sk_SK.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/sl_SI/app_sl_SI.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/sr_CS/app_sr_CS.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/sv_SE/app_sv_SE.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/th_TH/app_th_TH.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/tr_TR/app_tr_TR.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/uk_UA/app_uk_UA.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/vi_VN/app_vi_VN.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/zh_CN/app_zh_CN.arb | 38 +++++++++++++++++++++++++++++++++++- lib/l10n/zh_TW/app_zh_TW.arb | 38 +++++++++++++++++++++++++++++++++++- 38 files changed, 1406 insertions(+), 38 deletions(-) diff --git a/lib/l10n/ar_SA/app_ar_SA.arb b/lib/l10n/ar_SA/app_ar_SA.arb index 3f68ebc..987d6c6 100644 --- a/lib/l10n/ar_SA/app_ar_SA.arb +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/bg_BG/app_bg_BG.arb b/lib/l10n/bg_BG/app_bg_BG.arb index 3e9ba97..6740c8a 100644 --- a/lib/l10n/bg_BG/app_bg_BG.arb +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb index 247637a..88810e7 100644 --- a/lib/l10n/cs_CZ/app_cs_CZ.arb +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Žádné díly neodpovídají dotazu", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Nastavení dílu", "@partSettings": {}, "partsStarred": "Odebírané díly", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Zobrazit díl dodavatele", "@viewSupplierPart": {}, "website": "Webová stránka", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/da_DK/app_da_DK.arb b/lib/l10n/da_DK/app_da_DK.arb index fc96b01..b325f50 100644 --- a/lib/l10n/da_DK/app_da_DK.arb +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/de_DE/app_de_DE.arb b/lib/l10n/de_DE/app_de_DE.arb index d4fb72f..11ac52b 100644 --- a/lib/l10n/de_DE/app_de_DE.arb +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Keine Teile entsprechen der Anfrage", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Teil-Einstellungen", "@partSettings": {}, "partsStarred": "Abonnierte Teile", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Zulieferer-Teil anzeigen", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/el_GR/app_el_GR.arb b/lib/l10n/el_GR/app_el_GR.arb index b97937a..2351ef7 100644 --- a/lib/l10n/el_GR/app_el_GR.arb +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/es_ES/app_es_ES.arb b/lib/l10n/es_ES/app_es_ES.arb index e45bb9f..64e31e0 100644 --- a/lib/l10n/es_ES/app_es_ES.arb +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No hay piezas que coincidan", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Configuración de partes", "@partSettings": {}, "partsStarred": "Piezas destacadas", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Ver pieza del proveedor", "@viewSupplierPart": {}, "website": "Sitio Web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/es_MX/app_es_MX.arb b/lib/l10n/es_MX/app_es_MX.arb index c24b543..5596058 100644 --- a/lib/l10n/es_MX/app_es_MX.arb +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No hay partes que coincidan", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Ajustes de partes", "@partSettings": {}, "partsStarred": "Partes Suscritas", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Ver Parte de Proveedor", "@viewSupplierPart": {}, "website": "Sitio web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/et_EE/app_et_EE.arb b/lib/l10n/et_EE/app_et_EE.arb index 6eaa0b1..0cd1e01 100644 --- a/lib/l10n/et_EE/app_et_EE.arb +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Koduleht", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/fa_IR/app_fa_IR.arb b/lib/l10n/fa_IR/app_fa_IR.arb index 0e51eb7..8bcf061 100644 --- a/lib/l10n/fa_IR/app_fa_IR.arb +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "هیچ قطعه ای مطابق با جست و جو یافت نشد", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "تنظیمات قطعه", "@partSettings": {}, "partsStarred": "قطعه مشترک", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "نمایش قطعه تامین کننده", "@viewSupplierPart": {}, "website": "وب سایت", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/fi_FI/app_fi_FI.arb b/lib/l10n/fi_FI/app_fi_FI.arb index af9e7d5..5dafb94 100644 --- a/lib/l10n/fi_FI/app_fi_FI.arb +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Ei hakua vastaavia osia", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Osan asetukset", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Sivusto", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index ea28e7e..0c24bf0 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Pas de pièces correspondant à la requête", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Paramètres de la pièce", "@partSettings": {}, "partsStarred": "Pièces suivies", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Voir la pièce du fournisseur", "@viewSupplierPart": {}, "website": "Site web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/he_IL/app_he_IL.arb b/lib/l10n/he_IL/app_he_IL.arb index 721cead..bee67ce 100644 --- a/lib/l10n/he_IL/app_he_IL.arb +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "אין פריטים התואמים לשאילתה", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "הגדרות פריט", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "צפה בפריט הספק", "@viewSupplierPart": {}, "website": "אתר", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/hi_IN/app_hi_IN.arb b/lib/l10n/hi_IN/app_hi_IN.arb index 9a854ad..76e48cf 100644 --- a/lib/l10n/hi_IN/app_hi_IN.arb +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/hu_HU/app_hu_HU.arb b/lib/l10n/hu_HU/app_hu_HU.arb index 50f83b1..c26f18d 100644 --- a/lib/l10n/hu_HU/app_hu_HU.arb +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Alkatrész beállítások", "@partSettings": {}, "partsStarred": "Értesítésre beállított alkatrészek", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Beszállítói alkatrész megtekintése", "@viewSupplierPart": {}, "website": "Weboldal", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/id_ID/app_id_ID.arb b/lib/l10n/id_ID/app_id_ID.arb index c9cf87e..062b937 100644 --- a/lib/l10n/id_ID/app_id_ID.arb +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Tidak ada Part yang cocok dengan kueri", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Pengaturan Part", "@partSettings": {}, "partsStarred": "Part yang disubcribe", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Situs", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/it_IT/app_it_IT.arb b/lib/l10n/it_IT/app_it_IT.arb index 06047dd..bbed74a 100644 --- a/lib/l10n/it_IT/app_it_IT.arb +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Nessun articolo corrispondente alla ricerca", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Impostazioni articolo", "@partSettings": {}, "partsStarred": "Articoli Sottoscritti", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Visualizza Fornitore", "@viewSupplierPart": {}, "website": "Sito Web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/ja_JP/app_ja_JP.arb b/lib/l10n/ja_JP/app_ja_JP.arb index 9ddb254..95d343f 100644 --- a/lib/l10n/ja_JP/app_ja_JP.arb +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "クエリに一致する部品がありません", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "部品設定", "@partSettings": {}, "partsStarred": "購読済み部品", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "サプライヤー部品を表示", "@viewSupplierPart": {}, "website": "Webサイト", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/ko_KR/app_ko_KR.arb b/lib/l10n/ko_KR/app_ko_KR.arb index 2ca6509..502ab59 100644 --- a/lib/l10n/ko_KR/app_ko_KR.arb +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "웹사이트", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/lt_LT/app_lt_LT.arb b/lib/l10n/lt_LT/app_lt_LT.arb index 8fc041c..dde8345 100644 --- a/lib/l10n/lt_LT/app_lt_LT.arb +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/lv_LV/app_lv_LV.arb b/lib/l10n/lv_LV/app_lv_LV.arb index f54355b..562756c 100644 --- a/lib/l10n/lv_LV/app_lv_LV.arb +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/nl_NL/app_nl_NL.arb b/lib/l10n/nl_NL/app_nl_NL.arb index 9f2ad83..c1b3f80 100644 --- a/lib/l10n/nl_NL/app_nl_NL.arb +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Onderdeel instellingen", "@partSettings": {}, "partsStarred": "Geabonneerde Onderdelen", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Bekijk Leverancier van Onderdeel", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/no_NO/app_no_NO.arb b/lib/l10n/no_NO/app_no_NO.arb index a24ad61..6acd23c 100644 --- a/lib/l10n/no_NO/app_no_NO.arb +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Ingen deler samsvarer med spørringen", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Innstillinger for del", "@partSettings": {}, "partsStarred": "Abonnerte deler", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Vis leverandørdel", "@viewSupplierPart": {}, "website": "Nettside", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/pl_PL/app_pl_PL.arb b/lib/l10n/pl_PL/app_pl_PL.arb index b200931..607a5d6 100644 --- a/lib/l10n/pl_PL/app_pl_PL.arb +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Brak komponentów pasujących do zapytania", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Ustawienia części", "@partSettings": {}, "partsStarred": "Obserwowane części", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Zobacz Dostawcę Części", "@viewSupplierPart": {}, "website": "Strona WWW", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/pt_BR/app_pt_BR.arb b/lib/l10n/pt_BR/app_pt_BR.arb index 3ccc09b..ce240f7 100644 --- a/lib/l10n/pt_BR/app_pt_BR.arb +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Nenhuma peça corresponde a consulta", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Configurações de Peça", "@partSettings": {}, "partsStarred": "Peças subscritas", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Ver peça do fornecedor", "@viewSupplierPart": {}, "website": "Página Web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/pt_PT/app_pt_PT.arb b/lib/l10n/pt_PT/app_pt_PT.arb index 1807679..aa0f361 100644 --- a/lib/l10n/pt_PT/app_pt_PT.arb +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/ro_RO/app_ro_RO.arb b/lib/l10n/ro_RO/app_ro_RO.arb index e7421e7..0887744 100644 --- a/lib/l10n/ro_RO/app_ro_RO.arb +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Nicio piesă care se potrivește", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Setări Piesa", "@partSettings": {}, "partsStarred": "Piese Abonate", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/ru_RU/app_ru_RU.arb b/lib/l10n/ru_RU/app_ru_RU.arb index 0181776..2b3c886 100644 --- a/lib/l10n/ru_RU/app_ru_RU.arb +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Нет компонентов, соответствующих запросу", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Настройки деталей", "@partSettings": {}, "partsStarred": "Детали с включёнными уведомлениями", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Отобразить деталь поставщика", "@viewSupplierPart": {}, "website": "Сайт", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/sk_SK/app_sk_SK.arb b/lib/l10n/sk_SK/app_sk_SK.arb index 6598ba4..bfa0e53 100644 --- a/lib/l10n/sk_SK/app_sk_SK.arb +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/sl_SI/app_sl_SI.arb b/lib/l10n/sl_SI/app_sl_SI.arb index 7b2f759..15d9589 100644 --- a/lib/l10n/sl_SI/app_sl_SI.arb +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/sr_CS/app_sr_CS.arb b/lib/l10n/sr_CS/app_sr_CS.arb index be72ae9..9b11805 100644 --- a/lib/l10n/sr_CS/app_sr_CS.arb +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/sv_SE/app_sv_SE.arb b/lib/l10n/sv_SE/app_sv_SE.arb index d21097e..94e0132 100644 --- a/lib/l10n/sv_SE/app_sv_SE.arb +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Inga artiklar som matchar sökfrågan", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Artikel inställningar", "@partSettings": {}, "partsStarred": "Prenumererade artiklar", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Visa leverantörsartikel", "@viewSupplierPart": {}, "website": "Webbplats", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/th_TH/app_th_TH.arb b/lib/l10n/th_TH/app_th_TH.arb index 434106d..ddd2a07 100644 --- a/lib/l10n/th_TH/app_th_TH.arb +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "No parts matching query", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Part Settings", "@partSettings": {}, "partsStarred": "Subscribed Parts", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 33c4546..87a7b51 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Sorguyla eşleşen parça yok", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Parça Ayarları", "@partSettings": {}, "partsStarred": "Sürekli Gelen parçalar", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Tedarikçi Parçası Görüntüle", "@viewSupplierPart": {}, "website": "Web sitesi", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/uk_UA/app_uk_UA.arb b/lib/l10n/uk_UA/app_uk_UA.arb index 4d58c3a..dbc813f 100644 --- a/lib/l10n/uk_UA/app_uk_UA.arb +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Немає позицій відповідних запиту", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Налаштування позиції", "@partSettings": {}, "partsStarred": "Підписані позиції", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "View Supplier Part", "@viewSupplierPart": {}, "website": "Website", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/vi_VN/app_vi_VN.arb b/lib/l10n/vi_VN/app_vi_VN.arb index 7529fb3..cbe20d5 100644 --- a/lib/l10n/vi_VN/app_vi_VN.arb +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "Không có phụ kiện nào phù hợp", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "Cài đặt phụ kiện", "@partSettings": {}, "partsStarred": "Đăng kí phụ kiện", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "Xem nhà cung cấp phụ kiện", "@viewSupplierPart": {}, "website": "Trang web", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/zh_CN/app_zh_CN.arb b/lib/l10n/zh_CN/app_zh_CN.arb index d3596b9..520795b 100644 --- a/lib/l10n/zh_CN/app_zh_CN.arb +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "没有匹配查询的零件", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "零件设置", "@partSettings": {}, "partsStarred": "订阅的零件", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "查看供应商零件", "@viewSupplierPart": {}, "website": "网站", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file diff --git a/lib/l10n/zh_TW/app_zh_TW.arb b/lib/l10n/zh_TW/app_zh_TW.arb index 33b9ae3..476ef29 100644 --- a/lib/l10n/zh_TW/app_zh_TW.arb +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -574,6 +574,10 @@ "@partsNone": {}, "partNoResults": "沒有匹配查詢的零件", "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, "partSettings": "零件設置", "@partSettings": {}, "partsStarred": "訂閲的零件", @@ -1079,5 +1083,37 @@ "viewSupplierPart": "查看供應商零件", "@viewSupplierPart": {}, "website": "網站", - "@website": {} + "@website": {}, + "price": "Price", + "@price": {}, + "priceRange": "Price Range", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Sale Price", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Currency", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@priceBreaks": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {} } \ No newline at end of file From cf012b2531549b5725f538abb40f148b10c2004d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 21 Jun 2025 10:29:17 +1000 Subject: [PATCH 672/746] New Crowdin updates (#659) * New translations app_en.arb (Turkish) * New translations app_en.arb (French) --- lib/l10n/fr_FR/app_fr_FR.arb | 6 +++--- lib/l10n/tr_TR/app_tr_TR.arb | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 0c24bf0..8cdad55 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -1084,15 +1084,15 @@ "@viewSupplierPart": {}, "website": "Site web", "@website": {}, - "price": "Price", + "price": "Prix", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Fourchette de prix", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Prix de vente", "@salePrice": {}, "saleHistory": "Sale History", "@saleHistory": {}, diff --git a/lib/l10n/tr_TR/app_tr_TR.arb b/lib/l10n/tr_TR/app_tr_TR.arb index 87a7b51..a9a80f2 100644 --- a/lib/l10n/tr_TR/app_tr_TR.arb +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -574,9 +574,9 @@ "@partsNone": {}, "partNoResults": "Sorguyla eşleşen parça yok", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Parça Fiyatlandırma", "@partPricing": {}, - "partPricingSettingDetail": "Display part pricing information", + "partPricingSettingDetail": "Parça fiyatlandırma bilgisini görüntüle", "@pricingSettingDetail": {}, "partSettings": "Parça Ayarları", "@partSettings": {}, @@ -982,7 +982,7 @@ "@suppliers": {}, "supplierReference": "Tedarikçi Referansı", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Kamerayı Değiştir", "@switchCamera": {}, "takePicture": "Resim Çek", "@takePicture": {}, @@ -1016,7 +1016,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Feneri Aç/Kapat", "@toggleTorch": {}, "tokenError": "Token Hatası", "@tokenError": {}, @@ -1084,36 +1084,36 @@ "@viewSupplierPart": {}, "website": "Web sitesi", "@website": {}, - "price": "Price", + "price": "Fiyat", "@price": {}, - "priceRange": "Price Range", + "priceRange": "Fiyat Aralığı", "@priceRange": {}, "priceOverrideMin": "Minimum Price Override", "@priceOverrideMin": {}, "priceOverrideMax": "Maximum Price Override", "@priceOverrideMax": {}, - "salePrice": "Sale Price", + "salePrice": "Satış Fiyatı", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Satış Geçmişi", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Sağlayıcı Fiyatlandırması", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "BoM Maliyeti", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Dahili Maliyet", "@internalCost": {}, - "variantCost": "Variant Cost", + "variantCost": "Türev Maliyeti", "@variantCost": {}, - "overallPricing": "Overall Pricing", + "overallPricing": "Genel Fiyatlandırma", "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Para Birimi", "@currency": {}, "priceBreaks": "Price Breaks", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Fiyatlandırma mevcut değil", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Bu parça için fiyatlandırma verisi bulunamadı", "@noPricingDataFound": {} } \ No newline at end of file From c4e33a4c1a9129fe114c0aa07137c1c06ea4b131 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Mon, 23 Jun 2025 11:42:05 +0200 Subject: [PATCH 673/746] Use FVM in GitHub Actions and migrate to Flutter 3.32.4 (#641) * feat: implement Flutter version management using FVM across CI workflows * Flutter 3.29.3 + minor Package upgrades * Replace deprecated `withOpacity` * Upgrade major package versions without breaking changes. * Disable unnecessary_async rule Re-enable later * New language version and automated fixes - unnecessary_breaks - unnecessary_underscore * Update BUILDING.md to use fvm commands * Add gitignore files for Android and iOS build artifacts * Migrate iOS dependencies to Swift Package Manager This is being done automatically by Flutter * Flutter 3.32.4 * New sdk version * docs: add IDE setup instructions and troubleshooting guide for FVM integration --- .fvmrc | 3 + .github/workflows/android.yaml | 22 +- .github/workflows/ci.yaml | 21 +- .github/workflows/ios.yaml | 17 +- .gitignore | 3 + BUILDING.md | 74 +++- analysis_options.yaml | 3 + android/.gitignore | 14 + docs/android_studio_fvm.png | Bin 0 -> 143132 bytes ios/.gitignore | 34 ++ ios/Runner.xcodeproj/project.pbxproj | 54 +-- .../xcshareddata/swiftpm/Package.resolved | 69 +++ .../xcshareddata/xcschemes/Runner.xcscheme | 19 + .../xcshareddata/swiftpm/Package.resolved | 69 +++ lib/api.dart | 4 - lib/api_form.dart | 11 - lib/barcode/barcode.dart | 3 +- lib/barcode/camera_controller.dart | 109 ++--- lib/inventree/model.dart | 2 - lib/main.dart | 3 - lib/settings/app_settings.dart | 3 - lib/settings/barcode_settings.dart | 2 - lib/widget/dialogs.dart | 2 - lib/widget/part/part_suppliers.dart | 2 +- pubspec.lock | 400 ++++++++++-------- pubspec.yaml | 7 +- tasks.py | 10 +- 27 files changed, 630 insertions(+), 330 deletions(-) create mode 100644 .fvmrc create mode 100644 android/.gitignore create mode 100644 docs/android_studio_fvm.png create mode 100644 ios/.gitignore create mode 100644 ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..984aec1 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.32.4" +} \ No newline at end of file diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index c1e2a00..117c9a8 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -15,25 +15,39 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + - name: Setup Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - - name: Setup Flutter - uses: subosito/flutter-action@v2 + + - name: Setup FVM + id: fvm-config-action + uses: kuhnroyal/flutter-fvm-config-action@v2 + + - uses: subosito/flutter-action@v2 with: - flutter-version: '3.32.2' - channel: 'stable' + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" + pub-cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + - run: flutter --version + - name: Setup Gradle uses: gradle/gradle-build-action@v2.4.2 with: gradle-version: 8.7 + - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py + - name: Build for Android run: | flutter pub get diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 19e2024..0dddcf8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,19 +29,32 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive + - name: Setup Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' - - name: Setup Flutter - uses: subosito/flutter-action@v2 + + - name: Setup Flutter and FVM + id: fvm-config-action + uses: kuhnroyal/flutter-fvm-config-action@v2 + + - uses: subosito/flutter-action@v2 with: - flutter-version: '3.32.2' + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" + pub-cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py + - name: Static Analysis Tests run: | python3 find_dart_files.py @@ -52,6 +65,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.9 + - name: Start InvenTree Server run: | sudo apt-get install python3-dev python3-pip python3-venv python3-wheel g++ @@ -64,6 +78,7 @@ jobs: invoke dev.server -a 127.0.0.1:8000 & invoke wait sleep 30 + - name: Unit Tests run: | flutter test --coverage diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml index 2dc8235..53e8a30 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -17,20 +17,33 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive + - name: Setup Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' + + - name: Setup FVM + id: fvm-config-action + uses: kuhnroyal/flutter-fvm-config-action@v2 + - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.32.2' - channel: 'stable' + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" + pub-cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + - name: Collect Translation Files run: | cd lib/l10n python3 collect_translations.py + - name: Build for iOS run: | flutter pub get diff --git a/.gitignore b/.gitignore index 96b3528..8effbf9 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,6 @@ ios/Podfile.lock !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/BUILDING.md b/BUILDING.md index 9e1d3fe..c05e8e7 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -6,7 +6,8 @@ For developers looking to contribute to the project, we use Flutter for app deve To build the app from source, you will need the following tools installed on your system: -- Android Studio (with Flutter and Dart plugins) +- Android Studio or Visual Studio Code (with Flutter and Dart plugins) +- [Flutter Version Management (FVM)](https://fvm.app/) - We use FVM to manage Flutter versions ### iOS Development @@ -19,13 +20,61 @@ Some versions of Android Studio ship with a built-in version of the Java JDK. Ho If you see any errors related to JDK version mismatch, download and install the correct version of the JDK (from the link above) and update your Android Studio settings to point to the correct JDK location: ```bash -flutter config --jdk-dir /path/to/jdk +fvm flutter config --jdk-dir /path/to/jdk ``` ## Invoke Tasks We use the [invoke](https://www.pyinvoke.org) to run some core tasks - you will need python and invoke installed on your local system. +## Flutter Version Management (FVM) + +This project uses [Flutter Version Management (FVM)](https://fvm.app/) to ensure consistent Flutter versions across development environments and CI/CD pipelines. + +For installation instructions, please refer to the [official FVM documentation](https://fvm.app/documentation/getting-started/installation). + +Once installed, FVM will automatically use the Flutter version specified in the `.fvmrc` file at the root of the project. + +### Visual Studio Code + +To set up Visual Studio Code, you will need to make sure the `.vscode` directory exists. Then run `fvm use` to ensure the correct Flutter version is used. + +``` +mkdir -p .vscode +fvm use +``` + +#### What happens: +- Downloads SDK if not cached +- Creates `.fvm` directory with SDK symlink +- Updates `.fvmrc` configuration +- Configures IDE settings +- Runs `flutter pub get` + + +### Android Studio + +To set up Android Studio, run `fvm use` to ensure the correct Flutter version is used. + +``` +fvm use +``` + +#### What happens: +- Downloads SDK if not cached +- Creates `.fvm` directory with SDK symlink +- Updates `.fvmrc` configuration +- Runs `flutter pub get` + +Set Flutter SDK path in Android Studio: + +1. Open Android Studio +2. Go to `File` -> `Settings` -> `Languages & Frameworks` -> `Flutter` +3. Set `Flutter SDK path` to `.fvm/flutter_sdk`: + +![Setting Flutter SDK path in Android Studio](android_studio_fvm.png) + + ## Getting Started Initial project setup (after you have installed all required dev tools) is as follows: @@ -38,11 +87,30 @@ invoke translate Install required flutter packages: ``` -flutter pub get +fvm flutter pub get ``` You should now be ready to debug on a connected or emulated device! +## Troubleshooting + +### Flutter Doctor + +If you're experiencing issues with the development environment, run Flutter Doctor to diagnose problems: + +```bash +fvm flutter doctor -v +``` + +This will check your Flutter installation and identify any issues with your setup. Common issues include: + +- Missing Android SDK components +- iOS development tools not properly configured +- Missing dependencies + +Fix any identified issues before proceeding with development. + + ## Building Release Versions Building release versions for target platforms (either android or iOS) is simplified using invoke: diff --git a/analysis_options.yaml b/analysis_options.yaml index c470bae..eed06a4 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -80,3 +80,6 @@ linter: use_super_parameters: false + # TODO: Enable unnecessary_async and unawaited_futures rules + unnecessary_async: false + diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..97a5d13 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks \ No newline at end of file diff --git a/docs/android_studio_fvm.png b/docs/android_studio_fvm.png new file mode 100644 index 0000000000000000000000000000000000000000..4d497b9083518ac3f3e8cf8449e7b73b7e1dff88 GIT binary patch literal 143132 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�l+)(G!9%+SE^@XAC%)?uOXQA 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 KS9~z~^nU;ZYNp@- literal 0 HcmV?d00001 diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..0ca5a97 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index bda4a2a..0e0897d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -56,6 +57,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, D95D9CD46BE28F7F69DBC0F6 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -157,6 +159,9 @@ dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -186,6 +191,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -270,47 +278,15 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", - "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", - "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/audioplayers_darwin/audioplayers_darwin.framework", - "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework", - "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", - "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/flutter_zxing/flutter_zxing.framework", - "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", "${BUILT_PRODUCTS_DIR}/open_filex/open_filex.framework", - "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", - "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", - "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", - "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", - "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", - "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers_darwin.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_zxing.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_filex.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -640,6 +616,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..819c57b --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,69 @@ +{ + "originHash" : "820af3cc63f10647eb1a29c6d280a54dd695478a4b5abdddf411bf17c43695a0", + "pins" : [ + { + "identity" : "dkcamera", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKCamera", + "state" : { + "branch" : "master", + "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" + } + }, + { + "identity" : "dkimagepickercontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKImagePickerController", + "state" : { + "branch" : "4.3.9", + "revision" : "0bdfeacefa308545adde07bef86e349186335915" + } + }, + { + "identity" : "dkphotogallery", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKPhotoGallery", + "state" : { + "branch" : "master", + "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" + } + }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage", + "state" : { + "revision" : "cac9a55a3ae92478a2c95042dcc8d9695d2129ca", + "version" : "5.21.0" + } + }, + { + "identity" : "sentry-cocoa", + "kind" : "remoteSourceControl", + "location" : "https://github.com/getsentry/sentry-cocoa", + "state" : { + "revision" : "491c87a32af58414bd03825b3029526640d3e73d", + "version" : "8.50.0" + } + }, + { + "identity" : "swiftygif", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kirualex/SwiftyGif.git", + "state" : { + "revision" : "4430cbc148baa3907651d40562d96325426f409a", + "version" : "5.4.5" + } + }, + { + "identity" : "tocropviewcontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TimOliver/TOCropViewController", + "state" : { + "revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b", + "version" : "2.7.4" + } + } + ], + "version" : 3 +} diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d..128d576 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..819c57b --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,69 @@ +{ + "originHash" : "820af3cc63f10647eb1a29c6d280a54dd695478a4b5abdddf411bf17c43695a0", + "pins" : [ + { + "identity" : "dkcamera", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKCamera", + "state" : { + "branch" : "master", + "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" + } + }, + { + "identity" : "dkimagepickercontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKImagePickerController", + "state" : { + "branch" : "4.3.9", + "revision" : "0bdfeacefa308545adde07bef86e349186335915" + } + }, + { + "identity" : "dkphotogallery", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKPhotoGallery", + "state" : { + "branch" : "master", + "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" + } + }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage", + "state" : { + "revision" : "cac9a55a3ae92478a2c95042dcc8d9695d2129ca", + "version" : "5.21.0" + } + }, + { + "identity" : "sentry-cocoa", + "kind" : "remoteSourceControl", + "location" : "https://github.com/getsentry/sentry-cocoa", + "state" : { + "revision" : "491c87a32af58414bd03825b3029526640d3e73d", + "version" : "8.50.0" + } + }, + { + "identity" : "swiftygif", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kirualex/SwiftyGif.git", + "state" : { + "revision" : "4430cbc148baa3907651d40562d96325426f409a", + "version" : "5.4.5" + } + }, + { + "identity" : "tocropviewcontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TimOliver/TOCropViewController", + "state" : { + "revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b", + "version" : "2.7.4" + } + } + ], + "version" : 3 +} diff --git a/lib/api.dart b/lib/api.dart index aee6949..c8e706f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -593,10 +593,8 @@ class InvenTreeAPI { L10().serverAuthenticationError, L10().invalidUsernamePassword, ); - break; default: showStatusCodeError(apiUrl, response.statusCode); - break; } debug("Token request failed: STATUS ${response.statusCode}"); @@ -1342,7 +1340,6 @@ class InvenTreeAPI { "responseData": response.data.toString(), } ); - break; } } else { @@ -1414,7 +1411,6 @@ class InvenTreeAPI { "endpoint": url, } ); - break; } showServerError( diff --git a/lib/api_form.dart b/lib/api_form.dart index c1cabbd..75ea5d9 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1171,7 +1171,6 @@ class _APIFormWidgetState extends State { case "related field": case "choice": widgets.add(Divider(height: 15)); - break; default: break; } @@ -1202,10 +1201,8 @@ class _APIFormWidgetState extends State { case "choice": widgets.add(Divider(height: 15)); spacerRequired = false; - break; default: spacerRequired = true; - break; } } @@ -1344,7 +1341,6 @@ class _APIFormWidgetState extends State { } } - break; } if (!match) { @@ -1473,43 +1469,36 @@ class _APIFormWidgetState extends State { extractNonFieldErrors(response); checkInvalidErrors(response); - break; case 401: showSnackIcon( "401: " + L10().response401, success: false ); - break; case 403: showSnackIcon( "403: " + L10().response403, success: false, ); - break; case 404: showSnackIcon( "404: " + L10().response404, success: false, ); - break; case 405: showSnackIcon( "405: " + L10().response405, success: false, ); - break; case 500: showSnackIcon( "500: " + L10().response500, success: false, ); - break; default: showSnackIcon( "${response.statusCode}: " + L10().responseInvalid, success: false, ); - break; } setState(() { diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 0de089e..7cd2f0f 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -88,7 +88,6 @@ Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) asy switch (barcodeControllerType) { case BARCODE_CONTROLLER_WEDGE: controller = WedgeBarcodeController(handler); - break; case BARCODE_CONTROLLER_CAMERA: default: // Already set as default option @@ -97,7 +96,7 @@ Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) asy return Navigator.of(context).push( PageRouteBuilder( - pageBuilder: (context, _, __) => controller, + pageBuilder: (context, _, _) => controller, opaque: false, ) ); diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index 7e44de5..d6bfa6a 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -24,7 +24,7 @@ import "package:inventree/barcode/controller.dart"; */ class CameraBarcodeController extends InvenTreeBarcodeController { const CameraBarcodeController(BarcodeHandler handler, {Key? key}) - : super(handler, key: key); + : super(handler, key: key); @override State createState() => _CameraBarcodeControllerState(); @@ -43,7 +43,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { String scanned_code = ""; final MobileScannerController controller = MobileScannerController( - autoZoom: true + autoZoom: true, ); @override @@ -63,11 +63,14 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { * Load the barcode scanning settings */ Future _loadSettings() async { - bool _single = await InvenTreeSettingsManager() - .getBool(INV_BARCODE_SCAN_SINGLE, false); + bool _single = await InvenTreeSettingsManager().getBool( + INV_BARCODE_SCAN_SINGLE, + false, + ); - int _delay = await InvenTreeSettingsManager() - .getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + int _delay = + await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) + as int; if (mounted) { setState(() { @@ -80,7 +83,6 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future pauseScan() async { - if (mounted) { setState(() { scanning_paused = true; @@ -90,7 +92,6 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future resumeScan() async { - controller.start(); if (mounted) { @@ -114,8 +115,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { setState(() { multiple_barcodes = false; }); - } - else if (result.barcodes.length > 1) { + } else if (result.barcodes.length > 1) { setState(() { multiple_barcodes = true; }); @@ -177,7 +177,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { sentryReportError( "CameraBarcodeController.onControllerCreated", error, - null + null, ); } @@ -185,7 +185,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { showSnackIcon( L10().cameraCreationError, icon: TablerIcons.camera_x, - success: false + success: false, ); if (OneContext.hasContext) { @@ -195,7 +195,6 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { } Widget BarcodeOverlay(BuildContext context) { - final Size screenSize = MediaQuery.of(context).size; final double width = screenSize.width; final double height = screenSize.height; @@ -220,14 +219,11 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { width: D, height: D, decoration: BoxDecoration( - border: Border.all( - color: overlayColor, - width: 4, - ), + border: Border.all(color: overlayColor, width: 4), ), - ) - ) - ] + ), + ), + ], ); } @@ -235,7 +231,6 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { * Build the barcode reader widget */ Widget BarcodeReader(BuildContext context) { - final Size screenSize = MediaQuery.of(context).size; final double width = screenSize.width; final double height = screenSize.height; @@ -250,7 +245,7 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { scanWindow: Rect.fromCenter( center: Offset(width / 2, height / 2), width: D, - height: D + height: D, ), onDetect: (result) { onScanSuccess(result); @@ -263,28 +258,23 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { child: Align( alignment: Alignment.topCenter, child: Padding( - padding: EdgeInsets.only( - left: 10, - right: 10, - top: 75, - bottom: 10 - ), + padding: EdgeInsets.only(left: 10, right: 10, top: 75, bottom: 10), child: Text( widget.handler.getOverlayText(context), style: TextStyle( color: Colors.white, fontSize: 16, - fontWeight: FontWeight.bold - ) - ) - ) - ) + fontWeight: FontWeight.bold, + ), + ), + ), + ), ); } Widget bottomCenterOverlay() { - - String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; + String info_text = + scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; String text = scanned_code.isNotEmpty ? scanned_code : info_text; @@ -296,28 +286,22 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { child: Align( alignment: Alignment.bottomCenter, child: Padding( - padding: EdgeInsets.only( - left: 10, - right: 10, - top: 10, - bottom: 75 - ), + padding: EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 75), child: Text( - text, - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.bold - ) + text, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), - ) - ) + ), + ), ); } Widget? buildActions(BuildContext context) { - List actions = [ SpeedDialChild( child: Icon(flash_status ? TablerIcons.bulb_off : TablerIcons.bulb), @@ -329,26 +313,22 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { flash_status = !flash_status; }); } - } + }, ), SpeedDialChild( child: Icon(TablerIcons.camera), label: L10().switchCamera, onTap: () async { controller.switchCamera(); - } - ) + }, + ), ]; - return SpeedDial( - icon: Icons.more_horiz, - children: actions, - ); + return SpeedDial(icon: Icons.more_horiz, children: actions); } @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( backgroundColor: COLOR_APP_BAR, @@ -366,19 +346,12 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { }, child: Stack( children: [ - Column( - children: [ - Expanded( - child: BarcodeReader(context) - ), - ], - ), + Column(children: [Expanded(child: BarcodeReader(context))]), topCenterOverlay(), - bottomCenterOverlay() + bottomCenterOverlay(), ], ), ), ); } - } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 07b74f8..6df483a 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -584,7 +584,6 @@ class InvenTreeModel { L10().itemDeleted, success: false, ); - break; default: String detail = L10().errorFetch; detail += "\n${L10().statusCode}: ${response.statusCode}"; @@ -594,7 +593,6 @@ class InvenTreeModel { L10().serverError, detail ); - break; } return false; diff --git a/lib/main.dart b/lib/main.dart index e1ea41a..033ef21 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -66,15 +66,12 @@ Future main() async { switch (orientation) { case SCREEN_ORIENTATION_PORTRAIT: orientations.add(DeviceOrientation.portraitUp); - break; case SCREEN_ORIENTATION_LANDSCAPE: orientations.add(DeviceOrientation.landscapeLeft); - break; default: orientations.add(DeviceOrientation.portraitUp); orientations.add(DeviceOrientation.landscapeLeft); orientations.add(DeviceOrientation.landscapeRight); - break; } SystemChrome.setPreferredOrientations(orientations).then((_) { diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 8eba55b..2443e81 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -143,14 +143,11 @@ class _InvenTreeAppSettingsState extends State { switch (screenOrientation) { case SCREEN_ORIENTATION_PORTRAIT: orientationIcon = Icons.screen_lock_portrait; - break; case SCREEN_ORIENTATION_LANDSCAPE: orientationIcon = Icons.screen_lock_landscape; - break; case SCREEN_ORIENTATION_SYSTEM: default: orientationIcon = Icons.screen_rotation; - break; } return Scaffold( diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index 08a7bf6..f3776cd 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -104,11 +104,9 @@ class _InvenTreeBarcodeSettingsState extends State showErrorDialog(String title, {String description = "", APIResponse ) ); } - break; default: // Unhandled server response children.add( @@ -180,7 +179,6 @@ Future showErrorDialog(String title, {String description = "", APIResponse ) ); - break; } } diff --git a/lib/widget/part/part_suppliers.dart b/lib/widget/part/part_suppliers.dart index 73b5cb3..204ac6e 100644 --- a/lib/widget/part/part_suppliers.dart +++ b/lib/widget/part/part_suppliers.dart @@ -68,7 +68,7 @@ class _PartSupplierState extends RefreshableState { return ListView.separated( shrinkWrap: true, physics: ClampingScrollPhysics(), - separatorBuilder: (_, __) => const Divider(height: 3), + separatorBuilder: (_, _) => const Divider(height: 3), itemCount: _supplierParts.length, itemBuilder: _supplierPartTile, ); diff --git a/pubspec.lock b/pubspec.lock index 002a6e3..9520e7e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: "direct main" description: name: adaptive_theme - sha256: f4ee609b464e5efc68131d9d15ba9aa1de4e3b5ede64be17781c6e19a52d637d + sha256: caa49b4c73b681bf12a641dff77aa1383262a00cf38b9d1a25b180e275ba5ab9 url: "https://pub.dev" source: hosted - version: "3.6.0" + version: "3.7.0" analyzer: dependency: transitive description: @@ -29,20 +29,20 @@ packages: dependency: transitive description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.7" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" @@ -53,58 +53,58 @@ packages: dependency: "direct main" description: name: audioplayers - sha256: c346ba5a39dc208f1bab55fc239855f573d69b0e832402114bf0b793622adc4d + sha256: a5341380a4f1d3a10a4edde5bb75de5127fe31e0faa8c4d860e64d2f91ad84c7 url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.4.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4 + sha256: f8c90823a45b475d2c129f85bbda9c029c8d4450b172f62e066564c6e170f69a url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.2.0" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b + sha256: "405cdbd53ebdb4623f1c5af69f275dad4f930ce895512d5261c07cd95d23e778" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.2.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9" + sha256: "7e0d081a6a527c53aef9539691258a08ff69a7dc15ef6335fbea1b4b03ebbef0" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.2.0" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" + sha256: "77e5fa20fb4a64709158391c75c1cca69a481d35dc879b519e350a05ff520373" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.1.0" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: "3609bdf0e05e66a3d9750ee40b1e37f2a622c4edb796cc600b53a90a30a2ace4" + sha256: bd99d8821114747682a2be0adcdb70233d4697af989b549d3a20a0f49f6c9b13 url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.1.0" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2" + sha256: "871d3831c25cd2408ddc552600fd4b32fba675943e319a41284704ee038ad563" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.2.0" back_button_interceptor: dependency: transitive description: @@ -125,26 +125,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.1" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" camera: dependency: "direct main" description: @@ -157,18 +157,18 @@ packages: dependency: transitive description: name: camera_android_camerax - sha256: "0bd3d1645df00af2540a22df13ba466ac5fb2838a09bce4089cecdb1712a9e94" + sha256: b4197bd6ce75bc66963a904c34c4cbb6aaa2260a5d4aca13b3556926cf3a92b8 url: "https://pub.dev" source: hosted - version: "0.6.18" + version: "0.6.18+3" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: fdc0e668f65c8ddfb3be6c10ef4737fb6274cd04d8053a9525d410642f7989c0 + sha256: ca244564876d5a76f2126bca501aec25243cad23ba1784819242aea2fd25cf70 url: "https://pub.dev" source: hosted - version: "0.9.19+1" + version: "0.9.19+2" camera_platform_interface: dependency: transitive description: @@ -197,10 +197,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" cli_config: dependency: transitive description: @@ -237,18 +237,18 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" coverage: dependency: transitive description: name: coverage - sha256: "4b8701e48a58f7712492c9b1f7ba0bb9d525644dd66d023b62e1fc8cdb560c8a" + sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 url: "https://pub.dev" source: hosted - version: "1.14.0" + version: "1.14.1" cross_file: dependency: transitive description: @@ -261,10 +261,10 @@ packages: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -301,18 +301,18 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 + sha256: "0c6396126421b590089447154c5f98a5de423b70cfb15b1578fd018843ee6f53" url: "https://pub.dev" source: hosted - version: "10.1.2" + version: "11.4.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.2" dropdown_search: dependency: "direct main" description: @@ -333,42 +333,42 @@ packages: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" file_picker: dependency: "direct main" description: name: file_picker - sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12" + sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a url: "https://pub.dev" source: hosted - version: "8.1.2" + version: "10.2.0" file_selector_linux: dependency: transitive description: name: file_selector_linux - sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" url: "https://pub.dev" source: hosted - version: "0.9.2+1" + version: "0.9.3+2" file_selector_macos: dependency: transitive description: name: file_selector_macos - sha256: cb284e267f8e2a45a904b5c094d2ba51d0aabfc20b1538ab786d9ef7dc2bf75c + sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" url: "https://pub.dev" source: hosted - version: "0.9.4+1" + version: "0.9.4+3" file_selector_platform_interface: dependency: transitive description: @@ -381,10 +381,18 @@ packages: dependency: transitive description: name: file_selector_windows - sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69" + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" url: "https://pub.dev" source: hosted - version: "0.9.3+2" + version: "0.9.3+4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -394,18 +402,18 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.1" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" url: "https://pub.dev" source: hosted - version: "0.14.1" + version: "0.14.4" flutter_localizations: dependency: "direct main" description: flutter @@ -439,10 +447,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.28" flutter_speed_dial: dependency: "direct main" description: @@ -489,10 +497,10 @@ packages: dependency: transitive description: name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" http: dependency: "direct main" description: @@ -505,26 +513,26 @@ packages: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: transitive description: name: image - sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.5.4" image_picker: dependency: "direct main" description: @@ -537,50 +545,50 @@ packages: dependency: transitive description: name: image_picker_android - sha256: c0a6763d50b354793d0192afd0a12560b823147d3ded7c6b77daf658fa05cc85 + sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb" url: "https://pub.dev" source: hosted - version: "0.8.12+13" + version: "0.8.12+23" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50" + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" url: "https://pub.dev" source: hosted - version: "0.8.12" + version: "0.8.12+2" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.1+2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.1+2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.10.1" image_picker_windows: dependency: transitive description: @@ -593,10 +601,10 @@ packages: dependency: "direct main" description: name: infinite_scroll_pagination - sha256: b68bce20752fcf36c7739e60de4175494f74e99e9a69b4dd2fe3a1dd07a7f16a + sha256: "4047eb8191e8b33573690922a9e995af64c3949dc87efc844f936b039ea279df" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" intl: dependency: "direct main" description: @@ -609,18 +617,18 @@ packages: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" js: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.2" json_annotation: dependency: transitive description: @@ -657,26 +665,26 @@ packages: dependency: "direct dev" description: name: lint - sha256: d758a5211fce7fd3f5e316f804daefecdc34c7e53559716125e6da7388ae8565 + sha256: "3cd03646de313481336500ba02eb34d07c590535525f154aae7fda7362aa07a9" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.8.0" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" markdown: dependency: transitive description: name: markdown - sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "7.3.0" matcher: dependency: transitive description: @@ -705,10 +713,10 @@ packages: dependency: transitive description: name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "2.0.0" mobile_scanner: dependency: "direct main" description: @@ -737,10 +745,10 @@ packages: dependency: "direct main" description: name: one_context - sha256: "40607e6cf85d95dc81ee037788857a943784d37dfc04a40904a140328745e0af" + sha256: bafae468bdb5d1089736c4e97582b85abd994a80b65c5becb6956a31c59d69e4 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" open_filex: dependency: "direct main" description: @@ -753,26 +761,26 @@ packages: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" url: "https://pub.dev" source: hosted - version: "8.1.1" + version: "8.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.2.0" path: dependency: "direct main" description: @@ -793,18 +801,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -833,18 +841,18 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -861,38 +869,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + posix: + dependency: transitive + description: + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" + source: hosted + version: "6.0.2" pub_semver: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.4" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" - url: "https://pub.dev" - source: hosted - version: "1.5.0" + version: "2.2.0" rxdart: dependency: transitive description: name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" url: "https://pub.dev" source: hosted - version: "0.27.7" + version: "0.28.0" sembast: dependency: "direct main" description: name: sembast - sha256: "934a7b99297fb4f0b6e69fb1465286737b3b47b1a5149bf8dfc85667fbbdd21d" + sha256: "7119cf6f79bd1d48c8ec7943f4facd96c15ab26823021ed0792a487c7cd34441" url: "https://pub.dev" source: hosted - version: "3.7.4+3" + version: "3.8.5+1" sentry: dependency: transitive description: @@ -913,26 +921,26 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -953,10 +961,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: @@ -969,10 +977,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: @@ -993,10 +1001,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -1022,10 +1030,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" url: "https://pub.dev" source: hosted - version: "0.10.12" + version: "0.10.13" source_span: dependency: transitive description: @@ -1034,22 +1042,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" sqflite: dependency: transitive description: name: sqflite - sha256: ff5a2436ef8ebdfda748fbfe957f9981524cb5ff11e7bafa8c42771840e8a788 + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 url: "https://pub.dev" source: hosted - version: "2.3.3+2" + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "2d8e607db72e9cb7748c9c6e739e2c9618320a5517de693d5a24609c4671b1a4" + sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" url: "https://pub.dev" source: hosted - version: "2.5.4+4" + version: "2.5.5" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -1070,10 +1110,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -1086,10 +1126,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" + sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" url: "https://pub.dev" source: hosted - version: "3.3.0+3" + version: "3.3.1" term_glyph: dependency: transitive description: @@ -1126,10 +1166,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" url_launcher: dependency: "direct main" description: @@ -1142,34 +1182,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.3.10" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.3" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -1182,26 +1222,26 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.4" uuid: dependency: transitive description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -1238,34 +1278,34 @@ packages: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web_socket: dependency: transitive description: name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" url: "https://pub.dev" source: hosted - version: "0.1.6" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.3" webkit_inspection_protocol: dependency: transitive description: @@ -1278,26 +1318,26 @@ packages: dependency: transitive description: name: win32 - sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "5.14.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" url: "https://pub.dev" source: hosted - version: "1.1.5" + version: "2.1.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: @@ -1310,10 +1350,10 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" sdks: - dart: ">=3.7.0 <3.32.2" + dart: ">=3.8.1 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 97e2a98..8cadccc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,19 +4,20 @@ description: InvenTree stock management version: 0.18.1+98 environment: - sdk: ">=2.19.5 <3.32.2" + sdk: ^3.8.1 dependencies: adaptive_theme: ^3.3.0 # Theme management (e.g. dark mode) + async: any audioplayers: ^6.1.0 # Play audio files cached_network_image: ^3.3.1 # Download and cache remote images camera: ^0.11.1 # Camera cupertino_icons: ^1.0.8 currency_formatter: ^2.2.1 # Currency formatting datetime_picker_formfield: ^2.0.1 # Date / time picker - device_info_plus: ^10.1.2 # Information about the device + device_info_plus: ^11.4.0 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields - file_picker: ^8.1.2 # Select files from the device + file_picker: ^10.1.4 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 diff --git a/tasks.py b/tasks.py index 43573a4..a34d035 100644 --- a/tasks.py +++ b/tasks.py @@ -8,7 +8,7 @@ from invoke import task @task def clean(c): """Clean flutter build.""" - c.run("flutter clean") + c.run("fvm flutter clean") @task def update(c): @@ -20,20 +20,20 @@ def translate(c): """Update translation files.""" here = os.path.dirname(__file__) - l10_dir = os.path.join(here, 'lib', 'l10n') + l10_dir = os.path.join(here, "lib", "l10n") l10_dir = os.path.abspath(l10_dir) - python = 'python3' if sys.platform.lower() == 'darwin' else 'python' + python = "python3" if sys.platform.lower() == "darwin" else "python" c.run(f"cd {l10_dir} && {python} collect_translations.py") @task(pre=[clean, update, translate]) def ios(c): """Build iOS app in release configuration.""" - c.run("flutter build ipa --release --no-tree-shake-icons") + c.run("fvm flutter build ipa --release --no-tree-shake-icons") @task(pre=[clean, update, translate]) def android(c): """Build Android app in release configuration.""" - c.run("flutter build appbundle --release --no-tree-shake-icons") + c.run("fvm flutter build appbundle --release --no-tree-shake-icons") From fff16fec76afa2d3f3fdccd8c5a1d00db466720f Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Jun 2025 19:42:31 +1000 Subject: [PATCH 674/746] New translations app_en.arb (French) (#660) --- lib/l10n/fr_FR/app_fr_FR.arb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/l10n/fr_FR/app_fr_FR.arb b/lib/l10n/fr_FR/app_fr_FR.arb index 8cdad55..1284091 100644 --- a/lib/l10n/fr_FR/app_fr_FR.arb +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -574,7 +574,7 @@ "@partsNone": {}, "partNoResults": "Pas de pièces correspondant à la requête", "@partNoResults": {}, - "partPricing": "Part Pricing", + "partPricing": "Tarification des pièces", "@partPricing": {}, "partPricingSettingDetail": "Display part pricing information", "@pricingSettingDetail": {}, @@ -982,7 +982,7 @@ "@suppliers": {}, "supplierReference": "Référence du fournisseur", "@supplierReference": {}, - "switchCamera": "Switch Camera", + "switchCamera": "Changer de caméra", "@switchCamera": {}, "takePicture": "Prendre une photo", "@takePicture": {}, @@ -1016,7 +1016,7 @@ "@timeout": { "description": "" }, - "toggleTorch": "Toggle Torch", + "toggleTorch": "Lampe torche", "@toggleTorch": {}, "tokenError": "Erreur du jeton", "@tokenError": {}, @@ -1088,19 +1088,19 @@ "@price": {}, "priceRange": "Fourchette de prix", "@priceRange": {}, - "priceOverrideMin": "Minimum Price Override", + "priceOverrideMin": "Remplacer le prix minimum", "@priceOverrideMin": {}, - "priceOverrideMax": "Maximum Price Override", + "priceOverrideMax": "Remplacer le prix maximum", "@priceOverrideMax": {}, "salePrice": "Prix de vente", "@salePrice": {}, - "saleHistory": "Sale History", + "saleHistory": "Historique des ventes", "@saleHistory": {}, - "supplierPricing": "Supplier Pricing", + "supplierPricing": "Tarification du fournisseur", "@supplierPricing": {}, - "bomCost": "BOM Cost", + "bomCost": "Coût de la nomenclature", "@bomCost": {}, - "internalCost": "Internal Cost", + "internalCost": "Coût interne", "@internalCost": {}, "variantCost": "Variant Cost", "@variantCost": {}, @@ -1108,12 +1108,12 @@ "@overallPricing": {}, "pricingOverrides": "Pricing Overrides", "@pricingOverrides": {}, - "currency": "Currency", + "currency": "Devise", "@currency": {}, - "priceBreaks": "Price Breaks", + "priceBreaks": "Ruptures de prix", "@priceBreaks": {}, - "noPricingAvailable": "No pricing available", + "noPricingAvailable": "Aucune tarification disponible", "@noPricingAvailable": {}, - "noPricingDataFound": "No pricing data found for this part", + "noPricingDataFound": "Aucune donnée de tarification disponible pour cette pièce", "@noPricingDataFound": {} } \ No newline at end of file From a18c5d83545b159433c9f14750cc953698f206bf Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Jun 2025 19:58:15 +1000 Subject: [PATCH 675/746] Bump version to 0.19.0 (#661) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 8cadccc..5f1db57 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.18.1+98 +version: 0.19.0+99 environment: sdk: ^3.8.1 From e9db6532e479a891a6c2230bd2a27ab95e07f374 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Jun 2025 20:11:20 +1000 Subject: [PATCH 676/746] Notification frequency (#662) * Adjust notification check frequency - 60s vs 5s * Bump release notes --- assets/release_notes.md | 1 + lib/api.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 14d3df3..c69b658 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -3,6 +3,7 @@ - Replace barcode scanning library for better performance - Display part pricing information - Fix broken documentation link +- Reduce frequency of notification checks - Updated translations ### 0.18.1 - April 2025 diff --git a/lib/api.dart b/lib/api.dart index c8e706f..e8619ad 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -680,7 +680,7 @@ class InvenTreeAPI { if (_notification_timer == null) { debug("starting notification timer"); _notification_timer = Timer.periodic( - Duration(seconds: 5), + Duration(seconds: 60), (timer) { _refreshNotifications(); }); From 4444884afa2304b98d304feafba1ac7953cc48c6 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 24 Jun 2025 01:55:01 +0200 Subject: [PATCH 677/746] Format Code and Add Format Checks to CI (#643) * Remove unused lib/generated/i18n.dart * Use `fvm dart format .` * Add contributing guidelines * Enforce dart format * Add `dart format off` directive to generated files --- .github/workflows/ci.yaml | 1 + CONTRIBUTING.md | 50 ++ find_dart_files.py | 1 + lib/api.dart | 534 ++++++++-------- lib/api_form.dart | 441 ++++++------- lib/app_colors.dart | 1 - lib/barcode/barcode.dart | 204 +++--- lib/barcode/camera_controller.dart | 5 +- lib/barcode/controller.dart | 18 +- lib/barcode/handler.dart | 42 +- lib/barcode/purchase_order.dart | 56 +- lib/barcode/sales_order.dart | 49 +- lib/barcode/stock.dart | 90 +-- lib/barcode/tones.dart | 14 +- lib/barcode/wedge_controller.dart | 29 +- lib/dsn.dart | 4 +- lib/generated/i18n.dart | 76 --- lib/helpers.dart | 42 +- lib/inventree/bom.dart | 11 +- lib/inventree/company.dart | 127 ++-- lib/inventree/model.dart | 309 +++++----- lib/inventree/notification.dart | 15 +- lib/inventree/orders.dart | 22 +- lib/inventree/part.dart | 348 +++++------ lib/inventree/project_code.dart | 13 +- lib/inventree/purchase_order.dart | 138 ++--- lib/inventree/sales_order.dart | 127 ++-- lib/inventree/sentry.dart | 59 +- lib/inventree/status_codes.dart | 8 +- lib/inventree/stock.dart | 580 ++++++++---------- lib/l10.dart | 5 +- lib/l10n/collect_translations.py | 1 + lib/labels.dart | 112 ++-- lib/main.dart | 135 ++-- lib/preferences.dart | 10 +- lib/settings/about.dart | 120 ++-- lib/settings/app_settings.dart | 118 ++-- lib/settings/barcode_settings.dart | 93 +-- lib/settings/home_settings.dart | 221 ++++--- lib/settings/login.dart | 96 ++- lib/settings/part_settings.dart | 78 ++- lib/settings/purchase_order_settings.dart | 133 ++-- lib/settings/release.dart | 15 +- lib/settings/sales_order_settings.dart | 97 +-- lib/settings/select_server.dart | 164 +++-- lib/settings/settings.dart | 180 +++--- lib/user_profile.dart | 34 +- lib/widget/attachment_widget.dart | 146 ++--- lib/widget/back.dart | 3 +- lib/widget/company/company_detail.dart | 355 ++++++----- lib/widget/company/company_list.dart | 46 +- .../company/manufacturer_part_detail.dart | 146 ++--- lib/widget/company/supplier_part_detail.dart | 170 ++--- lib/widget/company/supplier_part_list.dart | 38 +- lib/widget/dialogs.dart | 140 ++--- lib/widget/drawer.dart | 89 ++- lib/widget/fields.dart | 176 +++--- lib/widget/home.dart | 231 ++++--- lib/widget/notes_widget.dart | 23 +- lib/widget/notifications.dart | 37 +- lib/widget/order/extra_line_detail.dart | 54 +- lib/widget/order/po_extra_line_list.dart | 47 +- lib/widget/order/po_line_detail.dart | 84 +-- lib/widget/order/po_line_list.dart | 42 +- lib/widget/order/purchase_order_detail.dart | 422 +++++++------ lib/widget/order/purchase_order_list.dart | 65 +- lib/widget/order/sales_order_detail.dart | 373 ++++++----- lib/widget/order/sales_order_list.dart | 86 +-- lib/widget/order/so_extra_line_list.dart | 69 ++- lib/widget/order/so_line_detail.dart | 114 ++-- lib/widget/order/so_line_list.dart | 44 +- lib/widget/order/so_shipment_list.dart | 35 +- lib/widget/paginator.dart | 177 +++--- lib/widget/part/bom_list.dart | 68 +- lib/widget/part/category_display.dart | 146 ++--- lib/widget/part/category_list.dart | 42 +- lib/widget/part/part_detail.dart | 490 +++++++-------- lib/widget/part/part_image_widget.dart | 15 +- lib/widget/part/part_list.dart | 38 +- lib/widget/part/part_parameter_widget.dart | 97 ++- lib/widget/part/part_pricing.dart | 85 ++- lib/widget/part/part_suppliers.dart | 8 +- lib/widget/progress.dart | 23 +- lib/widget/refreshable_state.dart | 100 ++- lib/widget/search.dart | 295 ++++----- lib/widget/snacks.dart | 55 +- lib/widget/spinner.dart | 16 +- lib/widget/stock/location_display.dart | 316 +++++----- lib/widget/stock/location_list.dart | 37 +- lib/widget/stock/stock_detail.dart | 504 ++++++++------- lib/widget/stock/stock_item_history.dart | 29 +- lib/widget/stock/stock_item_test_results.dart | 97 +-- lib/widget/stock/stock_list.dart | 33 +- test/api_test.dart | 14 +- test/barcode_test.dart | 28 +- test/models_test.dart | 30 +- test/preferences_test.dart | 38 +- test/setup.dart | 38 +- test/user_profile_test.dart | 33 +- test/wedge_scanner_test.dart | 11 +- 100 files changed, 5332 insertions(+), 5592 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 lib/generated/i18n.dart diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0dddcf8..b61677d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -60,6 +60,7 @@ jobs: python3 find_dart_files.py flutter pub get flutter analyze + dart format --output=none --set-exit-if-changed . - name: Install Python uses: actions/setup-python@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..248d20c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing to InvenTree App + +Thank you for considering contributing to the InvenTree App! This document outlines some guidelines to ensure smooth collaboration. + +## Code Style and Formatting + +### Dart Formatting + +We enforce consistent code formatting using Dart's built-in formatter. Before submitting a pull request: + +1. Run the formatter on your code: + ```bash + fvm dart format . + ``` + +2. Our CI pipeline will verify that all code follows the standard Flutter/Dart formatting rules. Pull requests with improper formatting will fail CI checks. + +### General Guidelines + +- Write clear, readable, and maintainable code +- Include comments where necessary +- Follow Flutter/Dart best practices +- Write tests for new features when applicable + +## Pull Request Process + +1. Fork the repository and create a feature branch +2. Make your changes +3. Ensure your code passes all tests and linting +4. Format your code using `fvm dart format` +5. Submit a pull request with a clear description of the changes +6. Address any review comments + +## Development Setup + +1. Ensure you have Flutter installed (we use Flutter Version Management) +2. Check the required Flutter version in the `.fvmrc` file +3. Install dependencies with `fvm flutter pub get` +4. Run tests with `fvm flutter test` + +## Reporting Issues + +When reporting issues, please include: +- Clear steps to reproduce the issue +- Expected behavior +- Actual behavior +- Screenshots if applicable +- Device/environment information + +Thank you for contributing to the InvenTree App! diff --git a/find_dart_files.py b/find_dart_files.py index e71babd..dbb1479 100644 --- a/find_dart_files.py +++ b/find_dart_files.py @@ -15,6 +15,7 @@ if __name__ == "__main__": with open("test/coverage_helper_test.dart", "w") as f: f.write("// ignore_for_file: unused_import\n\n") + f.write("// dart format off\n\n") skips = [ "generated", diff --git a/lib/api.dart b/lib/api.dart index e8619ad..d8639f3 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -27,13 +27,17 @@ import "package:inventree/user_profile.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/snacks.dart"; - /* * Class representing an API response from the server */ class APIResponse { - - APIResponse({this.url = "", this.method = "", this.statusCode = -1, this.error = "", this.data = const {}}); + APIResponse({ + this.url = "", + this.method = "", + this.statusCode = -1, + this.error = "", + this.data = const {}, + }); int statusCode = -1; @@ -88,7 +92,6 @@ class APIResponse { * Handles case where the response is paginated, or a complete set of results */ List resultsList() { - if (isList()) { return asList(); } else if (isMap()) { @@ -104,14 +107,12 @@ class APIResponse { } } - /* * Custom FileService for caching network images * Requires a custom badCertificateCallback, * so we can accept "dodgy" (e.g. self-signed) certificates */ class InvenTreeFileService extends FileService { - InvenTreeFileService({HttpClient? client, bool strictHttps = false}) { _client = client ?? HttpClient(); @@ -126,8 +127,10 @@ class InvenTreeFileService extends FileService { HttpClient? _client; @override - Future get(String url, - {Map? headers}) async { + Future get( + String url, { + Map? headers, + }) async { final Uri resolved = Uri.base.resolve(url); final HttpClientRequest req = await _client!.getUrl(resolved); @@ -141,8 +144,11 @@ class InvenTreeFileService extends FileService { final HttpClientResponse httpResponse = await req.close(); final http.StreamedResponse _response = http.StreamedResponse( - httpResponse.timeout(Duration(seconds: 60)), httpResponse.statusCode, - contentLength: httpResponse.contentLength < 0 ? 0 : httpResponse.contentLength, + httpResponse.timeout(Duration(seconds: 60)), + httpResponse.statusCode, + contentLength: httpResponse.contentLength < 0 + ? 0 + : httpResponse.contentLength, reasonPhrase: httpResponse.reasonPhrase, isRedirect: httpResponse.isRedirect, ); @@ -158,12 +164,10 @@ class InvenTreeFileService extends FileService { * initialised using a username:password combination. */ - /* * API class which manages all communication with the InvenTree server */ class InvenTreeAPI { - factory InvenTreeAPI() { return _api; } @@ -209,7 +213,6 @@ class InvenTreeAPI { } String _makeUrl(String url) { - // Strip leading slash if (url.startsWith("/")) { url = url.substring(1, url.length); @@ -257,14 +260,12 @@ class InvenTreeAPI { * Useful as a precursor check before performing operations. */ bool checkConnection() { - // Is the server connected? if (!isConnected()) { - showSnackIcon( L10().notConnected, success: false, - icon: TablerIcons.server + icon: TablerIcons.server, ); return false; @@ -388,7 +389,6 @@ class InvenTreeAPI { return !isConnected() && _connecting; } - /* * Perform the required login steps, in sequence. * Internal function, called by connectToServer() @@ -403,7 +403,6 @@ class InvenTreeAPI { * 5. Request information on available plugins */ Future _connectToServer() async { - if (!await _checkServer()) { return false; } @@ -413,7 +412,11 @@ class InvenTreeAPI { } if (!await _checkAuth()) { - showServerError(_URL_ME, L10().serverNotConnected, L10().serverAuthenticationError); + showServerError( + _URL_ME, + L10().serverNotConnected, + L10().serverAuthenticationError, + ); // Invalidate the token if (profile != null) { @@ -436,20 +439,18 @@ class InvenTreeAPI { return true; } - /* * Check that the remote server is available. * Ping the api/ endpoint, which does not require user authentication */ Future _checkServer() async { - String address = profile?.server ?? ""; if (address.isEmpty) { showSnackIcon( - L10().incompleteDetails, - icon: TablerIcons.exclamation_circle, - success: false + L10().incompleteDetails, + icon: TablerIcons.exclamation_circle, + success: false, ); return false; } @@ -459,7 +460,9 @@ class InvenTreeAPI { } // Cache the "strictHttps" setting, so we can use it later without async requirement - _strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + _strictHttps = + await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) + as bool; debug("Connecting to ${apiUrl}"); @@ -467,7 +470,11 @@ class InvenTreeAPI { if (!response.successful()) { debug("Server returned invalid response: ${response.statusCode}"); - showStatusCodeError(apiUrl, response.statusCode, details: response.data.toString()); + showStatusCodeError( + apiUrl, + response.statusCode, + details: response.data.toString(), + ); return false; } @@ -476,17 +483,12 @@ class InvenTreeAPI { serverInfo = {..._data}; if (serverVersion.isEmpty) { - showServerError( - apiUrl, - L10().missingData, - L10().serverMissingData, - ); + showServerError(apiUrl, L10().missingData, L10().serverMissingData); return false; } if (apiVersion < _minApiVersion) { - String message = L10().serverApiVersion + ": ${apiVersion}"; message += "\n"; @@ -496,11 +498,7 @@ class InvenTreeAPI { message += "Ensure your InvenTree server version is up to date!"; - showServerError( - apiUrl, - L10().serverOld, - message, - ); + showServerError(apiUrl, L10().serverOld, message); return false; } @@ -509,7 +507,6 @@ class InvenTreeAPI { return true; } - /* * Check that the user is authenticated * Fetch the user information @@ -525,7 +522,9 @@ class InvenTreeAPI { userInfo = response.asMap(); return true; } else { - debug("Auth request failed: Server returned status ${response.statusCode}"); + debug( + "Auth request failed: Server returned status ${response.statusCode}", + ); if (response.data != null) { debug("Server response: ${response.data.toString()}"); } @@ -538,8 +537,11 @@ class InvenTreeAPI { * Fetch a token from the server, * with a temporary authentication header */ - Future fetchToken(UserProfile userProfile, String username, String password) async { - + Future fetchToken( + UserProfile userProfile, + String username, + String password, + ) async { debug("Fetching user token from ${userProfile.server}"); profile = userProfile; @@ -574,13 +576,14 @@ class InvenTreeAPI { } // Construct auth header from username and password - String authHeader = "Basic " + base64Encode(utf8.encode("${username}:${password}")); + String authHeader = + "Basic " + base64Encode(utf8.encode("${username}:${password}")); // Perform request to get a token final response = await get( - _URL_TOKEN, - params: { "name": platform_name}, - headers: { HttpHeaders.authorizationHeader: authHeader} + _URL_TOKEN, + params: {"name": platform_name}, + headers: {HttpHeaders.authorizationHeader: authHeader}, ); // Invalid response @@ -641,11 +644,9 @@ class InvenTreeAPI { _connectionStatusChanged(); } - /* Public facing connection function. */ Future connectToServer(UserProfile prf) async { - // Ensure server is first disconnected disconnectFromServer(); @@ -653,9 +654,9 @@ class InvenTreeAPI { if (profile == null) { showSnackIcon( - L10().profileSelect, - success: false, - icon: TablerIcons.exclamation_circle + L10().profileSelect, + success: false, + icon: TablerIcons.exclamation_circle, ); return false; } @@ -679,11 +680,9 @@ class InvenTreeAPI { if (_notification_timer == null) { debug("starting notification timer"); - _notification_timer = Timer.periodic( - Duration(seconds: 60), - (timer) { - _refreshNotifications(); - }); + _notification_timer = Timer.periodic(Duration(seconds: 60), (timer) { + _refreshNotifications(); + }); } } @@ -698,7 +697,6 @@ class InvenTreeAPI { * Request the user roles (permissions) from the InvenTree server */ Future _fetchRoles() async { - roles.clear(); debug("API: Requesting user role data"); @@ -712,15 +710,10 @@ class InvenTreeAPI { var data = response.asMap(); if (!data.containsKey("roles")) { - roles = {}; permissions = {}; - showServerError( - apiUrl, - L10().serverError, - L10().errorUserRoles, - ); + showServerError(apiUrl, L10().serverError, L10().errorUserRoles); return false; } @@ -737,7 +730,6 @@ class InvenTreeAPI { // Request plugin information from the server Future _fetchPlugins() async { - _plugins.clear(); debug("API: getPluginInformation()"); @@ -762,7 +754,6 @@ class InvenTreeAPI { * e.g. "sales_order", "change" */ bool checkRole(String role, String permission) { - if (!_connected) { return false; } @@ -793,12 +784,13 @@ class InvenTreeAPI { // Unknown error - report it! sentryReportError( "api.checkRole", - error, stackTrace, + error, + stackTrace, context: { "role": role, "permission": permission, "error": error.toString(), - } + }, ); } @@ -840,13 +832,14 @@ class InvenTreeAPI { } else { // Unknown error - report it! sentryReportError( - "api.checkPermission", - error, stackTrace, - context: { - "model": model, - "permission": permission, - "error": error.toString(), - } + "api.checkPermission", + error, + stackTrace, + context: { + "model": model, + "permission": permission, + "error": error.toString(), + }, ); } @@ -855,10 +848,12 @@ class InvenTreeAPI { } } - // Perform a PATCH request - Future patch(String url, {Map body = const {}, int? expectedStatusCode}) async { - + Future patch( + String url, { + Map body = const {}, + int? expectedStatusCode, + }) async { Map _body = body; HttpClientRequest? request = await apiRequest(url, "PATCH"); @@ -868,14 +863,14 @@ class InvenTreeAPI { return APIResponse( url: url, method: "PATCH", - error: "HttpClientRequest is null" + error: "HttpClientRequest is null", ); } return completeRequest( request, data: json.encode(_body), - statusCode: expectedStatusCode + statusCode: expectedStatusCode, ); } @@ -883,7 +878,6 @@ class InvenTreeAPI { * Download a file from the given URL */ Future downloadFile(String url, {bool openOnDownload = true}) async { - if (url.isEmpty) { // No URL provided for download return; @@ -910,19 +904,22 @@ class InvenTreeAPI { HttpClientRequest? _request; - final bool strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + final bool strictHttps = + await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) + as bool; var client = createClient(url, strictHttps: strictHttps); // Attempt to open a connection to the server try { - _request = await client.openUrl("GET", _uri).timeout(Duration(seconds: 10)); + _request = await client + .openUrl("GET", _uri) + .timeout(Duration(seconds: 10)); // Set headers defaultHeaders().forEach((key, value) { _request?.headers.set(key, value); }); - } on SocketException catch (error) { debug("SocketException at ${url}: ${error.toString()}"); showServerError(url, L10().connectionRefused, error.toString()); @@ -939,10 +936,7 @@ class InvenTreeAPI { } catch (error, stackTrace) { debug("Server error at ${url}: ${error.toString()}"); showServerError(url, L10().serverError, error.toString()); - sentryReportError( - "api.downloadFile : client.openUrl", - error, stackTrace, - ); + sentryReportError("api.downloadFile : client.openUrl", error, stackTrace); return; } @@ -972,7 +966,8 @@ class InvenTreeAPI { showServerError(url, L10().downloadError, error.toString()); sentryReportError( "api.downloadFile : client.closeRequest", - error, stackTrace, + error, + stackTrace, ); } } @@ -980,8 +975,13 @@ class InvenTreeAPI { /* * Upload a file to the given URL */ - Future uploadFile(String url, File f, - {String name = "attachment", String method="POST", Map? fields}) async { + Future uploadFile( + String url, + File f, { + String name = "attachment", + String method = "POST", + Map? fields, + }) async { var _url = makeApiUrl(url); var request = http.MultipartRequest(method, Uri.parse(_url)); @@ -990,7 +990,6 @@ class InvenTreeAPI { if (fields != null) { fields.forEach((String key, dynamic value) { - if (value == null) { request.fields[key] = ""; } else { @@ -1003,10 +1002,7 @@ class InvenTreeAPI { request.files.add(_file); - APIResponse response = APIResponse( - url: url, - method: method, - ); + APIResponse response = APIResponse(url: url, method: method); String jsondata = ""; @@ -1022,15 +1018,15 @@ class InvenTreeAPI { // Report a server-side error if (response.statusCode == 500) { sentryReportMessage( - "Server error in uploadFile()", - context: { - "url": url, - "method": request.method, - "name": name, - "statusCode": response.statusCode.toString(), - "requestHeaders": request.headers.toString(), - "responseHeaders": httpResponse.headers.toString(), - } + "Server error in uploadFile()", + context: { + "url": url, + "method": request.method, + "name": name, + "statusCode": response.statusCode.toString(), + "requestHeaders": request.headers.toString(), + "responseHeaders": httpResponse.headers.toString(), + }, ); } } on SocketException catch (error) { @@ -1041,28 +1037,24 @@ class InvenTreeAPI { showServerError( url, L10().formatException, - L10().formatExceptionJson + ":\n${jsondata}" + L10().formatExceptionJson + ":\n${jsondata}", ); sentryReportMessage( - "Error decoding JSON response from server", - context: { - "method": "uploadFile", - "url": url, - "statusCode": response.statusCode.toString(), - "data": jsondata, - } + "Error decoding JSON response from server", + context: { + "method": "uploadFile", + "url": url, + "statusCode": response.statusCode.toString(), + "data": jsondata, + }, ); - } on TimeoutException { showTimeoutError(url); response.error = "TimeoutException"; } catch (error, stackTrace) { showServerError(url, L10().serverError, error.toString()); - sentryReportError( - "api.uploadFile", - error, stackTrace - ); + sentryReportError("api.uploadFile", error, stackTrace); response.error = "UnknownError"; response.errorDetail = error.toString(); } @@ -1077,15 +1069,11 @@ class InvenTreeAPI { * so that (hopefully) the field messages are correctly translated */ Future options(String url) async { - HttpClientRequest? request = await apiRequest(url, "OPTIONS"); if (request == null) { // Return an "invalid" APIResponse - return APIResponse( - url: url, - method: "OPTIONS" - ); + return APIResponse(url: url, method: "OPTIONS"); } return completeRequest(request); @@ -1095,22 +1083,22 @@ class InvenTreeAPI { * Perform a HTTP POST request * Returns a json object (or null if unsuccessful) */ - Future post(String url, {Map body = const {}, int? expectedStatusCode=201}) async { - + Future post( + String url, { + Map body = const {}, + int? expectedStatusCode = 201, + }) async { HttpClientRequest? request = await apiRequest(url, "POST"); if (request == null) { // Return an "invalid" APIResponse - return APIResponse( - url: url, - method: "POST" - ); + return APIResponse(url: url, method: "POST"); } return completeRequest( request, data: json.encode(body), - statusCode: expectedStatusCode + statusCode: expectedStatusCode, ); } @@ -1118,28 +1106,25 @@ class InvenTreeAPI { * Perform a request to link a custom barcode to a particular item */ Future linkBarcode(Map body) async { + HttpClientRequest? request = await apiRequest("/barcode/link/", "POST"); - HttpClientRequest? request = await apiRequest("/barcode/link/", "POST"); + if (request == null) { + return false; + } - if (request == null) { - return false; - } - - final response = await completeRequest( - request, - data: json.encode(body), - statusCode: 200 - ); - - return response.isValid() && response.statusCode == 200; + final response = await completeRequest( + request, + data: json.encode(body), + statusCode: 200, + ); + return response.isValid() && response.statusCode == 200; } /* * Perform a request to unlink a custom barcode from a particular item */ Future unlinkBarcode(Map body) async { - HttpClientRequest? request = await apiRequest("/barcode/unlink/", "POST"); if (request == null) { @@ -1147,33 +1132,31 @@ class InvenTreeAPI { } final response = await completeRequest( - request, - data: json.encode(body), - statusCode: 200, + request, + data: json.encode(body), + statusCode: 200, ); return response.isValid() && response.statusCode == 200; } - HttpClient createClient(String url, {bool strictHttps = false}) { - var client = HttpClient(); - client.badCertificateCallback = (X509Certificate cert, String host, int port) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (strictHttps) { + showServerError( + url, + L10().serverCertificateError, + L10().serverCertificateInvalid, + ); + return false; + } - if (strictHttps) { - showServerError( - url, - L10().serverCertificateError, - L10().serverCertificateInvalid, - ); - return false; - } - - // Strict HTTPs not enforced, so we'll ignore the bad cert - return true; - }; + // Strict HTTPs not enforced, so we'll ignore the bad cert + return true; + }; // Set the connection timeout client.connectionTimeout = Duration(seconds: 30); @@ -1189,22 +1172,15 @@ class InvenTreeAPI { * @param params is the request parameters */ Future apiRequest( - String url, - String method, - { - Map urlParams = const {}, - Map headers = const {}, - } - ) async { - + String url, + String method, { + Map urlParams = const {}, + Map headers = const {}, + }) async { var _url = makeApiUrl(url); if (_url.isEmpty) { - showServerError( - url, - L10().invalidHost, - L10().invalidHostDetails - ); + showServerError(url, L10().invalidHost, L10().invalidHostDetails); return null; } @@ -1225,23 +1201,23 @@ class InvenTreeAPI { Uri? _uri = Uri.tryParse(_url); if (_uri == null || _uri.host.isEmpty) { - showServerError( - _url, - L10().invalidHost, - L10().invalidHostDetails - ); + showServerError(_url, L10().invalidHost, L10().invalidHostDetails); return null; } HttpClientRequest? _request; - final bool strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + final bool strictHttps = + await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) + as bool; var client = createClient(url, strictHttps: strictHttps); // Attempt to open a connection to the server try { - _request = await client.openUrl(method, _uri).timeout(Duration(seconds: 10)); + _request = await client + .openUrl(method, _uri) + .timeout(Duration(seconds: 10)); // Default headers defaultHeaders().forEach((key, value) { @@ -1281,40 +1257,45 @@ class InvenTreeAPI { showServerError(url, L10().serverError, error.toString()); sentryReportError( "api.apiRequest : openUrl", - error, stackTrace, - context: { - "url": url, - "method": method, - } + error, + stackTrace, + context: {"url": url, "method": method}, ); return null; } } - /* * Complete an API request, and return an APIResponse object */ - Future completeRequest(HttpClientRequest request, {String? data, int? statusCode, bool ignoreResponse = false}) async { - + Future completeRequest( + HttpClientRequest request, { + String? data, + int? statusCode, + bool ignoreResponse = false, + }) async { if (data != null && data.isNotEmpty) { - var encoded_data = utf8.encode(data); - request.headers.set(HttpHeaders.contentLengthHeader, encoded_data.length.toString()); + request.headers.set( + HttpHeaders.contentLengthHeader, + encoded_data.length.toString(), + ); request.add(encoded_data); } APIResponse response = APIResponse( method: request.method, - url: request.uri.toString() + url: request.uri.toString(), ); String url = request.uri.toString(); try { - HttpClientResponse? _response = await request.close().timeout(Duration(seconds: 10)); + HttpClientResponse? _response = await request.close().timeout( + Duration(seconds: 10), + ); response.statusCode = _response.statusCode; @@ -1324,30 +1305,35 @@ class InvenTreeAPI { // Some server errors are not ones for us to worry about! switch (_response.statusCode) { - case 502: // Bad gateway - case 503: // Service unavailable - case 504: // Gateway timeout + case 502: // Bad gateway + case 503: // Service unavailable + case 504: // Gateway timeout break; - default: // Any other error code + default: // Any other error code sentryReportMessage( - "Server error", - context: { - "url": request.uri.toString(), - "method": request.method, - "statusCode": _response.statusCode.toString(), - "requestHeaders": request.headers.toString(), - "responseHeaders": _response.headers.toString(), - "responseData": response.data.toString(), - } + "Server error", + context: { + "url": request.uri.toString(), + "method": request.method, + "statusCode": _response.statusCode.toString(), + "requestHeaders": request.headers.toString(), + "responseHeaders": _response.headers.toString(), + "responseData": response.data.toString(), + }, ); } } else { - - response.data = ignoreResponse ? {} : await responseToJson(url, _response) ?? {}; + response.data = ignoreResponse + ? {} + : await responseToJson(url, _response) ?? {}; // First check that the returned status code is what we expected if (statusCode != null && statusCode != _response.statusCode) { - showStatusCodeError(url, _response.statusCode, details: response.data.toString()); + showStatusCodeError( + url, + _response.statusCode, + details: response.data.toString(), + ); } } } on HttpException catch (error) { @@ -1373,14 +1359,12 @@ class InvenTreeAPI { } return response; - } /* * Convert a HttpClientResponse response object to JSON */ dynamic responseToJson(String url, HttpClientResponse response) async { - String body = await response.transform(utf8.decoder).join(); try { @@ -1388,7 +1372,6 @@ class InvenTreeAPI { return data ?? {}; } on FormatException { - switch (response.statusCode) { case 400: case 401: @@ -1403,34 +1386,37 @@ class InvenTreeAPI { break; default: sentryReportMessage( - "Error decoding JSON response from server", - context: { - "headers": response.headers.toString(), - "statusCode": response.statusCode.toString(), - "data": body.toString(), - "endpoint": url, - } + "Error decoding JSON response from server", + context: { + "headers": response.headers.toString(), + "statusCode": response.statusCode.toString(), + "data": body.toString(), + "endpoint": url, + }, ); } showServerError( url, L10().formatException, - L10().formatExceptionJson + ":\n${body}" + L10().formatExceptionJson + ":\n${body}", ); // Return an empty map return {}; } - } /* * Perform a HTTP GET request * Returns a json object (or null if did not complete) */ - Future get(String url, {Map params = const {}, Map headers = const {}, int? expectedStatusCode=200}) async { - + Future get( + String url, { + Map params = const {}, + Map headers = const {}, + int? expectedStatusCode = 200, + }) async { HttpClientRequest? request = await apiRequest( url, "GET", @@ -1438,7 +1424,6 @@ class InvenTreeAPI { headers: headers, ); - if (request == null) { // Return an "invalid" APIResponse return APIResponse( @@ -1455,11 +1440,7 @@ class InvenTreeAPI { * Perform a HTTP DELETE request */ Future delete(String url) async { - - HttpClientRequest? request = await apiRequest( - url, - "DELETE", - ); + HttpClientRequest? request = await apiRequest(url, "DELETE"); if (request == null) { // Return an "invalid" APIResponse object @@ -1470,23 +1451,17 @@ class InvenTreeAPI { ); } - return completeRequest( - request, - ignoreResponse: true, - ); + return completeRequest(request, ignoreResponse: true); } // Find the current locale code for the running app String get currentLocale { - if (hasContext()) { // Try to get app context BuildContext? context = OneContext().context; if (context != null) { - Locale? locale = InvenTreeApp - .of(context) - ?.locale; + Locale? locale = InvenTreeApp.of(context)?.locale; if (locale != null) { return locale.languageCode; //.toString(); @@ -1526,8 +1501,11 @@ class InvenTreeAPI { static String get staticThumb => "/static/img/blank_image.thumbnail.png"; - CachedNetworkImage? getThumbnail(String imageUrl, {double size = 40, bool hideIfNull = false}) { - + CachedNetworkImage? getThumbnail( + String imageUrl, { + double size = 40, + bool hideIfNull = false, + }) { if (hideIfNull) { if (imageUrl.isEmpty) { return null; @@ -1535,11 +1513,7 @@ class InvenTreeAPI { } try { - return getImage( - imageUrl, - width: size, - height: size - ); + return getImage(imageUrl, width: size, height: size); } catch (error, stackTrace) { sentryReportError("_getThumbnail", error, stackTrace); return null; @@ -1550,7 +1524,11 @@ class InvenTreeAPI { * Load image from the InvenTree server, * or from local cache (if it has been cached!) */ - CachedNetworkImage getImage(String imageUrl, {double? height, double? width}) { + CachedNetworkImage getImage( + String imageUrl, { + double? height, + double? width, + }) { if (imageUrl.isEmpty) { imageUrl = staticImage; } @@ -1560,18 +1538,14 @@ class InvenTreeAPI { const key = "inventree_network_image"; CacheManager manager = CacheManager( - Config( - key, - fileService: InvenTreeFileService( - strictHttps: _strictHttps, - ), - ) + Config(key, fileService: InvenTreeFileService(strictHttps: _strictHttps)), ); return CachedNetworkImage( imageUrl: url, placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(TablerIcons.circle_x, color: COLOR_DANGER), + errorWidget: (context, url, error) => + Icon(TablerIcons.circle_x, color: COLOR_DANGER), httpHeaders: defaultHeaders(), height: height, width: width, @@ -1584,7 +1558,6 @@ class InvenTreeAPI { Map _userSettings = {}; Future getGlobalSetting(String key) async { - InvenTreeGlobalSetting? setting = _globalSettings[key]; if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { @@ -1603,7 +1576,10 @@ class InvenTreeAPI { } // Return a boolean global setting value - Future getGlobalBooleanSetting(String key, { bool backup = false }) async { + Future getGlobalBooleanSetting( + String key, { + bool backup = false, + }) async { String value = await getGlobalSetting(key); if (value.isEmpty) { @@ -1614,7 +1590,6 @@ class InvenTreeAPI { } Future getUserSetting(String key) async { - InvenTreeUserSetting? setting = _userSettings[key]; if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { @@ -1641,8 +1616,11 @@ class InvenTreeAPI { /* * Send a request to the server to locate / identify either a StockItem or StockLocation */ - Future locateItemOrLocation(BuildContext context, {int? item, int? location}) async { - + Future locateItemOrLocation( + BuildContext context, { + int? item, + int? location, + }) async { var plugins = getPlugins(mixin: "locate"); if (plugins.isEmpty) { @@ -1672,24 +1650,22 @@ class InvenTreeAPI { "value": plugins.first.key, "choices": plugin_options, "required": true, - } + }, }; await launchApiForm( - context, - L10().locateLocation, - "", - fields, - icon: TablerIcons.location_search, - onSuccess: (Map data) async { - plugin_name = (data["plugin"] ?? "") as String; - } + context, + L10().locateLocation, + "", + fields, + icon: TablerIcons.location_search, + onSuccess: (Map data) async { + plugin_name = (data["plugin"] ?? "") as String; + }, ); } - Map body = { - "plugin": plugin_name, - }; + Map body = {"plugin": plugin_name}; if (item != null) { body["item"] = item.toString(); @@ -1699,16 +1675,11 @@ class InvenTreeAPI { body["location"] = location.toString(); } - post( - "/api/locate/", - body: body, - expectedStatusCode: 200, - ).then((APIResponse response) { + post("/api/locate/", body: body, expectedStatusCode: 200).then(( + APIResponse response, + ) { if (response.successful()) { - showSnackIcon( - L10().requestSuccessful, - success: true, - ); + showSnackIcon(L10().requestSuccessful, success: true); } }); } @@ -1726,10 +1697,13 @@ class InvenTreeAPI { } // Accessors methods for various status code classes - InvenTreeStatusCode get StockHistoryStatus => _get_status_class("stock/track/status/"); + InvenTreeStatusCode get StockHistoryStatus => + _get_status_class("stock/track/status/"); InvenTreeStatusCode get StockStatus => _get_status_class("stock/status/"); - InvenTreeStatusCode get PurchaseOrderStatus => _get_status_class("order/po/status/"); - InvenTreeStatusCode get SalesOrderStatus => _get_status_class("order/so/status/"); + InvenTreeStatusCode get PurchaseOrderStatus => + _get_status_class("order/po/status/"); + InvenTreeStatusCode get SalesOrderStatus => + _get_status_class("order/so/status/"); void clearStatusCodeData() { StockHistoryStatus.data.clear(); @@ -1762,5 +1736,3 @@ class InvenTreeAPI { }); } } - - diff --git a/lib/api_form.dart b/lib/api_form.dart index 75ea5d9..e227289 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1,4 +1,3 @@ - import "dart:io"; import "package:intl/intl.dart"; @@ -27,13 +26,11 @@ import "package:inventree/widget/fields.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; - /* * Class that represents a single "form field", * defined by the InvenTree API */ class APIFormField { - // Constructor APIFormField(this.name, this.data); @@ -53,7 +50,6 @@ class APIFormField { // Return the "lookup path" for this field, within the server data String get lookupPath { - // Simple top-level case if (parent.isEmpty && !nested) { return name; @@ -133,19 +129,16 @@ class APIFormField { // Construct a set of "filters" for this field (e.g. related field) Map get filters { - Map _filters = {}; // Start with the field "definition" (provided by the server) if (definition.containsKey("filters")) { - try { var fDef = definition["filters"] as Map; fDef.forEach((String key, dynamic value) { _filters[key] = value.toString(); }); - } catch (error) { // pass } @@ -153,7 +146,6 @@ class APIFormField { // Next, look at any "instance_filters" provided by the server if (definition.containsKey("instance_filters")) { - try { var fIns = definition["instance_filters"] as Map; @@ -163,7 +155,6 @@ class APIFormField { } catch (error) { // pass } - } // Finally, augment or override with any filters provided by the calling function @@ -180,14 +171,12 @@ class APIFormField { } return _filters; - } bool hasErrors() => errorMessages().isNotEmpty; // Extract error messages from the server response void extractErrorMessages(APIResponse response) { - dynamic errors; if (isSimple) { @@ -213,7 +202,6 @@ class APIFormField { // Return the error message associated with this field List errorMessages() { - dynamic errors = data["errors"] ?? []; // Handle the case where a single error message is returned @@ -246,7 +234,6 @@ class APIFormField { List get choices => (getParameter("choices") ?? []) as List; Future loadInitialData() async { - // Only for "related fields" if (type != "related field") { return; @@ -265,10 +252,7 @@ class APIFormField { String url = api_url + "/" + pk.toString() + "/"; - final APIResponse response = await InvenTreeAPI().get( - url, - params: filters, - ); + final APIResponse response = await InvenTreeAPI().get(url, params: filters); if (response.successful()) { initial_data = response.data; @@ -277,7 +261,6 @@ class APIFormField { // Construct a widget for this input Widget constructField(BuildContext context) { - switch (type) { case "string": case "url": @@ -302,17 +285,14 @@ class APIFormField { return ListTile( title: Text( "Unsupported field type: '${type}' for field '${name}'", - style: TextStyle( - color: COLOR_DANGER, - fontStyle: FontStyle.italic), - ) + style: TextStyle(color: COLOR_DANGER, fontStyle: FontStyle.italic), + ), ); } } // Field for capturing a barcode Widget _constructBarcodeField(BuildContext context) { - TextEditingController controller = TextEditingController(); String barcode = (value ?? "").toString(); @@ -332,10 +312,7 @@ class APIFormField { hintText: placeholderText, ), child: ListTile( - title: TextField( - readOnly: true, - controller: controller, - ), + title: TextField(readOnly: true, controller: controller), trailing: IconButton( icon: Icon(TablerIcons.qrcode), onPressed: () async { @@ -349,15 +326,13 @@ class APIFormField { scanBarcode(context, handler: handler); }, ), - ) + ), ); - } // Field for displaying and selecting dates Widget _constructDateField() { - - DateTime? currentDate = DateTime.tryParse((value ?? "")as String); + DateTime? currentDate = DateTime.tryParse((value ?? "") as String); return InputDecorator( decoration: InputDecoration( @@ -387,18 +362,17 @@ class APIFormField { return time; }, - ) + ), ); - } - // Field for selecting and uploading files Widget _constructFileField() { - TextEditingController controller = TextEditingController(); - controller.text = (attachedfile?.path ?? L10().attachmentSelect).split("/").last; + controller.text = (attachedfile?.path ?? L10().attachmentSelect) + .split("/") + .last; return InputDecorator( decoration: InputDecoration( @@ -406,10 +380,7 @@ class APIFormField { labelStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), child: ListTile( - title: TextField( - readOnly: true, - controller: controller, - ), + title: TextField(readOnly: true, controller: controller), trailing: IconButton( icon: Icon(TablerIcons.circle_plus), onPressed: () async { @@ -421,17 +392,16 @@ class APIFormField { // Save the file attachedfile = file; - } + }, ); }, - ) - ) + ), + ), ); } // Field for selecting from multiple choice options Widget _constructChoiceField() { - dynamic initial; // Check if the current value is within the allowed values @@ -445,17 +415,16 @@ class APIFormField { return DropdownSearch( popupProps: PopupProps.bottomSheet( showSelectedItems: false, - searchFieldProps: TextFieldProps( - autofocus: true - ) + searchFieldProps: TextFieldProps(autofocus: true), ), selectedItem: initial, items: choices, dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: label, - hintText: helpText, - )), + dropdownSearchDecoration: InputDecoration( + labelText: label, + hintText: helpText, + ), + ), onChanged: null, clearButtonProps: ClearButtonProps(isVisible: !required), itemAsString: (dynamic item) { @@ -467,12 +436,12 @@ class APIFormField { } else { data["value"] = item["value"]; } - }); + }, + ); } // Construct a floating point numerical input field Widget _constructFloatField() { - // Initial value: try to cast to a valid number String initial = ""; @@ -491,7 +460,10 @@ class APIFormField { hintText: placeholderText, ), initialValue: initial, - keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), + keyboardType: TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), validator: (value) { value = value?.trim() ?? ""; @@ -512,7 +484,6 @@ class APIFormField { data["value"] = val; }, ); - } // Construct an input for a related field @@ -528,22 +499,20 @@ class APIFormField { emptyBuilder: (context, item) { return _renderEmptyResult(); }, - searchFieldProps: TextFieldProps( - autofocus: true - ) + searchFieldProps: TextFieldProps(autofocus: true), ), selectedItem: initial_data, asyncItems: (String filter) async { - Map _filters = { - ..._relatedFieldFilters(), - ...filters, - }; + Map _filters = {..._relatedFieldFilters(), ...filters}; _filters["search"] = filter; _filters["offset"] = "0"; _filters["limit"] = "25"; - final APIResponse response = await InvenTreeAPI().get(api_url, params: _filters); + final APIResponse response = await InvenTreeAPI().get( + api_url, + params: _filters, + ); if (response.isValid()) { return response.resultsList(); @@ -551,14 +520,13 @@ class APIFormField { return []; } }, - clearButtonProps: ClearButtonProps( - isVisible: !required - ), + clearButtonProps: ClearButtonProps(isVisible: !required), dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: label, - hintText: helpText, - )), + dropdownSearchDecoration: InputDecoration( + labelText: label, + hintText: helpText, + ), + ), onChanged: null, itemAsString: (dynamic item) { Map data = item as Map; @@ -607,12 +575,12 @@ class APIFormField { } return result; - }); + }, + ); } // Construct a set of custom filters for the dropdown search Map _relatedFieldFilters() { - switch (model) { case InvenTreeSupplierPart.MODEL_TYPE: return InvenTreeSupplierPart().defaultListFilters(); @@ -626,8 +594,12 @@ class APIFormField { } // Render a "related field" based on the "model" type - Widget _renderRelatedField(String fieldName, dynamic item, bool selected, bool extended) { - + Widget _renderRelatedField( + String fieldName, + dynamic item, + bool selected, + bool extended, + ) { // Convert to JSON Map data = {}; @@ -641,14 +613,16 @@ class APIFormField { data = {}; sentryReportError( - "_renderRelatedField", error, stackTrace, + "_renderRelatedField", + error, + stackTrace, context: { "method": "_renderRelateField", "field_name": fieldName, "item": item.toString(), "selected": selected.toString(), "extended": extended.toString(), - } + }, ); } @@ -658,52 +632,71 @@ class APIFormField { return ListTile( title: Text( - part.fullname, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + part.fullname, + style: TextStyle( + fontWeight: selected && extended + ? FontWeight.bold + : FontWeight.normal, + ), ), - subtitle: extended ? Text( - part.description, - style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), - ) : null, - leading: extended ? InvenTreeAPI().getThumbnail(part.thumbnail) : null, + subtitle: extended + ? Text( + part.description, + style: TextStyle( + fontWeight: selected ? FontWeight.bold : FontWeight.normal, + ), + ) + : null, + leading: extended + ? InvenTreeAPI().getThumbnail(part.thumbnail) + : null, ); case InvenTreePartTestTemplate.MODEL_TYPE: - var template = InvenTreePartTestTemplate.fromJson(data); + var template = InvenTreePartTestTemplate.fromJson(data); - return ListTile( - title: Text(template.testName), - subtitle: Text(template.description), - ); + return ListTile( + title: Text(template.testName), + subtitle: Text(template.description), + ); case InvenTreeSupplierPart.MODEL_TYPE: var part = InvenTreeSupplierPart.fromJson(data); return ListTile( title: Text(part.SKU), subtitle: Text(part.partName), - leading: extended ? InvenTreeAPI().getThumbnail(part.partImage) : null, - trailing: extended && part.supplierImage.isNotEmpty ? InvenTreeAPI().getThumbnail(part.supplierImage) : null, + leading: extended + ? InvenTreeAPI().getThumbnail(part.partImage) + : null, + trailing: extended && part.supplierImage.isNotEmpty + ? InvenTreeAPI().getThumbnail(part.supplierImage) + : null, ); case InvenTreePartCategory.MODEL_TYPE: - var cat = InvenTreePartCategory.fromJson(data); return ListTile( title: Text( - cat.pathstring, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + cat.pathstring, + style: TextStyle( + fontWeight: selected && extended + ? FontWeight.bold + : FontWeight.normal, + ), ), - subtitle: extended ? Text( - cat.description, - style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), - ) : null, + subtitle: extended + ? Text( + cat.description, + style: TextStyle( + fontWeight: selected ? FontWeight.bold : FontWeight.normal, + ), + ) + : null, ); case InvenTreeStockItem.MODEL_TYPE: var item = InvenTreeStockItem.fromJson(data); return ListTile( - title: Text( - item.partName, - ), + title: Text(item.partName), leading: InvenTreeAPI().getThumbnail(item.partThumbnail), trailing: Text(item.quantityString()), ); @@ -712,13 +705,21 @@ class APIFormField { return ListTile( title: Text( - loc.pathstring, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + loc.pathstring, + style: TextStyle( + fontWeight: selected && extended + ? FontWeight.bold + : FontWeight.normal, + ), ), - subtitle: extended ? Text( - loc.description, - style: TextStyle(fontWeight: selected ? FontWeight.bold : FontWeight.normal), - ) : null, + subtitle: extended + ? Text( + loc.description, + style: TextStyle( + fontWeight: selected ? FontWeight.bold : FontWeight.normal, + ), + ) + : null, ); case InvenTreeSalesOrderShipment.MODEL_TYPE: var shipment = InvenTreeSalesOrderShipment.fromJson(data); @@ -738,32 +739,26 @@ class APIFormField { case "contact": String name = (data["name"] ?? "") as String; String role = (data["role"] ?? "") as String; - return ListTile( - title: Text(name), - subtitle: Text(role), - ); + return ListTile(title: Text(name), subtitle: Text(role)); case InvenTreeCompany.MODEL_TYPE: var company = InvenTreeCompany.fromJson(data); return ListTile( - title: Text(company.name), - subtitle: extended ? Text(company.description) : null, - leading: InvenTreeAPI().getThumbnail(company.thumbnail) + title: Text(company.name), + subtitle: extended ? Text(company.description) : null, + leading: InvenTreeAPI().getThumbnail(company.thumbnail), ); case InvenTreeProjectCode.MODEL_TYPE: var project_code = InvenTreeProjectCode.fromJson(data); return ListTile( - title: Text(project_code.code), - subtitle: Text(project_code.description), - leading: Icon(TablerIcons.list) + title: Text(project_code.code), + subtitle: Text(project_code.description), + leading: Icon(TablerIcons.list), ); default: return ListTile( title: Text( - "Unsupported model", - style: TextStyle( - fontWeight: FontWeight.bold, - color: COLOR_DANGER - ) + "Unsupported model", + style: TextStyle(fontWeight: FontWeight.bold, color: COLOR_DANGER), ), subtitle: Text("Model '${model}' rendering not supported"), ); @@ -782,10 +777,8 @@ class APIFormField { ); } - // Construct a string input element Widget _constructString() { - if (readOnly) { return ListTile( title: Text(label), @@ -821,7 +814,6 @@ class APIFormField { // Construct a boolean input element Widget _constructBoolean() { - bool? initial_value; if (value is bool || value == null) { @@ -860,15 +852,12 @@ class APIFormField { color: hasErrors() ? COLOR_DANGER : null, ); } - } - /* * Extract field options from a returned OPTIONS request */ Map extractFields(APIResponse response) { - if (!response.isValid()) { return {}; } @@ -896,8 +885,10 @@ Map extractFields(APIResponse response) { * The map "tree" is traversed based on the provided lookup string, which can use dotted notation. * This allows complex paths to be used to lookup field information. */ -Map extractFieldDefinition(Map data, String lookup) { - +Map extractFieldDefinition( + Map data, + String lookup, +) { List path = lookup.split("."); // Shadow copy the data for path traversal @@ -905,7 +896,6 @@ Map extractFieldDefinition(Map data, String lo // Iterate through all but the last element of the path for (int ii = 0; ii < (path.length - 1); ii++) { - String el = path[ii]; if (!_data.containsKey(el)) { @@ -923,11 +913,9 @@ Map extractFieldDefinition(Map data, String lo // Report the error sentryReportError( "apiForm.extractFieldDefinition : path traversal", - error, stackTrace, - context: { - "path": path.toString(), - "el": el, - } + error, + stackTrace, + context: {"path": path.toString(), "el": el}, ); return {}; } @@ -938,7 +926,6 @@ Map extractFieldDefinition(Map data, String lo if (!_data.containsKey(el)) { return {}; } else { - try { Map definition = _data[el] as Map; @@ -950,19 +937,16 @@ Map extractFieldDefinition(Map data, String lo // Report the error sentryReportError( "apiForm.extractFieldDefinition : as map", - error, stacktrace, - context: { - "el": el.toString(), - } + error, + stacktrace, + context: {"el": el.toString()}, ); return {}; } - } } - /* * Launch an API-driven form, * which uses the OPTIONS metadata (at the provided URL) @@ -976,24 +960,24 @@ Map extractFieldDefinition(Map data, String lo */ Future launchApiForm( - BuildContext context, String title, String url, Map fields, - { - String fileField = "", - Map modelData = const {}, - String method = "PATCH", - Function(Map)? onSuccess, - bool Function(Map)? validate, - Function? onCancel, - IconData icon = TablerIcons.device_floppy - }) async { - + BuildContext context, + String title, + String url, + Map fields, { + String fileField = "", + Map modelData = const {}, + String method = "PATCH", + Function(Map)? onSuccess, + bool Function(Map)? validate, + Function? onCancel, + IconData icon = TablerIcons.device_floppy, +}) async { showLoadingOverlay(); // List of fields defined by the server Map serverFields = {}; if (url.isNotEmpty) { - var options = await InvenTreeAPI().options(url); // Invalid response from server @@ -1006,10 +990,7 @@ Future launchApiForm( if (serverFields.isEmpty) { // User does not have permission to perform this action - showSnackIcon( - L10().response403, - icon: TablerIcons.user_x, - ); + showSnackIcon(L10().response403, icon: TablerIcons.user_x); hideLoadingOverlay(); return; @@ -1022,7 +1003,6 @@ Future launchApiForm( APIFormField field; for (String fieldName in fields.keys) { - dynamic data = fields[fieldName]; Map fieldData = {}; @@ -1066,35 +1046,33 @@ Future launchApiForm( // Now, launch a new widget! Navigator.push( context, - MaterialPageRoute(builder: (context) => APIFormWidget( - title, - url, - formFields, - method, - onSuccess: onSuccess, - validate: validate, - fileField: fileField, - icon: icon, - )) + MaterialPageRoute( + builder: (context) => APIFormWidget( + title, + url, + formFields, + method, + onSuccess: onSuccess, + validate: validate, + fileField: fileField, + icon: icon, + ), + ), ); } - class APIFormWidget extends StatefulWidget { - const APIFormWidget( - this.title, - this.url, - this.fields, - this.method, - { - Key? key, - this.onSuccess, - this.validate, - this.fileField = "", - this.icon = TablerIcons.device_floppy, - } - ) : super(key: key); + this.title, + this.url, + this.fields, + this.method, { + Key? key, + this.onSuccess, + this.validate, + this.fileField = "", + this.icon = TablerIcons.device_floppy, + }) : super(key: key); //! Form title to display final String title; @@ -1118,12 +1096,9 @@ class APIFormWidget extends StatefulWidget { @override _APIFormWidgetState createState() => _APIFormWidgetState(); - } - class _APIFormWidgetState extends State { - _APIFormWidgetState() : super(); final _formKey = GlobalKey(); @@ -1133,7 +1108,6 @@ class _APIFormWidgetState extends State { bool spacerRequired = false; List _buildForm() { - List widgets = []; // Display non-field errors first @@ -1141,26 +1115,16 @@ class _APIFormWidgetState extends State { for (String error in nonFieldErrors) { widgets.add( ListTile( - title: Text( - error, - style: TextStyle( - color: COLOR_DANGER, - ), - ), - leading: Icon( - TablerIcons.exclamation_circle, - color: COLOR_DANGER - ), - ) + title: Text(error, style: TextStyle(color: COLOR_DANGER)), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + ), ); } widgets.add(Divider(height: 5)); - } for (var field in widget.fields) { - if (field.hidden) { continue; } @@ -1189,8 +1153,8 @@ class _APIFormWidgetState extends State { fontStyle: FontStyle.italic, fontSize: 16, ), - ) - ) + ), + ), ); } } @@ -1210,20 +1174,16 @@ class _APIFormWidgetState extends State { } Future _submit(Map data) async { - // If a file upload is required, we have to handle the submission differently if (widget.fileField.isNotEmpty) { - // Pop the "file" field data.remove(widget.fileField); for (var field in widget.fields) { if (field.name == widget.fileField) { - File? file = field.attachedfile; if (file != null) { - // A valid file has been supplied final response = await InvenTreeAPI().uploadFile( widget.url, @@ -1239,23 +1199,21 @@ class _APIFormWidgetState extends State { } if (widget.method == "POST") { - showLoadingOverlay(); - final response = await InvenTreeAPI().post( + final response = await InvenTreeAPI().post( widget.url, body: data, - expectedStatusCode: null + expectedStatusCode: null, ); hideLoadingOverlay(); return response; - } else { showLoadingOverlay(); final response = await InvenTreeAPI().patch( widget.url, body: data, - expectedStatusCode: null + expectedStatusCode: null, ); hideLoadingOverlay(); @@ -1264,17 +1222,12 @@ class _APIFormWidgetState extends State { } void extractNonFieldErrors(APIResponse response) { - List errors = []; Map data = response.asMap(); // Potential keys representing non-field errors - List keys = [ - "__all__", - "non_field_errors", - "errors", - ]; + List keys = ["__all__", "non_field_errors", "errors"]; for (String key in keys) { if (data.containsKey(key)) { @@ -1301,7 +1254,6 @@ class _APIFormWidgetState extends State { var errors = response.asMap(); for (String fieldName in errors.keys) { - bool match = false; switch (fieldName) { @@ -1313,7 +1265,6 @@ class _APIFormWidgetState extends State { continue; default: for (var field in widget.fields) { - // Hidden fields can't display errors, so we won't match if (field.hidden) { continue; @@ -1324,7 +1275,6 @@ class _APIFormWidgetState extends State { match = true; break; } else if (field.parent == fieldName) { - var error = errors[fieldName]; if (error is List) { @@ -1340,7 +1290,6 @@ class _APIFormWidgetState extends State { } } } - } if (!match) { @@ -1352,7 +1301,7 @@ class _APIFormWidgetState extends State { "status_code": response.statusCode.toString(), "field": fieldName, "error_message": response.data.toString(), - } + }, ); } } @@ -1362,14 +1311,12 @@ class _APIFormWidgetState extends State { * Submit the form data to the server, and handle the results */ Future _save(BuildContext context) async { - // Package up the form data Map data = {}; // Iterate through and find "simple" top-level fields for (var field in widget.fields) { - if (field.readOnly) { continue; } @@ -1380,7 +1327,6 @@ class _APIFormWidgetState extends State { } else { // Not so simple... (WHY DID I MAKE THE API SO COMPLEX?) if (field.parent.isNotEmpty) { - // TODO: This is a dirty hack, there *must* be a cleaner way?! dynamic parent = data[field.parent] ?? {}; @@ -1402,7 +1348,7 @@ class _APIFormWidgetState extends State { } } } - + final bool isValid = widget.validate?.call(data) ?? true; if (!isValid) { @@ -1442,7 +1388,6 @@ class _APIFormWidgetState extends State { Navigator.pop(context); if (successFunc != null) { - // Ensure the response is a valid JSON structure Map json = {}; @@ -1457,10 +1402,7 @@ class _APIFormWidgetState extends State { return; case 400: // Form submission / validation error - showSnackIcon( - L10().formError, - success: false, - ); + showSnackIcon(L10().formError, success: false); // Update field errors for (var field in widget.fields) { @@ -1470,30 +1412,15 @@ class _APIFormWidgetState extends State { extractNonFieldErrors(response); checkInvalidErrors(response); case 401: - showSnackIcon( - "401: " + L10().response401, - success: false - ); + showSnackIcon("401: " + L10().response401, success: false); case 403: - showSnackIcon( - "403: " + L10().response403, - success: false, - ); + showSnackIcon("403: " + L10().response403, success: false); case 404: - showSnackIcon( - "404: " + L10().response404, - success: false, - ); + showSnackIcon("404: " + L10().response404, success: false); case 405: - showSnackIcon( - "405: " + L10().response405, - success: false, - ); + showSnackIcon("405: " + L10().response405, success: false); case 500: - showSnackIcon( - "500: " + L10().response500, - success: false, - ); + showSnackIcon("500: " + L10().response500, success: false); default: showSnackIcon( "${response.statusCode}: " + L10().responseInvalid, @@ -1504,12 +1431,10 @@ class _APIFormWidgetState extends State { setState(() { // Refresh the form }); - } @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( title: Text(widget.title), @@ -1518,15 +1443,14 @@ class _APIFormWidgetState extends State { IconButton( icon: Icon(widget.icon), onPressed: () { - if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); _save(context); } }, - ) - ] + ), + ], ), body: Form( key: _formKey, @@ -1538,9 +1462,8 @@ class _APIFormWidgetState extends State { children: _buildForm(), ), padding: EdgeInsets.all(16), - ) - ) + ), + ), ); - } } diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 5ed9e20..aeda838 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -4,7 +4,6 @@ import "package:inventree/helpers.dart"; import "package:one_context/one_context.dart"; bool isDarkMode() { - if (!hasContext()) { return false; } diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart index 7cd2f0f..ddbb319 100644 --- a/lib/barcode/barcode.dart +++ b/lib/barcode/barcode.dart @@ -10,7 +10,6 @@ import "package:inventree/widget/company/manufacturer_part_detail.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; import "package:one_context/one_context.dart"; - import "package:inventree/api.dart"; import "package:inventree/l10.dart"; @@ -35,10 +34,8 @@ import "package:inventree/widget/stock/stock_detail.dart"; import "package:inventree/widget/company/company_detail.dart"; import "package:inventree/widget/company/supplier_part_detail.dart"; - // Signal a barcode scan success to the user Future barcodeSuccess(String msg) async { - barcodeSuccessTone(); showSnackIcon(msg, success: true); } @@ -47,24 +44,23 @@ Future barcodeSuccess(String msg) async { Future barcodeFailure(String msg, dynamic extra) async { barcodeFailureTone(); showSnackIcon( - msg, - success: false, + msg, + success: false, onAction: () { - if (hasContext()) { - OneContext().showDialog( - builder: (BuildContext context) => - SimpleDialog( - title: Text(L10().barcodeError), - children: [ - ListTile( - title: Text(L10().responseData), - subtitle: Text(extra.toString()) - ) - ] - ) - ); - } - } + if (hasContext()) { + OneContext().showDialog( + builder: (BuildContext context) => SimpleDialog( + title: Text(L10().barcodeError), + children: [ + ListTile( + title: Text(L10().responseData), + subtitle: Text(extra.toString()), + ), + ], + ), + ); + } + }, ); } @@ -75,15 +71,22 @@ Future barcodeFailure(String msg, dynamic extra) async { * - Returns a Future which resolves when the scanner is dismissed * - The provided BarcodeHandler instance is used to handle the scanned barcode */ -Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) async { - +Future scanBarcode( + BuildContext context, { + BarcodeHandler? handler, +}) async { // Default to generic scan handler handler ??= BarcodeScanHandler(); - + InvenTreeBarcodeController controller = CameraBarcodeController(handler); // Select barcode controller based on user preference - final int barcodeControllerType = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_TYPE, BARCODE_CONTROLLER_CAMERA) as int; + final int barcodeControllerType = + await InvenTreeSettingsManager().getValue( + INV_BARCODE_SCAN_TYPE, + BARCODE_CONTROLLER_CAMERA, + ) + as int; switch (barcodeControllerType) { case BARCODE_CONTROLLER_WEDGE: @@ -95,14 +98,10 @@ Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) asy } return Navigator.of(context).push( - PageRouteBuilder( - pageBuilder: (context, _, _) => controller, - opaque: false, - ) + PageRouteBuilder(pageBuilder: (context, _, _) => controller, opaque: false), ); } - /* * Class for general barcode scanning. * Scan *any* barcode without context, and then redirect app to correct view. @@ -116,19 +115,17 @@ Future scanBarcode(BuildContext context, {BarcodeHandler? handler}) asy * - PurchaseOrder */ class BarcodeScanHandler extends BarcodeHandler { - @override String getOverlayText(BuildContext context) => L10().barcodeScanGeneral; @override Future onBarcodeUnknown(Map data) async { - barcodeFailureTone(); showSnackIcon( - L10().barcodeNoMatch, - icon: TablerIcons.exclamation_circle, - success: false, + L10().barcodeNoMatch, + icon: TablerIcons.exclamation_circle, + success: false, ); } @@ -136,12 +133,13 @@ class BarcodeScanHandler extends BarcodeHandler { * Response when a "Part" instance is scanned */ Future handlePart(int pk) async { - var part = await InvenTreePart().get(pk); if (part is InvenTreePart) { OneContext().pop(); - OneContext().push(MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + OneContext().push( + MaterialPageRoute(builder: (context) => PartDetailWidget(part)), + ); } } @@ -149,13 +147,13 @@ class BarcodeScanHandler extends BarcodeHandler { * Response when a "StockItem" instance is scanned */ Future handleStockItem(int pk) async { - var item = await InvenTreeStockItem().get(pk); if (item is InvenTreeStockItem) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => StockDetailWidget(item))); + OneContext().push( + MaterialPageRoute(builder: (context) => StockDetailWidget(item)), + ); } } @@ -163,13 +161,13 @@ class BarcodeScanHandler extends BarcodeHandler { * Response when a "StockLocation" instance is scanned */ Future handleStockLocation(int pk) async { - var loc = await InvenTreeStockLocation().get(pk); if (loc is InvenTreeStockLocation) { OneContext().pop(); - OneContext().navigator.push(MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc))); + OneContext().navigator.push( + MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc)), + ); } } @@ -177,13 +175,15 @@ class BarcodeScanHandler extends BarcodeHandler { * Response when a "SupplierPart" instance is scanned */ Future handleSupplierPart(int pk) async { - var supplierPart = await InvenTreeSupplierPart().get(pk); if (supplierPart is InvenTreeSupplierPart) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(supplierPart))); + OneContext().push( + MaterialPageRoute( + builder: (context) => SupplierPartDetailWidget(supplierPart), + ), + ); } } @@ -195,8 +195,11 @@ class BarcodeScanHandler extends BarcodeHandler { if (manufacturerPart is InvenTreeManufacturerPart) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => ManufacturerPartDetailWidget(manufacturerPart))); + OneContext().push( + MaterialPageRoute( + builder: (context) => ManufacturerPartDetailWidget(manufacturerPart), + ), + ); } } @@ -205,8 +208,9 @@ class BarcodeScanHandler extends BarcodeHandler { if (company is InvenTreeCompany) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => CompanyDetailWidget(company))); + OneContext().push( + MaterialPageRoute(builder: (context) => CompanyDetailWidget(company)), + ); } } @@ -218,8 +222,11 @@ class BarcodeScanHandler extends BarcodeHandler { if (order is InvenTreePurchaseOrder) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => PurchaseOrderDetailWidget(order))); + OneContext().push( + MaterialPageRoute( + builder: (context) => PurchaseOrderDetailWidget(order), + ), + ); } } @@ -229,8 +236,9 @@ class BarcodeScanHandler extends BarcodeHandler { if (order is InvenTreeSalesOrder) { OneContext().pop(); - OneContext().push(MaterialPageRoute( - builder: (context) => SalesOrderDetailWidget(order))); + OneContext().push( + MaterialPageRoute(builder: (context) => SalesOrderDetailWidget(order)), + ); } } @@ -250,7 +258,6 @@ class BarcodeScanHandler extends BarcodeHandler { InvenTreeManufacturerPart.MODEL_TYPE, ]; - if (InvenTreeAPI().supportsOrderBarcodes) { validModels.add(InvenTreePurchaseOrder.MODEL_TYPE); validModels.add(InvenTreeSalesOrder.MODEL_TYPE); @@ -274,7 +281,6 @@ class BarcodeScanHandler extends BarcodeHandler { // A valid result has been found if (pk > 0 && model.isNotEmpty) { - barcodeSuccessTone(); switch (model) { @@ -312,35 +318,31 @@ class BarcodeScanHandler extends BarcodeHandler { barcodeFailureTone(); showSnackIcon( - L10().barcodeUnknown, - success: false, - onAction: () { - - if (hasContext()) { - OneContext().showDialog( - builder: (BuildContext context) => - SimpleDialog( - title: Text(L10().unknownResponse), - children: [ - ListTile( - title: Text(L10().responseData), - subtitle: Text(data.toString()), - ) - ], - ) - ); - } + L10().barcodeUnknown, + success: false, + onAction: () { + if (hasContext()) { + OneContext().showDialog( + builder: (BuildContext context) => SimpleDialog( + title: Text(L10().unknownResponse), + children: [ + ListTile( + title: Text(L10().responseData), + subtitle: Text(data.toString()), + ), + ], + ), + ); } + }, ); } } - /* * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) */ class UniqueBarcodeHandler extends BarcodeHandler { - UniqueBarcodeHandler(this.callback, {this.overlayText = ""}); // Callback function when a "unique" barcode hash is found @@ -360,11 +362,7 @@ class UniqueBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(Map data) async { if (!data.containsKey("hash") && !data.containsKey("barcode_hash")) { - showServerError( - "barcode/", - L10().missingData, - L10().barcodeMissingHash, - ); + showServerError("barcode/", L10().missingData, L10().barcodeMissingHash); } else { String barcode; @@ -373,12 +371,8 @@ class UniqueBarcodeHandler extends BarcodeHandler { if (barcode.isEmpty) { barcodeFailureTone(); - showSnackIcon( - L10().barcodeError, - success: false, - ); + showSnackIcon(L10().barcodeError, success: false); } else { - barcodeSuccessTone(); // Close the barcode scanner @@ -395,41 +389,43 @@ class UniqueBarcodeHandler extends BarcodeHandler { Future onBarcodeUnknown(Map data) async { await onBarcodeMatched(data); } - } - -SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, String barcode, String model, int pk) { - +SpeedDialChild customBarcodeAction( + BuildContext context, + RefreshableState state, + String barcode, + String model, + int pk, +) { if (barcode.isEmpty) { return SpeedDialChild( label: L10().barcodeAssign, child: Icon(Icons.barcode_reader), onTap: () { var handler = UniqueBarcodeHandler((String barcode) { - InvenTreeAPI().linkBarcode({ - model: pk.toString(), - "barcode": barcode, - }).then((bool result) { - showSnackIcon( - result ? L10().barcodeAssigned : L10().barcodeNotAssigned, - success: result - ); + InvenTreeAPI() + .linkBarcode({model: pk.toString(), "barcode": barcode}) + .then((bool result) { + showSnackIcon( + result ? L10().barcodeAssigned : L10().barcodeNotAssigned, + success: result, + ); - state.refresh(context); - }); + state.refresh(context); + }); }); scanBarcode(context, handler: handler); - } + }, ); } else { return SpeedDialChild( child: Icon(Icons.barcode_reader), label: L10().barcodeUnassign, onTap: () { - InvenTreeAPI().unlinkBarcode({ - model: pk.toString() - }).then((bool result) { + InvenTreeAPI().unlinkBarcode({model: pk.toString()}).then(( + bool result, + ) { showSnackIcon( result ? L10().requestSuccessful : L10().requestFailed, success: result, @@ -437,7 +433,7 @@ SpeedDialChild customBarcodeAction(BuildContext context, RefreshableState state, state.refresh(context); }); - } + }, ); } } diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart index d6bfa6a..9e2fe50 100644 --- a/lib/barcode/camera_controller.dart +++ b/lib/barcode/camera_controller.dart @@ -273,8 +273,9 @@ class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState { } Widget bottomCenterOverlay() { - String info_text = - scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause; + String info_text = scanning_paused + ? L10().barcodeScanPaused + : L10().barcodeScanPause; String text = scanned_code.isNotEmpty ? scanned_code : info_text; diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart index 3a8fa2c..70a7986 100644 --- a/lib/barcode/controller.dart +++ b/lib/barcode/controller.dart @@ -11,7 +11,6 @@ import "package:inventree/widget/progress.dart"; * which is used to process the scanned barcode. */ class InvenTreeBarcodeController extends StatefulWidget { - const InvenTreeBarcodeController(this.handler, {Key? key}) : super(key: key); final BarcodeHandler handler; @@ -20,16 +19,17 @@ class InvenTreeBarcodeController extends StatefulWidget { State createState() => InvenTreeBarcodeControllerState(); } - /* * Base state widget for the barcode controller. * This defines the basic interface for the barcode controller. */ -class InvenTreeBarcodeControllerState extends State { - +class InvenTreeBarcodeControllerState + extends State { InvenTreeBarcodeControllerState() : super(); - final GlobalKey barcodeControllerKey = GlobalKey(debugLabel: "barcodeController"); + final GlobalKey barcodeControllerKey = GlobalKey( + debugLabel: "barcodeController", + ); // Internal state flag to test if we are currently processing a barcode bool processingBarcode = false; @@ -40,7 +40,6 @@ class InvenTreeBarcodeControllerState extends State * Barcode data should be passed as a string */ Future handleBarcodeData(String? data) async { - // Check that the data is valid, and this view is still mounted if (!mounted || data == null || data.isEmpty) { return; @@ -66,7 +65,9 @@ class InvenTreeBarcodeControllerState extends State return; } - int delay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; + int delay = + await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) + as int; Future.delayed(Duration(milliseconds: delay), () { hideLoadingOverlay(); @@ -99,5 +100,4 @@ class InvenTreeBarcodeControllerState extends State Widget build(BuildContext context) { return Container(); } - -} \ No newline at end of file +} diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart index 48831f9..3b9a72c 100644 --- a/lib/barcode/handler.dart +++ b/lib/barcode/handler.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -13,7 +12,6 @@ import "package:inventree/inventree/sentry.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/snacks.dart"; - /* Generic class which "handles" a barcode, by communicating with the InvenTree server, * and handling match / unknown / error cases. * @@ -21,7 +19,6 @@ import "package:inventree/widget/snacks.dart"; * based on the response returned from the InvenTree server */ class BarcodeHandler { - BarcodeHandler(); // Return the text to display on the barcode overlay @@ -57,23 +54,23 @@ class BarcodeHandler { * * Returns true only if the barcode scanner should remain open */ - Future processBarcode(String barcode, - {String url = "barcode/", - Map extra_data = const {}}) async { - + Future processBarcode( + String barcode, { + String url = "barcode/", + Map extra_data = const {}, + }) async { debug("Scanned barcode data: '${barcode}'"); barcode = barcode.trim(); // Empty barcode is invalid if (barcode.isEmpty) { - barcodeFailureTone(); showSnackIcon( L10().barcodeError, icon: TablerIcons.exclamation_circle, - success: false + success: false, ); return; @@ -84,10 +81,7 @@ class BarcodeHandler { try { response = await InvenTreeAPI().post( url, - body: { - "barcode": barcode, - ...extra_data, - }, + body: {"barcode": barcode, ...extra_data}, expectedStatusCode: null, // Do not show an error on "unexpected code" ); } catch (error, stackTrace) { @@ -113,17 +107,17 @@ class BarcodeHandler { // We want to know about this one! await sentryReportMessage( - "BarcodeHandler.processBarcode returned unexpected value", - context: { - "data": response.data?.toString() ?? "null", - "barcode": barcode, - "url": url, - "statusCode": response.statusCode.toString(), - "valid": response.isValid().toString(), - "error": response.error, - "errorDetail": response.errorDetail, - "className": "${this}", - } + "BarcodeHandler.processBarcode returned unexpected value", + context: { + "data": response.data?.toString() ?? "null", + "barcode": barcode, + "url": url, + "statusCode": response.statusCode.toString(), + "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, + "className": "${this}", + }, ); } else if (data.containsKey("success")) { await onBarcodeMatched(data); diff --git a/lib/barcode/purchase_order.dart b/lib/barcode/purchase_order.dart index 8b2f984..65f4913 100644 --- a/lib/barcode/purchase_order.dart +++ b/lib/barcode/purchase_order.dart @@ -20,7 +20,6 @@ import "package:inventree/widget/snacks.dart"; * - If location or quantity information wasn't provided, show a form to fill it in */ class POReceiveBarcodeHandler extends BarcodeHandler { - POReceiveBarcodeHandler({this.purchaseOrder, this.location, this.lineItem}); InvenTreePurchaseOrder? purchaseOrder; @@ -31,11 +30,15 @@ class POReceiveBarcodeHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().barcodeReceivePart; @override - Future processBarcode(String barcode, - {String url = "barcode/po-receive/", - Map extra_data = const {}}) async { - - final bool confirm = await InvenTreeSettingsManager().getBool(INV_PO_CONFIRM_SCAN, true); + Future processBarcode( + String barcode, { + String url = "barcode/po-receive/", + Map extra_data = const {}, + }) async { + final bool confirm = await InvenTreeSettingsManager().getBool( + INV_PO_CONFIRM_SCAN, + true, + ); final po_extra_data = { "purchase_order": purchaseOrder?.pk, @@ -50,7 +53,6 @@ class POReceiveBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(Map data) async { - if (data.containsKey("lineitem") || data.containsKey("success")) { barcodeSuccess(L10().receivedItem); return; @@ -66,7 +68,8 @@ class POReceiveBarcodeHandler extends BarcodeHandler { } final lineItemData = data["lineitem"] as Map; - if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { + if (!lineItemData.containsKey("pk") || + !lineItemData.containsKey("purchase_order")) { barcodeFailureTone(); showSnackIcon(L10().missingData, success: false); } @@ -79,7 +82,8 @@ class POReceiveBarcodeHandler extends BarcodeHandler { return; } - InvenTreePOLineItem? lineItem = await InvenTreePOLineItem().get(lineItemId) as InvenTreePOLineItem?; + InvenTreePOLineItem? lineItem = + await InvenTreePOLineItem().get(lineItemId) as InvenTreePOLineItem?; if (lineItem == null) { barcodeFailureTone(); @@ -89,7 +93,9 @@ class POReceiveBarcodeHandler extends BarcodeHandler { // Next, extract the "optional" fields // Extract information from the returned server response - double? quantity = double.tryParse((lineItemData["quantity"] ?? "0").toString()); + double? quantity = double.tryParse( + (lineItemData["quantity"] ?? "0").toString(), + ); int? destination = lineItemData["location"] as int?; String? barcode = data["barcode_data"] as String?; @@ -105,7 +111,7 @@ class POReceiveBarcodeHandler extends BarcodeHandler { barcode: barcode, onSuccess: () { showSnackIcon(L10().receivedItem, success: true); - } + }, ); } @@ -113,18 +119,16 @@ class POReceiveBarcodeHandler extends BarcodeHandler { Future onBarcodeUnknown(Map data) async { barcodeFailureTone(); showSnackIcon( - data["error"] as String? ?? L10().barcodeError, - success: false + data["error"] as String? ?? L10().barcodeError, + success: false, ); } } - /* * Barcode handler to add a line item to a purchase order */ class POAllocateBarcodeHandler extends BarcodeHandler { - POAllocateBarcodeHandler({this.purchaseOrder}); InvenTreePurchaseOrder? purchaseOrder; @@ -133,21 +137,14 @@ class POAllocateBarcodeHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().scanSupplierPart; @override - Future processBarcode(String barcode, { + Future processBarcode( + String barcode, { String url = "barcode/po-allocate/", - Map extra_data = const {}} - ) { + Map extra_data = const {}, + }) { + final po_extra_data = {"purchase_order": purchaseOrder?.pk, ...extra_data}; - final po_extra_data = { - "purchase_order": purchaseOrder?.pk, - ...extra_data, - }; - - return super.processBarcode( - barcode, - url: url, - extra_data: po_extra_data, - ); + return super.processBarcode(barcode, url: url, extra_data: po_extra_data); } @override @@ -189,10 +186,9 @@ class POAllocateBarcodeHandler extends BarcodeHandler { @override Future onBarcodeUnhandled(Map data) async { - print("onBarcodeUnhandled:"); print(data.toString()); super.onBarcodeUnhandled(data); } -} \ No newline at end of file +} diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart index e0e79ad..75fbdc0 100644 --- a/lib/barcode/sales_order.dart +++ b/lib/barcode/sales_order.dart @@ -14,13 +14,11 @@ import "package:inventree/barcode/tones.dart"; import "package:inventree/widget/snacks.dart"; - /* * Barcode handler class for scanning a new part into a SalesOrder */ class SOAddItemBarcodeHandler extends BarcodeHandler { - SOAddItemBarcodeHandler({this.salesOrder}); InvenTreeSalesOrder? salesOrder; @@ -30,7 +28,6 @@ class SOAddItemBarcodeHandler extends BarcodeHandler { @override Future onBarcodeMatched(Map data) async { - // Extract the part ID from the returned data int part_id = -1; @@ -46,7 +43,6 @@ class SOAddItemBarcodeHandler extends BarcodeHandler { var part = await InvenTreePart().get(part_id); if (part is InvenTreePart) { - if (part.isSalable) { // Dispose of the barcode scanner if (OneContext.hasContext) { @@ -68,23 +64,18 @@ class SOAddItemBarcodeHandler extends BarcodeHandler { L10().lineItemAdd, fields: fields, ); - } else { barcodeFailureTone(); showSnackIcon(L10().partNotSalable, success: false); } - } else { // Failed to fetch part return onBarcodeUnknown(data); } - } } - class SOAllocateStockHandler extends BarcodeHandler { - SOAllocateStockHandler({this.salesOrder, this.lineItem, this.shipment}); InvenTreeSalesOrder? salesOrder; @@ -95,16 +86,16 @@ class SOAllocateStockHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().allocateStock; @override - Future processBarcode(String barcode, - { + Future processBarcode( + String barcode, { String url = "barcode/so-allocate/", - Map extra_data = const {}}) { - + Map extra_data = const {}, + }) { final so_extra_data = { "sales_order": salesOrder?.pk, "shipment": shipment?.pk, "line": lineItem?.pk, - ...extra_data + ...extra_data, }; return super.processBarcode(barcode, url: url, extra_data: so_extra_data); @@ -121,8 +112,8 @@ class SOAllocateStockHandler extends BarcodeHandler { @override Future onBarcodeUnhandled(Map data) async { - - if (!data.containsKey("action_required") || !data.containsKey("line_item")) { + if (!data.containsKey("action_required") || + !data.containsKey("line_item")) { return super.onBarcodeUnhandled(data); } @@ -132,10 +123,7 @@ class SOAllocateStockHandler extends BarcodeHandler { // Update fields with data gathered from the API response fields["line_item"]?["value"] = data["line_item"]; - Map stock_filters = { - "in_stock": true, - "available": true, - }; + Map stock_filters = {"in_stock": true, "available": true}; if (data.containsKey("part")) { stock_filters["part"] = data["part"]; @@ -147,9 +135,7 @@ class SOAllocateStockHandler extends BarcodeHandler { fields["quantity"]?["value"] = data["quantity"]; fields["shipment"]?["value"] = data["shipment"]; - fields["shipment"]?["filters"] = { - "order": salesOrder!.pk.toString() - }; + fields["shipment"]?["filters"] = {"order": salesOrder!.pk.toString()}; final context = OneContext().context!; @@ -157,20 +143,21 @@ class SOAllocateStockHandler extends BarcodeHandler { context, L10().allocateStock, salesOrder!.allocate_url, - fields, - method: "POST", - icon: TablerIcons.transition_right, - onSuccess: (data) async { + fields, + method: "POST", + icon: TablerIcons.transition_right, + onSuccess: (data) async { showSnackIcon(L10().allocated, success: true); - }); + }, + ); } @override Future onBarcodeUnknown(Map data) async { barcodeFailureTone(); showSnackIcon( - data["error"] as String? ?? L10().barcodeError, - success: false + data["error"] as String? ?? L10().barcodeError, + success: false, ); } -} \ No newline at end of file +} diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart index 126d1d0..09826f7 100644 --- a/lib/barcode/stock.dart +++ b/lib/barcode/stock.dart @@ -16,7 +16,6 @@ import "package:inventree/inventree/stock.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/snacks.dart"; - /* * Generic class for scanning a StockLocation. * @@ -24,20 +23,17 @@ import "package:inventree/widget/snacks.dart"; * - Runs a "callback" function if a valid StockLocation is found */ class BarcodeScanStockLocationHandler extends BarcodeHandler { - @override String getOverlayText(BuildContext context) => L10().barcodeScanLocation; @override Future onBarcodeMatched(Map data) async { - // We expect that the barcode points to a 'stocklocation' if (data.containsKey("stocklocation")) { int _loc = (data["stocklocation"]?["pk"] ?? -1) as int; // A valid stock location! if (_loc > 0) { - debug("Scanned stock location ${_loc}"); final bool result = await onLocationScanned(_loc); @@ -52,10 +48,7 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { // If we get to this point, something went wrong during the scan process barcodeFailureTone(); - showSnackIcon( - L10().invalidStockLocation, - success: false, - ); + showSnackIcon(L10().invalidStockLocation, success: false); } // Callback function which runs when a valid StockLocation is scanned @@ -64,10 +57,8 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { // Re-implement this for particular subclass return false; } - } - /* * Generic class for scanning a StockItem * @@ -75,7 +66,6 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler { * - Runs a "callback" function if a valid StockItem is found */ class BarcodeScanStockItemHandler extends BarcodeHandler { - @override String getOverlayText(BuildContext context) => L10().barcodeScanItem; @@ -87,7 +77,6 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { // A valid stock location! if (_item > 0) { - barcodeSuccessTone(); bool result = await onItemScanned(_item); @@ -102,10 +91,7 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { // If we get to this point, something went wrong during the scan process barcodeFailureTone(); - showSnackIcon( - L10().invalidStockItem, - success: false, - ); + showSnackIcon(L10().invalidStockItem, success: false); } // Callback function which runs when a valid StockItem is scanned @@ -115,7 +101,6 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { } } - /* * Barcode handler for scanning a provided StockItem into a scanned StockLocation. * @@ -124,20 +109,20 @@ class BarcodeScanStockItemHandler extends BarcodeHandler { * - The StockItem is transferred into the scanned location */ class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { - StockItemScanIntoLocationHandler(this.item); final InvenTreeStockItem item; @override Future onLocationScanned(int locationId) async { - - final bool confirm = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); + final bool confirm = await InvenTreeSettingsManager().getBool( + INV_STOCK_CONFIRM_SCAN, + false, + ); bool result = false; if (confirm) { - Map fields = item.transferFields(); // Override location with scanned value @@ -152,7 +137,7 @@ class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { icon: TablerIcons.transfer, onSuccess: (data) async { showSnackIcon(L10().stockItemUpdated, success: true); - } + }, ); return true; @@ -171,7 +156,6 @@ class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { } } - /* * Barcode handler for scanning stock item(s) into the specified StockLocation. * @@ -180,7 +164,6 @@ class StockItemScanIntoLocationHandler extends BarcodeScanStockLocationHandler { * - The scanned StockItem is transferred into the provided StockLocation */ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { - StockLocationScanInItemsHandler(this.location); final InvenTreeStockLocation location; @@ -190,14 +173,16 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { @override Future onItemScanned(int itemId) async { - - final InvenTreeStockItem? item = await InvenTreeStockItem().get(itemId) as InvenTreeStockItem?; - final bool confirm = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); + final InvenTreeStockItem? item = + await InvenTreeStockItem().get(itemId) as InvenTreeStockItem?; + final bool confirm = await InvenTreeSettingsManager().getBool( + INV_STOCK_CONFIRM_SCAN, + false, + ); bool result = false; if (item != null) { - // Item is already *in* the specified location if (item.locationId == location.pk) { barcodeFailureTone(); @@ -211,25 +196,26 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { fields["location"]?["value"] = location.pk; launchApiForm( - OneContext().context!, - L10().transferStock, - InvenTreeStockItem.transferStockUrl(), - fields, - method: "POST", - icon: TablerIcons.transfer, - onSuccess: (data) async { - showSnackIcon(L10().stockItemUpdated, success: true); - } + OneContext().context!, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: TablerIcons.transfer, + onSuccess: (data) async { + showSnackIcon(L10().stockItemUpdated, success: true); + }, ); return true; - } else { result = await item.transferStock(location.pk); showSnackIcon( - result ? L10().barcodeScanIntoLocationSuccess : L10().barcodeScanIntoLocationFailure, - success: result + result + ? L10().barcodeScanIntoLocationSuccess + : L10().barcodeScanIntoLocationFailure, + success: result, ); } } @@ -240,7 +226,6 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { } } - /* * Barcode handler class for scanning a StockLocation into another StockLocation * @@ -249,18 +234,14 @@ class StockLocationScanInItemsHandler extends BarcodeScanStockItemHandler { * - The scanned StockLocation is set as the "parent" of the provided StockLocation */ class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { - ScanParentLocationHandler(this.location); final InvenTreeStockLocation location; @override Future onLocationScanned(int locationId) async { - final response = await location.update( - values: { - "parent": locationId.toString(), - }, + values: {"parent": locationId.toString()}, expectedStatusCode: null, ); @@ -269,22 +250,19 @@ class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { case 201: barcodeSuccess(L10().barcodeScanIntoLocationSuccess); return true; - case 400: // Invalid parent location chosen + case 400: // Invalid parent location chosen barcodeFailureTone(); showSnackIcon(L10().invalidStockLocation, success: false); return false; default: barcodeFailureTone(); showSnackIcon( - L10().barcodeScanIntoLocationFailure, - success: false, - actionText: L10().details, - onAction: () { - showErrorDialog( - L10().barcodeError, - response: response, - ); - } + L10().barcodeScanIntoLocationFailure, + success: false, + actionText: L10().details, + onAction: () { + showErrorDialog(L10().barcodeError, response: response); + }, ); return false; } diff --git a/lib/barcode/tones.dart b/lib/barcode/tones.dart index a6e4b77..0d8fddc 100644 --- a/lib/barcode/tones.dart +++ b/lib/barcode/tones.dart @@ -5,19 +5,21 @@ import "package:inventree/preferences.dart"; * Play an audible 'success' alert to the user. */ Future barcodeSuccessTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; + final bool en = + await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) + as bool; if (en) { playAudioFile("sounds/barcode_scan.mp3"); } } -Future barcodeFailureTone() async { - - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; +Future barcodeFailureTone() async { + final bool en = + await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) + as bool; if (en) { playAudioFile("sounds/barcode_error.mp3"); } -} \ No newline at end of file +} diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart index b3147e5..5edf0f5 100644 --- a/lib/barcode/wedge_controller.dart +++ b/lib/barcode/wedge_controller.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -15,17 +14,14 @@ import "package:inventree/helpers.dart"; * intercepting barcode data which is entered as rapid keyboard presses */ class WedgeBarcodeController extends InvenTreeBarcodeController { - - const WedgeBarcodeController(BarcodeHandler handler, {Key? key}) : super(handler, key: key); + const WedgeBarcodeController(BarcodeHandler handler, {Key? key}) + : super(handler, key: key); @override State createState() => _WedgeBarcodeControllerState(); - } - class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { - _WedgeBarcodeControllerState() : super(); bool canScan = true; @@ -40,7 +36,6 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future pauseScan() async { - if (mounted) { setState(() { canScan = false; @@ -50,7 +45,6 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Future resumeScan() async { - if (mounted) { setState(() { canScan = true; @@ -60,7 +54,6 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { // Callback for a single key press / scan void handleKeyEvent(KeyEvent event) { - if (!scanning) { return; } @@ -78,7 +71,8 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { DateTime now = DateTime.now(); // Throw away old characters - if (_lastScanTime == null || _lastScanTime!.isBefore(now.subtract(Duration(milliseconds: 250)))) { + if (_lastScanTime == null || + _lastScanTime!.isBefore(now.subtract(Duration(milliseconds: 250)))) { _scannedCharacters.clear(); } @@ -99,7 +93,6 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( backgroundColor: COLOR_APP_BAR, @@ -118,7 +111,7 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { focusNode: _focusNode, child: SizedBox( child: CircularProgressIndicator( - color: scanning ? COLOR_ACTION : COLOR_PROGRESS + color: scanning ? COLOR_ACTION : COLOR_PROGRESS, ), width: 64, height: 64, @@ -140,14 +133,14 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState { widget.handler.getOverlayText(context), style: TextStyle( fontWeight: FontWeight.bold, - color: Colors.white) + color: Colors.white, + ), ), padding: EdgeInsets.all(20), - ) + ), ], - ) - ) + ), + ), ); } - -} \ No newline at end of file +} diff --git a/lib/dsn.dart b/lib/dsn.dart index 39092c8..87eb6eb 100644 --- a/lib/dsn.dart +++ b/lib/dsn.dart @@ -1,7 +1,7 @@ - /* * For integration with sentry.io, fill out the SENTRY_DSN_KEY value below. * This should be set to a valid DSN key, from your sentry.io account * */ -String SENTRY_DSN_KEY = "https://fea705aa4b8e4c598dcf9b146b3d1b86@o378676.ingest.sentry.io/5202450"; \ No newline at end of file +String SENTRY_DSN_KEY = + "https://fea705aa4b8e4c598dcf9b146b3d1b86@o378676.ingest.sentry.io/5202450"; diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart deleted file mode 100644 index ad002d5..0000000 --- a/lib/generated/i18n.dart +++ /dev/null @@ -1,76 +0,0 @@ - -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. - -class S implements WidgetsLocalizations { - const S(); - - static const GeneratedLocalizationsDelegate delegate = GeneratedLocalizationsDelegate(); - - static S of(BuildContext context) => Localizations.of(context, WidgetsLocalizations); - - @override - TextDirection get textDirection => TextDirection.ltr; - -} - -class en extends S { - const en(); -} - - -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { - const GeneratedLocalizationsDelegate(); - - List get supportedLocales { - return const [ - - const Locale("en", ""), - - ]; - } - - LocaleResolutionCallback resolution({Locale fallback}) { - return (Locale locale, Iterable supported) { - 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) { - final String lang = getLang(locale); - switch (lang) { - - case "en": - return new SynchronousFuture(const en()); - - default: - return new SynchronousFuture(const S()); - } - } - - @override - bool isSupported(Locale locale) => supportedLocales.contains(locale); - - @override - bool shouldReload(GeneratedLocalizationsDelegate old) => false; -} - -String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); diff --git a/lib/helpers.dart b/lib/helpers.dart index 349a821..5f74c00 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -17,8 +17,6 @@ import "package:audioplayers/audioplayers.dart"; import "package:inventree/l10.dart"; import "package:inventree/widget/snacks.dart"; - - List debug_messages = []; void clearDebugMessage() => debug_messages.clear(); @@ -44,14 +42,12 @@ bool debugContains(String msg, {bool raiseAssert = true}) { } if (raiseAssert) { - assert(result); } return result; } - bool isTesting() { return Platform.environment.containsKey("FLUTTER_TEST"); } @@ -64,12 +60,10 @@ bool hasContext() { } } - /* * Display a debug message if we are in testing mode, or running in debug mode */ void debug(dynamic msg) { - if (Platform.environment.containsKey("FLUTTER_TEST")) { debug_messages.add(msg.toString()); } @@ -77,13 +71,11 @@ void debug(dynamic msg) { print("DEBUG: ${msg.toString()}"); } - /* * Simplify string representation of a floating point value * Basically, don't display fractional component if it is an integer */ String simpleNumberString(double number) { - if (number.toInt() == number) { return number.toInt().toString(); } else { @@ -98,7 +90,6 @@ String simpleNumberString(double number) { * we will not attempt to play the sound */ Future playAudioFile(String path) async { - // Debug message for unit testing debug("Playing audio file: '${path}'"); @@ -110,21 +101,21 @@ Future playAudioFile(String path) async { // Specify context options for the audio player // Ref: https://github.com/inventree/inventree-app/issues/582 - player.setAudioContext(AudioContext( - android: AudioContextAndroid( - usageType: AndroidUsageType.notification, - audioFocus: AndroidAudioFocus.none, + player.setAudioContext( + AudioContext( + android: AudioContextAndroid( + usageType: AndroidUsageType.notification, + audioFocus: AndroidAudioFocus.none, + ), + iOS: AudioContextIOS(), ), - iOS: AudioContextIOS() - )); + ); player.play(AssetSource(path)); } - // Open an external URL Future openLink(String url) async { - final link = Uri.parse(url); try { @@ -134,24 +125,20 @@ Future openLink(String url) async { } } - /* * Helper function for rendering a money / currency object as a String */ String renderCurrency(double? amount, String currency, {int decimals = 2}) { - if (amount == null || amount.isInfinite || amount.isNaN) return "-"; currency = currency.trim(); if (currency.isEmpty) return "-"; - CurrencyFormat fmt = CurrencyFormat.fromCode(currency.toLowerCase()) ?? CurrencyFormat.usd; + CurrencyFormat fmt = + CurrencyFormat.fromCode(currency.toLowerCase()) ?? CurrencyFormat.usd; - String value = CurrencyFormatter.format( - amount, - fmt - ); + String value = CurrencyFormatter.format(amount, fmt); return value; } @@ -163,8 +150,11 @@ bool isValidNumber(double? value) { /* * Render a "range" of prices between two values. */ -String formatPriceRange(double? minPrice, double? maxPrice, { String? currency }) { - +String formatPriceRange( + double? minPrice, + double? maxPrice, { + String? currency, +}) { // Account for empty or null values if (!isValidNumber(minPrice) && !isValidNumber(maxPrice)) { return "-"; diff --git a/lib/inventree/bom.dart b/lib/inventree/bom.dart index 8019ecf..7c89376 100644 --- a/lib/inventree/bom.dart +++ b/lib/inventree/bom.dart @@ -1,4 +1,3 @@ - import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; @@ -6,13 +5,13 @@ import "package:inventree/inventree/part.dart"; * Class representing the BomItem database model */ class InvenTreeBomItem extends InvenTreeModel { - InvenTreeBomItem() : super(); InvenTreeBomItem.fromJson(Map json) : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeBomItem.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeBomItem.fromJson(json); @override String get URL => "bom/"; @@ -28,7 +27,7 @@ class InvenTreeBomItem extends InvenTreeModel { // Extract the 'reference' value associated with this BomItem String get reference => getString("reference"); - + // Extract the 'quantity' value associated with this BomItem double get quantity => getDouble("quantity"); @@ -57,8 +56,8 @@ class InvenTreeBomItem extends InvenTreeModel { } return null; -} + } // Extract the ID of the related sub-part int get subPartId => getInt("sub_part"); -} \ No newline at end of file +} diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 072f0fe..43f7d51 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -6,13 +6,11 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/purchase_order.dart"; import "package:inventree/widget/company/company_detail.dart"; - /* * The InvenTreeCompany class represents the Company model in the InvenTree database. */ class InvenTreeCompany extends InvenTreeModel { - InvenTreeCompany() : super(); InvenTreeCompany.fromJson(Map json) : super.fromJson(json); @@ -26,14 +24,16 @@ class InvenTreeCompany extends InvenTreeModel { Future goToDetailPage(BuildContext context) async { return Navigator.push( context, - MaterialPageRoute( - builder: (context) => CompanyDetailWidget(this) - ) + MaterialPageRoute(builder: (context) => CompanyDetailWidget(this)), ); } @override - List get rolesRequired => ["purchase_order", "sales_order", "return_order"]; + List get rolesRequired => [ + "purchase_order", + "sales_order", + "return_order", + ]; @override Map> formFields() { @@ -54,12 +54,16 @@ class InvenTreeCompany extends InvenTreeModel { return fields; } - String get image => (jsondata["image"] ?? jsondata["thumbnail"] ?? InvenTreeAPI.staticImage) as String; + String get image => + (jsondata["image"] ?? jsondata["thumbnail"] ?? InvenTreeAPI.staticImage) + as String; - String get thumbnail => (jsondata["thumbnail"] ?? jsondata["image"] ?? InvenTreeAPI.staticThumb) as String; + String get thumbnail => + (jsondata["thumbnail"] ?? jsondata["image"] ?? InvenTreeAPI.staticThumb) + as String; String get website => getString("website"); - + String get phone => getString("phone"); String get email => getString("email"); @@ -73,22 +77,21 @@ class InvenTreeCompany extends InvenTreeModel { bool get active => getBool("active", backup: true); int get partSuppliedCount => getInt("part_supplied"); - - int get partManufacturedCount => getInt("parts_manufactured"); - - // Request a list of purchase orders against this company - Future> getPurchaseOrders({bool? outstanding}) async { - Map filters = { - "supplier": "${pk}" - }; + int get partManufacturedCount => getInt("parts_manufactured"); + + // Request a list of purchase orders against this company + Future> getPurchaseOrders({ + bool? outstanding, + }) async { + Map filters = {"supplier": "${pk}"}; if (outstanding != null) { filters["outstanding"] = outstanding ? "true" : "false"; } final List results = await InvenTreePurchaseOrder().list( - filters: filters + filters: filters, ); List orders = []; @@ -103,18 +106,18 @@ class InvenTreeCompany extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) => InvenTreeCompany.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeCompany.fromJson(json); } - /* * Class representing an attachment file against a Company object */ class InvenTreeCompanyAttachment extends InvenTreeAttachment { - InvenTreeCompanyAttachment() : super(); - InvenTreeCompanyAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreeCompanyAttachment.fromJson(Map json) + : super.fromJson(json); @override String get REFERENCE_FIELD => "company"; @@ -123,21 +126,23 @@ class InvenTreeCompanyAttachment extends InvenTreeAttachment { String get REF_MODEL_TYPE => "company"; @override - String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "company/attachment/"; + String get URL => InvenTreeAPI().supportsModernAttachments + ? "attachment/" + : "company/attachment/"; @override - InvenTreeModel createFromJson(Map json) => InvenTreeCompanyAttachment.fromJson(json); - + InvenTreeModel createFromJson(Map json) => + InvenTreeCompanyAttachment.fromJson(json); } /* * The InvenTreeSupplierPart class represents the SupplierPart model in the InvenTree database */ class InvenTreeSupplierPart extends InvenTreeModel { - InvenTreeSupplierPart() : super(); - InvenTreeSupplierPart.fromJson(Map json) : super.fromJson(json); + InvenTreeSupplierPart.fromJson(Map json) + : super.fromJson(json); @override String get URL => "company/part/"; @@ -180,37 +185,47 @@ class InvenTreeSupplierPart extends InvenTreeModel { }; } - int get manufacturerId => getInt("pk", subKey: "manufacturer_detail"); - - String get manufacturerName => getString("name", subKey: "manufacturer_detail"); - + + String get manufacturerName => + getString("name", subKey: "manufacturer_detail"); + String get MPN => getString("MPN", subKey: "manufacturer_part_detail"); - - String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + + String get manufacturerImage => + (jsondata["manufacturer_detail"]?["image"] ?? + jsondata["manufacturer_detail"]?["thumbnail"] ?? + InvenTreeAPI.staticThumb) + as String; int get manufacturerPartId => getInt("manufacturer_part"); - + int get supplierId => getInt("supplier"); - + String get supplierName => getString("name", subKey: "supplier_detail"); - - String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + + String get supplierImage => + (jsondata["supplier_detail"]?["image"] ?? + jsondata["supplier_detail"]?["thumbnail"] ?? + InvenTreeAPI.staticThumb) + as String; String get SKU => getString("SKU"); bool get active => getBool("active", backup: true); - + int get partId => getInt("part"); - String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get partImage => + (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) + as String; String get partName => getString("name", subKey: "part_detail"); Map get partDetail => getMap("part_detail"); String get partDescription => getString("description", subKey: "part_detail"); - + String get note => getString("note"); String get packaging => getString("packaging"); @@ -224,15 +239,15 @@ class InvenTreeSupplierPart extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) => InvenTreeSupplierPart.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSupplierPart.fromJson(json); } - class InvenTreeManufacturerPart extends InvenTreeModel { - InvenTreeManufacturerPart() : super(); - InvenTreeManufacturerPart.fromJson(Map json) : super.fromJson(json); + InvenTreeManufacturerPart.fromJson(Map json) + : super.fromJson(json); @override String URL = "company/part/manufacturer/"; @@ -255,10 +270,7 @@ class InvenTreeManufacturerPart extends InvenTreeModel { @override Map defaultFilters() { - return { - "manufacturer_detail": "true", - "part_detail": "true", - }; + return {"manufacturer_detail": "true", "part_detail": "true"}; } int get partId => getInt("part"); @@ -269,18 +281,27 @@ class InvenTreeManufacturerPart extends InvenTreeModel { String get partIPN => getString("IPN", subKey: "part_detail"); - String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get partImage => + (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) + as String; int get manufacturerId => getInt("manufacturer"); - String get manufacturerName => getString("name", subKey: "manufacturer_detail"); + String get manufacturerName => + getString("name", subKey: "manufacturer_detail"); - String get manufacturerDescription => getString("description", subKey: "manufacturer_detail"); + String get manufacturerDescription => + getString("description", subKey: "manufacturer_detail"); - String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; + String get manufacturerImage => + (jsondata["manufacturer_detail"]?["image"] ?? + jsondata["manufacturer_detail"]?["thumbnail"] ?? + InvenTreeAPI.staticThumb) + as String; String get MPN => getString("MPN"); @override - InvenTreeModel createFromJson(Map json) => InvenTreeManufacturerPart.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeManufacturerPart.fromJson(json); } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 6df483a..c3fc8b6 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -17,10 +17,8 @@ import "package:inventree/inventree/sentry.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/fields.dart"; - // Paginated response object class InvenTreePageResponse { - InvenTreePageResponse() { results = []; } @@ -31,7 +29,7 @@ class InvenTreePageResponse { // Total number of results in the dataset int count = 0; - + int get length => results.length; List results = []; @@ -42,7 +40,6 @@ class InvenTreePageResponse { * for interacting with InvenTree data. */ class InvenTreeModel { - InvenTreeModel(); // Construct an InvenTreeModel from a JSON data object @@ -87,7 +84,6 @@ class InvenTreeModel { // If a subKey is specified, we need to dig deeper into the JSON data if (subKey.isNotEmpty) { - if (!data.containsKey(subKey)) { debug("JSON data does not contain subKey '$subKey' for key '$key'"); return backup; @@ -98,7 +94,6 @@ class InvenTreeModel { if (sub_data is Map) { data = (data[subKey] ?? {}) as Map; } - } if (data.containsKey(key)) { @@ -109,7 +104,11 @@ class InvenTreeModel { } // Helper function to get sub-map from JSON data - Map getMap(String key, {Map backup = const {}, String subKey = ""}) { + Map getMap( + String key, { + Map backup = const {}, + String subKey = "", + }) { dynamic value = getValue(key, backup: backup, subKey: subKey); if (value == null) { @@ -152,7 +151,7 @@ class InvenTreeModel { return double.tryParse(value.toString()) ?? backup; } - double getDouble(String key, {double backup = 0.0, String subkey = "" }) { + double getDouble(String key, {double backup = 0.0, String subkey = ""}) { double? value = getDoubleOrNull(key, backup: backup, subKey: subkey); return value ?? backup; } @@ -194,7 +193,6 @@ class InvenTreeModel { // Return the InvenTree web server URL for this object String get webUrl { - if (api.isConnected()) { String web = InvenTreeAPI().baseUrl; @@ -205,7 +203,6 @@ class InvenTreeModel { web = web.replaceAll("//", "/"); return web; - } else { return ""; } @@ -216,7 +213,9 @@ class InvenTreeModel { */ List get rolesRequired { // Default implementation should not be called - debug("rolesRequired() not implemented for model ${URL} - returning empty list"); + debug( + "rolesRequired() not implemented for model ${URL} - returning empty list", + ); return []; } @@ -271,12 +270,17 @@ class InvenTreeModel { // Fields for editing / creating this model // Override per-model Map> formFields() { - return {}; } - Future createForm(BuildContext context, String title, {String fileField = "", Map fields=const{}, Map data=const {}, Function(dynamic)? onSuccess}) async { - + Future createForm( + BuildContext context, + String title, { + String fileField = "", + Map fields = const {}, + Map data = const {}, + Function(dynamic)? onSuccess, + }) async { if (fields.isEmpty) { fields = formFields(); } @@ -291,14 +295,17 @@ class InvenTreeModel { method: "POST", fileField: fileField, ); - } /* * Launch a modal form to edit the fields available to this model instance. */ - Future editForm(BuildContext context, String title, {Map fields=const {}, Function(dynamic)? onSuccess}) async { - + Future editForm( + BuildContext context, + String title, { + Map fields = const {}, + Function(dynamic)? onSuccess, + }) async { if (fields.isEmpty) { fields = formFields(); } @@ -310,9 +317,8 @@ class InvenTreeModel { fields, modelData: jsondata, onSuccess: onSuccess, - method: "PATCH" + method: "PATCH", ); - } // JSON data which defines this object @@ -324,12 +330,12 @@ class InvenTreeModel { int get pk => getInt("pk"); String get pkString => pk.toString(); - + // Some common accessors String get name => getString("name"); String get description => getString("description"); - + String get notes => getString("notes"); int get parentId => getInt("parent"); @@ -387,8 +393,7 @@ class InvenTreeModel { return ""; } - Future goToInvenTreePage() async { - + Future goToInvenTreePage() async { var uri = Uri.tryParse(webUrl); if (uri != null && await canLaunchUrl(uri)) { await launchUrl(uri); @@ -397,8 +402,7 @@ class InvenTreeModel { } } - Future openLink() async { - + Future openLink() async { if (link.isNotEmpty) { var uri = Uri.tryParse(link); if (uri != null && await canLaunchUrl(uri)) { @@ -408,16 +412,21 @@ class InvenTreeModel { } String get keywords => getString("keywords"); - + // Create a new object from JSON data (not a constructor!) - InvenTreeModel createFromJson(Map json) => InvenTreeModel.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeModel.fromJson(json); // Return the API detail endpoint for this Model object String get url => "${URL}/${pk}/".replaceAll("//", "/"); // Search this Model type in the database - Future> search(String searchTerm, {Map filters = const {}, int offset = 0, int limit = 25}) async { - + Future> search( + String searchTerm, { + Map filters = const {}, + int offset = 0, + int limit = 25, + }) async { Map searchFilters = {}; for (String key in filters.keys) { @@ -431,12 +440,13 @@ class InvenTreeModel { final results = list(filters: searchFilters); return results; - } // Return the number of results that would meet a particular "query" - Future count({Map filters = const {}, String searchQuery = ""} ) async { - + Future count({ + Map filters = const {}, + String searchQuery = "", + }) async { var params = defaultListFilters(); filters.forEach((String key, String value) { @@ -458,7 +468,7 @@ class InvenTreeModel { } else { return 0; } -} + } Map defaultFilters() { return {}; @@ -476,8 +486,11 @@ class InvenTreeModel { /* * Report error information to sentry, when a model operation fails. */ - Future reportModelError(String title, APIResponse response, {Map context = const {}}) async { - + Future reportModelError( + String title, + APIResponse response, { + Map context = const {}, + }) async { String dataString = response.data?.toString() ?? "null"; // If the response has "errorDetail" set, then the error has already been handled, and there is no need to continue @@ -506,16 +519,12 @@ class InvenTreeModel { context["dataType"] = response.data?.runtimeType.toString() ?? "null"; context["model"] = URL; - await sentryReportMessage( - title, - context: context, - ); + await sentryReportMessage(title, context: context); } /// Delete the instance on the remote server /// Returns true if the operation was successful, else false Future delete() async { - // Return if we do not have a valid pk if (pk < 0) { return false; @@ -523,18 +532,15 @@ class InvenTreeModel { var response = await api.delete(url); - if (!response.isValid() || response.data == null || (response.data is! Map)) { - + if (!response.isValid() || + response.data == null || + (response.data is! Map)) { reportModelError( "InvenTreeModel.delete() returned invalid response", response, ); - showServerError( - url, - L10().serverError, - L10().errorDelete, - ); + showServerError(url, L10().serverError, L10().errorDelete); return false; } @@ -547,52 +553,40 @@ class InvenTreeModel { * Reload this object, by requesting data from the server */ Future reload() async { - // If we do not have a valid pk (for some reason), exit immediately if (pk < 0) { return false; } - var response = await api.get(url, params: defaultGetFilters(), expectedStatusCode: 200); + var response = await api.get( + url, + params: defaultGetFilters(), + expectedStatusCode: 200, + ); // A valid response has been returned if (response.isValid() && response.statusCode == 200) { - // Returned data was not a valid JSON object if (response.data == null || response.data is! Map) { reportModelError( - "InvenTreeModel.reload() returned invalid response", - response, - context: { - "pk": pk.toString(), - } + "InvenTreeModel.reload() returned invalid response", + response, + context: {"pk": pk.toString()}, ); - showServerError( - url, - L10().serverError, - L10().responseInvalid, - ); + showServerError(url, L10().serverError, L10().responseInvalid); return false; } } else { - switch (response.statusCode) { case 404: // Object has been deleted - showSnackIcon( - L10().itemDeleted, - success: false, - ); + showSnackIcon(L10().itemDeleted, success: false); default: String detail = L10().errorFetch; detail += "\n${L10().statusCode}: ${response.statusCode}"; - showServerError( - url, - L10().serverError, - detail - ); + showServerError(url, L10().serverError, detail); } return false; @@ -606,15 +600,15 @@ class InvenTreeModel { } // POST data to update the model - Future update({Map values = const {}, int? expectedStatusCode = 200}) async { - + Future update({ + Map values = const {}, + int? expectedStatusCode = 200, + }) async { var url = path.join(URL, pk.toString()); // Return if we do not have a valid pk if (pk < 0) { - return APIResponse( - url: url, - ); + return APIResponse(url: url); } if (!url.endsWith("/")) { @@ -631,8 +625,10 @@ class InvenTreeModel { } // Return the detail view for the associated pk - Future getModel(String pk, {Map filters = const {}}) async { - + Future getModel( + String pk, { + Map filters = const {}, + }) async { var url = path.join(URL, pk.toString()); if (!url.endsWith("/")) { @@ -649,27 +645,18 @@ class InvenTreeModel { var response = await api.get(url, params: params); if (!response.isValid() || response.data == null || response.data is! Map) { - if (response.statusCode != -1) { // Report error reportModelError( - "InvenTreeModel.getModel() returned invalid response", - response, - context: { - "filters": filters.toString(), - "pk": pk, - } + "InvenTreeModel.getModel() returned invalid response", + response, + context: {"filters": filters.toString(), "pk": pk}, ); } - showServerError( - url, - L10().serverError, - L10().errorFetch, - ); + showServerError(url, L10().serverError, L10().errorFetch); return null; - } lastReload = DateTime.now(); @@ -677,8 +664,10 @@ class InvenTreeModel { return createFromJson(response.asMap()); } - Future get(int pk, {Map filters = const {}}) async { - + Future get( + int pk, { + Map filters = const {}, + }) async { if (pk < 0) { return null; } @@ -687,7 +676,6 @@ class InvenTreeModel { } Future create(Map data) async { - if (data.containsKey("pk")) { data.remove("pk"); } @@ -700,20 +688,13 @@ class InvenTreeModel { // Invalid response returned from server if (!response.isValid() || response.data == null || response.data is! Map) { - reportModelError( - "InvenTreeModel.create() returned invalid response", - response, - context: { - "pk": pk.toString(), - } + "InvenTreeModel.create() returned invalid response", + response, + context: {"pk": pk.toString()}, ); - showServerError( - URL, - L10().serverError, - L10().errorCreate, - ); + showServerError(URL, L10().serverError, L10().errorCreate); return null; } @@ -721,7 +702,11 @@ class InvenTreeModel { return createFromJson(response.asMap()); } - Future listPaginated(int limit, int offset, {Map filters = const {}}) async { + Future listPaginated( + int limit, + int offset, { + Map filters = const {}, + }) async { var params = defaultListFilters(); for (String key in filters.keys) { @@ -737,7 +722,6 @@ class InvenTreeModel { * - In such a case, we want to concatenate them together */ if (params.containsKey("original_search")) { - String search = params["search"] ?? ""; String original = params["original_search"] ?? ""; @@ -759,18 +743,20 @@ class InvenTreeModel { // First attempt is to look for paginated data, returned as a map - if (dataMap.isNotEmpty && dataMap.containsKey("count") && dataMap.containsKey("results")) { + if (dataMap.isNotEmpty && + dataMap.containsKey("count") && + dataMap.containsKey("results")) { page.count = (dataMap["count"] ?? 0) as int; - page.results = []; + page.results = []; - List results = dataMap["results"] as List; + List results = dataMap["results"] as List; - for (dynamic result in results) { - page.addResult(createFromJson(result as Map)); - } + for (dynamic result in results) { + page.addResult(createFromJson(result as Map)); + } - return page; + return page; } // Second attempt is to look for a list of data (not paginated) @@ -782,7 +768,7 @@ class InvenTreeModel { for (var result in dataList) { page.addResult(createFromJson(result as Map)); - } + } return page; } @@ -792,7 +778,9 @@ class InvenTreeModel { } // Return list of objects from the database, with optional filters - Future> list({Map filters = const {}}) async { + Future> list({ + Map filters = const {}, + }) async { var params = defaultListFilters(); for (String key in filters.keys) { @@ -821,7 +809,6 @@ class InvenTreeModel { } for (var d in data) { - // Create a new object (of the current class type InvenTreeModel obj = createFromJson(d as Map); @@ -847,7 +834,6 @@ class InvenTreeModel { // Each filter must be matched // Used for (e.g.) filtering returned results bool filter(String filterString) { - List filters = filterString.trim().toLowerCase().split(" "); for (var f in filters) { @@ -860,22 +846,20 @@ class InvenTreeModel { } } - /* * Class representing a single plugin instance */ class InvenTreePlugin extends InvenTreeModel { - InvenTreePlugin() : super(); InvenTreePlugin.fromJson(Map json) : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreePlugin.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePlugin.fromJson(json); @override String get URL { - /* Note: The plugin API endpoint changed at API version 90, * < 90 = 'plugin' * >= 90 = 'plugins' @@ -889,23 +873,24 @@ class InvenTreePlugin extends InvenTreeModel { } String get key => getString("key"); - + bool get active => getBool("active"); - + // Return the metadata struct for this plugin - Map get _meta => (jsondata["meta"] ?? {}) as Map; + Map get _meta => + (jsondata["meta"] ?? {}) as Map; String get humanName => (_meta["human_name"] ?? "") as String; // Return the mixins struct for this plugin - Map get _mixins => (jsondata["mixins"] ?? {}) as Map; + Map get _mixins => + (jsondata["mixins"] ?? {}) as Map; bool supportsMixin(String mixin) { return _mixins.containsKey(mixin); } } - /* * Class representing a 'setting' object on the InvenTree server. * There are two sorts of settings available from the server, via the API: @@ -913,10 +898,10 @@ class InvenTreePlugin extends InvenTreeModel { * - UserSetting (applicable only to the current user) */ class InvenTreeGlobalSetting extends InvenTreeModel { - InvenTreeGlobalSetting() : super(); - InvenTreeGlobalSetting.fromJson(Map json) : super.fromJson(json); + InvenTreeGlobalSetting.fromJson(Map json) + : super.fromJson(json); @override InvenTreeGlobalSetting createFromJson(Map json) { @@ -927,18 +912,17 @@ class InvenTreeGlobalSetting extends InvenTreeModel { String get URL => "settings/global/"; String get key => getString("key"); - - String get value => getString("value"); - - String get type => getString("type"); + String get value => getString("value"); + + String get type => getString("type"); } class InvenTreeUserSetting extends InvenTreeGlobalSetting { - InvenTreeUserSetting() : super(); - InvenTreeUserSetting.fromJson(Map json) : super.fromJson(json); + InvenTreeUserSetting.fromJson(Map json) + : super.fromJson(json); @override InvenTreeGlobalSetting createFromJson(Map json) { @@ -949,22 +933,19 @@ class InvenTreeUserSetting extends InvenTreeGlobalSetting { String get URL => "settings/user/"; } - class InvenTreeAttachment extends InvenTreeModel { // Class representing an "attachment" file InvenTreeAttachment() : super(); - InvenTreeAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreeAttachment.fromJson(Map json) + : super.fromJson(json); @override String get URL => "attachment/"; @override Map> formFields() { - Map> fields = { - "link": {}, - "comment": {} - }; + Map> fields = {"link": {}, "comment": {}}; if (!hasLink) { fields.remove("link"); @@ -1004,13 +985,7 @@ class InvenTreeAttachment extends InvenTreeModel { } // Image formats - final List img_formats = [ - ".png", - ".jpg", - ".gif", - ".bmp", - ".svg", - ]; + final List img_formats = [".png", ".jpg", ".gif", ".bmp", ".svg"]; for (String fmt in img_formats) { if (fn.endsWith(fmt)) { @@ -1022,7 +997,7 @@ class InvenTreeAttachment extends InvenTreeModel { } String get comment => getString("comment"); - + DateTime? get uploadDate { if (jsondata.containsKey("upload_date")) { return DateTime.tryParse((jsondata["upload_date"] ?? "") as String); @@ -1033,7 +1008,6 @@ class InvenTreeAttachment extends InvenTreeModel { // Return a count of how many attachments exist against the specified model ID Future countAttachments(int modelId) { - Map filters = {}; if (InvenTreeAPI().supportsModernAttachments) { @@ -1046,8 +1020,12 @@ class InvenTreeAttachment extends InvenTreeModel { return count(filters: filters); } - Future uploadAttachment(File attachment, int modelId, {String comment = "", Map fields = const {}}) async { - + Future uploadAttachment( + File attachment, + int modelId, { + String comment = "", + Map fields = const {}, + }) async { // Ensure that the correct reference field is set Map data = Map.from(fields); @@ -1058,15 +1036,14 @@ class InvenTreeAttachment extends InvenTreeModel { } if (InvenTreeAPI().supportsModernAttachments) { - url = "attachment/"; data["model_id"] = modelId.toString(); data["model_type"] = REF_MODEL_TYPE; - } else { - if (REFERENCE_FIELD.isEmpty) { - sentryReportMessage("uploadAttachment called with empty 'REFERENCE_FIELD'"); + sentryReportMessage( + "uploadAttachment called with empty 'REFERENCE_FIELD'", + ); return false; } @@ -1074,24 +1051,21 @@ class InvenTreeAttachment extends InvenTreeModel { } final APIResponse response = await InvenTreeAPI().uploadFile( - url, - attachment, - method: "POST", - name: "attachment", - fields: data + url, + attachment, + method: "POST", + name: "attachment", + fields: data, ); return response.successful(); } - Future uploadImage(int modelId, {String prefix = "InvenTree"}) async { - bool result = false; await FilePickerDialog.pickImageFromCamera().then((File? file) { if (file != null) { - String dir = path.dirname(file.path); String ext = path.extension(file.path); String now = DateTime.now().toIso8601String().replaceAll(":", "-"); @@ -1104,8 +1078,9 @@ class InvenTreeAttachment extends InvenTreeModel { uploadAttachment(renamed, modelId).then((success) { result = success; showSnackIcon( - result ? L10().imageUploadSuccess : L10().imageUploadFailure, - success: result); + result ? L10().imageUploadSuccess : L10().imageUploadFailure, + success: result, + ); }); }); } catch (error, stackTrace) { @@ -1118,14 +1093,10 @@ class InvenTreeAttachment extends InvenTreeModel { return result; } - /* * Download this attachment file */ Future downloadAttachment() async { await InvenTreeAPI().downloadFile(attachment); } - } - - diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart index ae79fa2..eee2872 100644 --- a/lib/inventree/notification.dart +++ b/lib/inventree/notification.dart @@ -5,10 +5,10 @@ import "package:inventree/inventree/model.dart"; */ class InvenTreeNotification extends InvenTreeModel { - InvenTreeNotification() : super(); - InvenTreeNotification.fromJson(Map json) : super.fromJson(json); + InvenTreeNotification.fromJson(Map json) + : super.fromJson(json); @override InvenTreeNotification createFromJson(Map json) { @@ -20,15 +20,12 @@ class InvenTreeNotification extends InvenTreeModel { @override Map defaultListFilters() { - // By default, only return 'unread' notifications - return { - "read": "false", - }; + return {"read": "false"}; } String get message => getString("message"); - + DateTime? get creationDate { if (jsondata.containsKey("creation")) { return DateTime.tryParse((jsondata["creation"] ?? "") as String); @@ -41,7 +38,6 @@ class InvenTreeNotification extends InvenTreeModel { * Dismiss this notification (mark as read) */ Future dismiss() async { - if (api.apiVersion >= 82) { // "Modern" API endpoint operates a little differently await update(values: {"read": "true"}); @@ -49,5 +45,4 @@ class InvenTreeNotification extends InvenTreeModel { await api.post("${url}read/"); } } - -} \ No newline at end of file +} diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart index d06ddc8..a558092 100644 --- a/lib/inventree/orders.dart +++ b/lib/inventree/orders.dart @@ -2,16 +2,13 @@ * Base model for various "orders" which share common properties */ - import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; - /* * Generic class representing an "order" */ class InvenTreeOrder extends InvenTreeModel { - InvenTreeOrder() : super(); InvenTreeOrder.fromJson(Map json) : super.fromJson(json); @@ -34,7 +31,8 @@ class InvenTreeOrder extends InvenTreeModel { int get shipmentCount => getInt("shipments_count", backup: 0); - int get completedShipmentCount => getInt("completed_shipments_count", backup: 0); + int get completedShipmentCount => + getInt("completed_shipments_count", backup: 0); bool get complete => completedLineItemCount >= lineItemCount; @@ -46,14 +44,16 @@ class InvenTreeOrder extends InvenTreeModel { String get responsibleName => getString("name", subKey: "responsible_detail"); - String get responsibleLabel => getString("label", subKey: "responsible_detail"); + String get responsibleLabel => + getString("label", subKey: "responsible_detail"); // Project code information int get projectCodeId => getInt("project_code"); String get projectCode => getString("code", subKey: "project_code_detail"); - String get projectCodeDescription => getString("description", subKey: "project_code_detail"); + String get projectCodeDescription => + getString("description", subKey: "project_code_detail"); bool get hasProjectCode => projectCode.isNotEmpty; @@ -84,12 +84,10 @@ class InvenTreeOrder extends InvenTreeModel { } } - /* * Generic class representing an "order line" */ class InvenTreeOrderLine extends InvenTreeModel { - InvenTreeOrderLine() : super(); InvenTreeOrderLine.fromJson(Map json) : super.fromJson(json); @@ -121,15 +119,14 @@ class InvenTreeOrderLine extends InvenTreeModel { String get targetDate => getDateString("target_date"); } - /* * Generic class representing an "ExtraLineItem" */ class InvenTreeExtraLineItem extends InvenTreeModel { - InvenTreeExtraLineItem() : super(); - InvenTreeExtraLineItem.fromJson(Map json) : super.fromJson(json); + InvenTreeExtraLineItem.fromJson(Map json) + : super.fromJson(json); int get orderId => getInt("order"); @@ -157,5 +154,4 @@ class InvenTreeExtraLineItem extends InvenTreeModel { "notes": {}, }; } - -} \ No newline at end of file +} diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 0aeec56..c0050ec 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -14,15 +14,14 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/part/part_detail.dart"; - /* * Class representing the PartCategory database model */ class InvenTreePartCategory extends InvenTreeModel { - InvenTreePartCategory() : super(); - InvenTreePartCategory.fromJson(Map json) : super.fromJson(json); + InvenTreePartCategory.fromJson(Map json) + : super.fromJson(json); @override String get URL => "part/category/"; @@ -37,16 +36,13 @@ class InvenTreePartCategory extends InvenTreeModel { Future goToDetailPage(BuildContext context) async { // Default implementation does not do anything... return Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(this) - ) + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(this)), ); } @override Map> formFields() { - Map> fields = { "name": {}, "description": {}, @@ -58,9 +54,8 @@ class InvenTreePartCategory extends InvenTreeModel { } String get pathstring => getString("pathstring"); - - String get parentPathString { + String get parentPathString { List psplit = pathstring.split("/"); if (psplit.isNotEmpty) { @@ -78,21 +73,22 @@ class InvenTreePartCategory extends InvenTreeModel { // Return the number of parts in this category // Note that the API changed from 'parts' to 'part_count' (v69) - int get partcount => (jsondata["part_count"] ?? jsondata["parts"] ?? 0) as int; + int get partcount => + (jsondata["part_count"] ?? jsondata["parts"] ?? 0) as int; @override - InvenTreeModel createFromJson(Map json) => InvenTreePartCategory.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePartCategory.fromJson(json); } - /* * Class representing the PartTestTemplate database model */ class InvenTreePartTestTemplate extends InvenTreeModel { - InvenTreePartTestTemplate() : super(); - InvenTreePartTestTemplate.fromJson(Map json) : super.fromJson(json); + InvenTreePartTestTemplate.fromJson(Map json) + : super.fromJson(json); @override String get URL => "part/test-template/"; @@ -104,16 +100,16 @@ class InvenTreePartTestTemplate extends InvenTreeModel { String get testName => getString("test_name"); bool get required => getBool("required"); - + bool get requiresValue => getBool("requires_value"); bool get requiresAttachment => getBool("requires_attachment"); @override - InvenTreeModel createFromJson(Map json) => InvenTreePartTestTemplate.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePartTestTemplate.fromJson(json); bool passFailStatus() { - var result = latestResult(); if (result == null) { @@ -134,17 +130,16 @@ class InvenTreePartTestTemplate extends InvenTreeModel { return results.last; } - } /* Class representing the PartParameter database model */ class InvenTreePartParameter extends InvenTreeModel { - InvenTreePartParameter() : super(); - InvenTreePartParameter.fromJson(Map json) : super.fromJson(json); + InvenTreePartParameter.fromJson(Map json) + : super.fromJson(json); @override String get URL => "part/parameter/"; @@ -153,11 +148,11 @@ class InvenTreePartParameter extends InvenTreeModel { List get rolesRequired => ["part"]; @override - InvenTreeModel createFromJson(Map json) => InvenTreePartParameter.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePartParameter.fromJson(json); @override Map> formFields() { - Map> fields = { "header": { "type": "string", @@ -166,9 +161,7 @@ class InvenTreePartParameter extends InvenTreeModel { "help_text": description, "value": "", }, - "data": { - "type": "string", - } + "data": {"type": "string"}, }; return fields; @@ -179,9 +172,9 @@ class InvenTreePartParameter extends InvenTreeModel { @override String get description => getString("description", subKey: "template_detail"); - + String get value => getString("data"); - + String get valueString { String v = value; @@ -196,15 +189,15 @@ class InvenTreePartParameter extends InvenTreeModel { bool get as_bool => value.toLowerCase() == "true"; String get units => getString("units", subKey: "template_detail"); - - bool get is_checkbox => getBool("checkbox", subKey: "template_detail", backup: false); + + bool get is_checkbox => + getBool("checkbox", subKey: "template_detail", backup: false); } /* * Class representing the Part database model */ class InvenTreePart extends InvenTreeModel { - InvenTreePart() : super(); InvenTreePart.fromJson(Map json) : super.fromJson(json); @@ -222,10 +215,8 @@ class InvenTreePart extends InvenTreeModel { Future goToDetailPage(BuildContext context) async { // Default implementation does not do anything... return Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartDetailWidget(this) - ) + context, + MaterialPageRoute(builder: (context) => PartDetailWidget(this)), ); } @@ -259,9 +250,7 @@ class InvenTreePart extends InvenTreeModel { @override Map defaultFilters() { - return { - "category_detail": "true", - }; + return {"category_detail": "true"}; } // Cached list of stock items @@ -270,27 +259,25 @@ class InvenTreePart extends InvenTreeModel { int get stockItemCount => stockItems.length; // Request stock items for this part - Future getStockItems(BuildContext context, {bool showDialog=false}) async { + Future getStockItems( + BuildContext context, { + bool showDialog = false, + }) async { + await InvenTreeStockItem() + .list(filters: {"part": "${pk}", "in_stock": "true"}) + .then((var items) { + stockItems.clear(); - await InvenTreeStockItem().list( - filters: { - "part": "${pk}", - "in_stock": "true", - }, - ).then((var items) { - stockItems.clear(); - - for (var item in items) { - if (item is InvenTreeStockItem) { - stockItems.add(item); - } - } - }); + for (var item in items) { + if (item is InvenTreeStockItem) { + stockItems.add(item); + } + } + }); } // Request pricing data for this part Future getPricing() async { - print("REQUEST PRICING FOR: ${pk}"); try { @@ -311,15 +298,13 @@ class InvenTreePart extends InvenTreeModel { } int get supplierCount => getInt("suppliers", backup: 0); - + // Request supplier parts for this part Future> getSupplierParts() async { List _supplierParts = []; final parts = await InvenTreeSupplierPart().list( - filters: { - "part": "${pk}", - } + filters: {"part": "${pk}"}, ); for (var result in parts) { @@ -338,13 +323,9 @@ class InvenTreePart extends InvenTreeModel { // Request test templates from the serve Future getTestTemplates() async { - - InvenTreePartTestTemplate().list( - filters: { - "part": "${pk}", - }, - ).then((var templates) { - + InvenTreePartTestTemplate().list(filters: {"part": "${pk}"}).then(( + var templates, + ) { testingTemplates.clear(); for (var t in templates) { @@ -373,12 +354,12 @@ class InvenTreePart extends InvenTreeModel { // Get the 'available stock' for this Part double get unallocatedStock { - double unallocated = 0; // Note that the 'available_stock' was not added until API v35 if (jsondata.containsKey("unallocated_stock")) { - unallocated = double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; + unallocated = + double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; } else { unallocated = inStock; } @@ -386,148 +367,150 @@ class InvenTreePart extends InvenTreeModel { return max(0, unallocated); } - String get unallocatedStockString => simpleNumberString(unallocatedStock); + String get unallocatedStockString => simpleNumberString(unallocatedStock); - String stockString({bool includeUnits = true}) { - String q = unallocatedStockString; + String stockString({bool includeUnits = true}) { + String q = unallocatedStockString; - if (unallocatedStock != inStock) { - q += " / ${inStockString}"; - } - - if (includeUnits && units.isNotEmpty) { - q += " ${units}"; - } - - return q; + if (unallocatedStock != inStock) { + q += " / ${inStockString}"; } - String get units => getString("units"); - - // Get the ID of the Part that this part is a variant of (or null) - int? get variantOf => jsondata["variant_of"] as int?; - - // Get the number of units being build for this Part - double get building => getDouble("building"); - - // Get the number of BOMs this Part is used in (if it is a component) - int get usedInCount => jsondata.containsKey("used_in") ? getInt("used_in", backup: 0) : 0; - - bool get isAssembly => getBool("assembly"); - - bool get isComponent => getBool("component"); - - bool get isPurchaseable => getBool("purchaseable"); - - bool get isSalable => getBool("salable"); - - bool get isActive => getBool("active"); - - bool get isVirtual => getBool("virtual"); - - bool get isTemplate => getBool("is_template"); - - bool get isTrackable => getBool("trackable"); - - // Get the IPN (internal part number) for the Part instance - String get IPN => getString("IPN"); - - // Get the revision string for the Part instance - String get revision => getString("revision"); - - // Get the category ID for the Part instance (or "null" if does not exist) - int get categoryId => getInt("category"); - - // Get the category name for the Part instance - String get categoryName { - // Inavlid category ID - if (categoryId <= 0) return ""; - - if (!jsondata.containsKey("category_detail")) return ""; - - return (jsondata["category_detail"]?["name"] ?? "") as String; + if (includeUnits && units.isNotEmpty) { + q += " ${units}"; } - // Get the category description for the Part instance - String get categoryDescription { - // Invalid category ID - if (categoryId <= 0) return ""; + return q; + } - if (!jsondata.containsKey("category_detail")) return ""; + String get units => getString("units"); - return (jsondata["category_detail"]?["description"] ?? "") as String; - } - // Get the image URL for the Part instance - String get _image => getString("image"); + // Get the ID of the Part that this part is a variant of (or null) + int? get variantOf => jsondata["variant_of"] as int?; - // Get the thumbnail URL for the Part instance - String get _thumbnail => getString("thumbnail"); + // Get the number of units being build for this Part + double get building => getDouble("building"); - // Return the fully-qualified name for the Part instance - String get fullname { + // Get the number of BOMs this Part is used in (if it is a component) + int get usedInCount => + jsondata.containsKey("used_in") ? getInt("used_in", backup: 0) : 0; - String fn = getString("full_name"); + bool get isAssembly => getBool("assembly"); - if (fn.isNotEmpty) return fn; + bool get isComponent => getBool("component"); - List elements = []; + bool get isPurchaseable => getBool("purchaseable"); - if (IPN.isNotEmpty) elements.add(IPN); + bool get isSalable => getBool("salable"); - elements.add(name); + bool get isActive => getBool("active"); - if (revision.isNotEmpty) elements.add(revision); + bool get isVirtual => getBool("virtual"); - return elements.join(" | "); - } + bool get isTemplate => getBool("is_template"); - // Return a path to the image for this Part - String get image { - // Use thumbnail as a backup - String img = _image.isNotEmpty ? _image : _thumbnail; + bool get isTrackable => getBool("trackable"); - return img.isNotEmpty ? img : InvenTreeAPI.staticImage; - } + // Get the IPN (internal part number) for the Part instance + String get IPN => getString("IPN"); - // Return a path to the thumbnail for this part - String get thumbnail { - // Use image as a backup - String img = _thumbnail.isNotEmpty ? _thumbnail : _image; + // Get the revision string for the Part instance + String get revision => getString("revision"); - return img.isNotEmpty ? img : InvenTreeAPI.staticThumb; - } + // Get the category ID for the Part instance (or "null" if does not exist) + int get categoryId => getInt("category"); - Future uploadImage(File image) async { - // Upload file against this part - final APIResponse response = await InvenTreeAPI().uploadFile( - url, - image, - method: "PATCH", - name: "image", - ); + // Get the category name for the Part instance + String get categoryName { + // Inavlid category ID + if (categoryId <= 0) return ""; - return response.successful(); - } + if (!jsondata.containsKey("category_detail")) return ""; - // Return the "starred" status of this part - bool get starred => getBool("starred"); + return (jsondata["category_detail"]?["name"] ?? "") as String; + } + + // Get the category description for the Part instance + String get categoryDescription { + // Invalid category ID + if (categoryId <= 0) return ""; + + if (!jsondata.containsKey("category_detail")) return ""; + + return (jsondata["category_detail"]?["description"] ?? "") as String; + } + + // Get the image URL for the Part instance + String get _image => getString("image"); + + // Get the thumbnail URL for the Part instance + String get _thumbnail => getString("thumbnail"); + + // Return the fully-qualified name for the Part instance + String get fullname { + String fn = getString("full_name"); + + if (fn.isNotEmpty) return fn; + + List elements = []; + + if (IPN.isNotEmpty) elements.add(IPN); + + elements.add(name); + + if (revision.isNotEmpty) elements.add(revision); + + return elements.join(" | "); + } + + // Return a path to the image for this Part + String get image { + // Use thumbnail as a backup + String img = _image.isNotEmpty ? _image : _thumbnail; + + return img.isNotEmpty ? img : InvenTreeAPI.staticImage; + } + + // Return a path to the thumbnail for this part + String get thumbnail { + // Use image as a backup + String img = _thumbnail.isNotEmpty ? _thumbnail : _image; + + return img.isNotEmpty ? img : InvenTreeAPI.staticThumb; + } + + Future uploadImage(File image) async { + // Upload file against this part + final APIResponse response = await InvenTreeAPI().uploadFile( + url, + image, + method: "PATCH", + name: "image", + ); + + return response.successful(); + } + + // Return the "starred" status of this part + bool get starred => getBool("starred"); @override - InvenTreeModel createFromJson(Map json) => InvenTreePart.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePart.fromJson(json); } - class InvenTreePartPricing extends InvenTreeModel { - InvenTreePartPricing() : super(); - InvenTreePartPricing.fromJson(Map json) : super.fromJson(json); + InvenTreePartPricing.fromJson(Map json) + : super.fromJson(json); @override List get rolesRequired => ["part"]; @override - InvenTreeModel createFromJson(Map json) => InvenTreePartPricing.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePartPricing.fromJson(json); // Price data accessors String get currency => getString("currency", backup: "USD"); @@ -538,8 +521,10 @@ class InvenTreePartPricing extends InvenTreeModel { double? get overrideMin => getDoubleOrNull("override_min"); double? get overrideMax => getDoubleOrNull("override_max"); - String get overrideMinCurrency => getString("override_min_currency", backup: currency); - String get overrideMaxCurrency => getString("override_max_currency", backup: currency); + String get overrideMinCurrency => + getString("override_min_currency", backup: currency); + String get overrideMaxCurrency => + getString("override_max_currency", backup: currency); double? get bomCostMin => getDoubleOrNull("bom_cost_min"); double? get bomCostMax => getDoubleOrNull("bom_cost_max"); @@ -563,15 +548,14 @@ class InvenTreePartPricing extends InvenTreeModel { double? get saleHistoryMax => getDoubleOrNull("sale_history_max"); } - /* * Class representing an attachment file against a Part object */ class InvenTreePartAttachment extends InvenTreeAttachment { - InvenTreePartAttachment() : super(); - InvenTreePartAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreePartAttachment.fromJson(Map json) + : super.fromJson(json); @override String get REFERENCE_FIELD => "part"; @@ -580,9 +564,11 @@ class InvenTreePartAttachment extends InvenTreeAttachment { String get REF_MODEL_TYPE => "part"; @override - String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "part/attachment/"; + String get URL => InvenTreeAPI().supportsModernAttachments + ? "attachment/" + : "part/attachment/"; @override - InvenTreeModel createFromJson(Map json) => InvenTreePartAttachment.fromJson(json); - + InvenTreeModel createFromJson(Map json) => + InvenTreePartAttachment.fromJson(json); } diff --git a/lib/inventree/project_code.dart b/lib/inventree/project_code.dart index e5d4528..3d8793b 100644 --- a/lib/inventree/project_code.dart +++ b/lib/inventree/project_code.dart @@ -1,17 +1,17 @@ import "package:inventree/inventree/model.dart"; - /* * Class representing the ProjectCode database model */ class InvenTreeProjectCode extends InvenTreeModel { - InvenTreeProjectCode() : super(); - InvenTreeProjectCode.fromJson(Map json) : super.fromJson(json); + InvenTreeProjectCode.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeProjectCode.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeProjectCode.fromJson(json); @override String get URL => "project-code/"; @@ -20,10 +20,7 @@ class InvenTreeProjectCode extends InvenTreeModel { @override Map> formFields() { - return { - "code": {}, - "description": {}, - }; + return {"code": {}, "description": {}}; } String get code => getString("code"); diff --git a/lib/inventree/purchase_order.dart b/lib/inventree/purchase_order.dart index 1b8bc7c..59874dc 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -12,18 +12,18 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; - /* * Class representing an individual PurchaseOrder instance */ class InvenTreePurchaseOrder extends InvenTreeOrder { - InvenTreePurchaseOrder() : super(); - InvenTreePurchaseOrder.fromJson(Map json) : super.fromJson(json); + InvenTreePurchaseOrder.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrder.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePurchaseOrder.fromJson(json); @override String get URL => "order/po/"; @@ -31,10 +31,8 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { @override Future goToDetailPage(BuildContext context) async { return Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PurchaseOrderDetailWidget(this) - ) + context, + MaterialPageRoute(builder: (context) => PurchaseOrderDetailWidget(this)), ); } @@ -50,9 +48,7 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { Map> fields = { "reference": {}, "supplier": { - "filters": { - "is_supplier": true, - }, + "filters": {"is_supplier": true}, }, "supplier_reference": {}, "description": {}, @@ -63,9 +59,7 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { "link": {}, "responsible": {}, "contact": { - "filters": { - "company": supplierId, - } + "filters": {"company": supplierId}, }, }; @@ -82,20 +76,16 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { } return fields; - } @override Map defaultFilters() { - return { - "supplier_detail": "true", - }; + return {"supplier_detail": "true"}; } int get supplierId => getInt("supplier"); InvenTreeCompany? get supplier { - dynamic supplier_detail = jsondata["supplier_detail"]; if (supplier_detail == null) { @@ -109,20 +99,26 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { int get destinationId => getInt("destination"); - bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED", "ON_HOLD"]); + bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, [ + "PENDING", + "PLACED", + "ON_HOLD", + ]); - bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); + bool get isPending => + api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); bool get isPlaced => api.PurchaseOrderStatus.isNameIn(status, ["PLACED"]); - bool get isFailed => api.PurchaseOrderStatus.isNameIn(status, ["CANCELLED", "LOST", "RETURNED"]); + bool get isFailed => api.PurchaseOrderStatus.isNameIn(status, [ + "CANCELLED", + "LOST", + "RETURNED", + ]); Future> getLineItems() async { - final results = await InvenTreePOLineItem().list( - filters: { - "order": "${pk}", - } + filters: {"order": "${pk}"}, ); List items = []; @@ -161,13 +157,14 @@ class InvenTreePurchaseOrder extends InvenTreeOrder { } class InvenTreePOLineItem extends InvenTreeOrderLine { - InvenTreePOLineItem() : super(); - InvenTreePOLineItem.fromJson(Map json) : super.fromJson(json); + InvenTreePOLineItem.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreePOLineItem.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePOLineItem.fromJson(json); @override String get URL => "order/po-line/"; @@ -198,10 +195,7 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { @override Map defaultFilters() { - return { - "part_detail": "true", - "order_detail": "true", - }; + return {"part_detail": "true", "order_detail": "true"}; } double get received => getDouble("received"); @@ -216,14 +210,14 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { return received / quantity; } - String get progressString => simpleNumberString(received) + " / " + simpleNumberString(quantity); + String get progressString => + simpleNumberString(received) + " / " + simpleNumberString(quantity); double get outstanding => quantity - received; int get supplierPartId => getInt("part"); InvenTreeSupplierPart? get supplierPart { - dynamic detail = jsondata["supplier_part_detail"]; if (detail == null) { @@ -246,7 +240,7 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { String get SKU => getString("SKU", subKey: "supplier_part_detail"); double get purchasePrice => getDouble("purchase_price"); - + String get purchasePriceCurrency => getString("purchase_price_currency"); int get destinationId => getInt("destination"); @@ -256,7 +250,13 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { Map get destinationDetail => getMap("destination_detail"); // Receive this line item into stock - Future receive(BuildContext context, {int? destination, double? quantity, String? barcode, Function? onSuccess}) async { + Future receive( + BuildContext context, { + int? destination, + double? quantity, + String? barcode, + Function? onSuccess, + }) async { // Infer the destination location from the line item if not provided if (destinationId > 0) { destination = destinationId; @@ -274,20 +274,10 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { "hidden": true, "value": pk, }, - "quantity": { - "parent": "items", - "nested": true, - "value": quantity, - }, + "quantity": {"parent": "items", "nested": true, "value": quantity}, "location": {}, - "status": { - "parent": "items", - "nested": true, - }, - "batch_code": { - "parent": "items", - "nested": true, - }, + "status": {"parent": "items", "nested": true}, + "batch_code": {"parent": "items", "nested": true}, "barcode": { "parent": "items", "nested": true, @@ -295,7 +285,7 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { "label": L10().barcodeAssign, "value": barcode, "required": false, - } + }, }; if (destination != null && destination > 0) { @@ -306,31 +296,31 @@ class InvenTreePOLineItem extends InvenTreeOrderLine { if (order != null) { await launchApiForm( - context, - L10().receiveItem, - order.receive_url, - fields, - method: "POST", - icon: TablerIcons.transition_right, - onSuccess: (data) { - if (onSuccess != null) { - onSuccess(); - } + context, + L10().receiveItem, + order.receive_url, + fields, + method: "POST", + icon: TablerIcons.transition_right, + onSuccess: (data) { + if (onSuccess != null) { + onSuccess(); } + }, ); } } } - class InvenTreePOExtraLineItem extends InvenTreeExtraLineItem { - InvenTreePOExtraLineItem() : super(); - InvenTreePOExtraLineItem.fromJson(Map json) : super.fromJson(json); + InvenTreePOExtraLineItem.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreePOExtraLineItem.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreePOExtraLineItem.fromJson(json); @override String get URL => "order/po-extra-line/"; @@ -342,23 +332,19 @@ class InvenTreePOExtraLineItem extends InvenTreeExtraLineItem { Future goToDetailPage(BuildContext context) async { return Navigator.push( context, - MaterialPageRoute( - builder: (context) => ExtraLineDetailWidget(this) - ) + MaterialPageRoute(builder: (context) => ExtraLineDetailWidget(this)), ); } - } - /* * Class representing an attachment file against a PurchaseOrder object */ class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { - InvenTreePurchaseOrderAttachment() : super(); - InvenTreePurchaseOrderAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreePurchaseOrderAttachment.fromJson(Map json) + : super.fromJson(json); @override String get REFERENCE_FIELD => "order"; @@ -367,9 +353,11 @@ class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment { String get REF_MODEL_TYPE => "purchaseorder"; @override - String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "order/po/attachment/"; + String get URL => InvenTreeAPI().supportsModernAttachments + ? "attachment/" + : "order/po/attachment/"; @override - InvenTreeModel createFromJson(Map json) => InvenTreePurchaseOrderAttachment.fromJson(json); - + InvenTreeModel createFromJson(Map json) => + InvenTreePurchaseOrderAttachment.fromJson(json); } diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart index babf2a2..51412db 100644 --- a/lib/inventree/sales_order.dart +++ b/lib/inventree/sales_order.dart @@ -1,5 +1,3 @@ - - import "package:flutter/material.dart"; import "package:inventree/api.dart"; import "package:inventree/helpers.dart"; @@ -11,18 +9,18 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/widget/order/extra_line_detail.dart"; import "package:inventree/widget/order/sales_order_detail.dart"; - /* * Class representing an individual SalesOrder */ class InvenTreeSalesOrder extends InvenTreeOrder { - InvenTreeSalesOrder() : super(); - InvenTreeSalesOrder.fromJson(Map json) : super.fromJson(json); + InvenTreeSalesOrder.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrder.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSalesOrder.fromJson(json); @override String get URL => "order/so/"; @@ -38,9 +36,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { Future goToDetailPage(BuildContext context) async { return Navigator.push( context, - MaterialPageRoute( - builder: (context) => SalesOrderDetailWidget(this) - ) + MaterialPageRoute(builder: (context) => SalesOrderDetailWidget(this)), ); } @@ -49,9 +45,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { Map> fields = { "reference": {}, "customer": { - "filters": { - "is_customer": true, - } + "filters": {"is_customer": true}, }, "customer_reference": {}, "description": {}, @@ -61,10 +55,8 @@ class InvenTreeSalesOrder extends InvenTreeOrder { "link": {}, "responsible": {}, "contact": { - "filters": { - "company": customerId, - } - } + "filters": {"company": customerId}, + }, }; if (!InvenTreeAPI().supportsProjectCodes) { @@ -84,9 +76,7 @@ class InvenTreeSalesOrder extends InvenTreeOrder { @override Map defaultFilters() { - return { - "customer_detail": "true", - }; + return {"customer_detail": "true"}; } Future issueOrder() async { @@ -124,28 +114,33 @@ class InvenTreeSalesOrder extends InvenTreeOrder { String get customerReference => getString("customer_reference"); - bool get isOpen => api.SalesOrderStatus.isNameIn(status, ["PENDING", "IN_PROGRESS", "ON_HOLD"]); + bool get isOpen => api.SalesOrderStatus.isNameIn(status, [ + "PENDING", + "IN_PROGRESS", + "ON_HOLD", + ]); - bool get isPending => api.SalesOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); + bool get isPending => + api.SalesOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); - bool get isInProgress => api.SalesOrderStatus.isNameIn(status, ["IN_PROGRESS"]); + bool get isInProgress => + api.SalesOrderStatus.isNameIn(status, ["IN_PROGRESS"]); bool get isComplete => api.SalesOrderStatus.isNameIn(status, ["SHIPPED"]); - } - /* * Class representing an individual line item in a SalesOrder */ class InvenTreeSOLineItem extends InvenTreeOrderLine { - InvenTreeSOLineItem() : super(); - InvenTreeSOLineItem.fromJson(Map json) : super.fromJson(json); + InvenTreeSOLineItem.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeSOLineItem.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSOLineItem.fromJson(json); @override String get URL => "order/so-line/"; @@ -156,13 +151,9 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { @override Map> formFields() { return { - "order": { - "hidden": true, - }, + "order": {"hidden": true}, "part": { - "filters": { - "salable": true, - } + "filters": {"salable": true}, }, "quantity": {}, "reference": {}, @@ -172,33 +163,17 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { } Map> allocateFormFields() { - return { - "line_item": { - "parent": "items", - "nested": true, - "hidden": true, - }, - "stock_item": { - "parent": "items", - "nested": true, - "filters": {}, - }, - "quantity": { - "parent": "items", - "nested": true, - }, - "shipment": { - "filters": {} - } + "line_item": {"parent": "items", "nested": true, "hidden": true}, + "stock_item": {"parent": "items", "nested": true, "filters": {}}, + "quantity": {"parent": "items", "nested": true}, + "shipment": {"filters": {}}, }; } @override Map defaultFilters() { - return { - "part_detail": "true", - }; + return {"part_detail": "true"}; } double get allocated => getDouble("allocated"); @@ -223,7 +198,8 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { return unallocated; } - String get allocatedString => simpleNumberString(allocated) + " / " + simpleNumberString(quantity); + String get allocatedString => + simpleNumberString(allocated) + " / " + simpleNumberString(quantity); double get shipped => getDouble("shipped"); @@ -239,26 +215,28 @@ class InvenTreeSOLineItem extends InvenTreeOrderLine { return shipped / quantity; } - String get progressString => simpleNumberString(shipped) + " / " + simpleNumberString(quantity); + String get progressString => + simpleNumberString(shipped) + " / " + simpleNumberString(quantity); bool get isComplete => shipped >= quantity; - double get available => getDouble("available_stock") + getDouble("available_variant_stock"); + double get available => + getDouble("available_stock") + getDouble("available_variant_stock"); double get salePrice => getDouble("sale_price"); String get salePriceCurrency => getString("sale_price_currency"); - } - class InvenTreeSOExtraLineItem extends InvenTreeExtraLineItem { InvenTreeSOExtraLineItem() : super(); - InvenTreeSOExtraLineItem.fromJson(Map json) : super.fromJson(json); + InvenTreeSOExtraLineItem.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeSOExtraLineItem.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSOExtraLineItem.fromJson(json); @override String get URL => "order/so-extra-line/"; @@ -269,10 +247,8 @@ class InvenTreeSOExtraLineItem extends InvenTreeExtraLineItem { @override Future goToDetailPage(BuildContext context) async { return Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ExtraLineDetailWidget(this) - ) + context, + MaterialPageRoute(builder: (context) => ExtraLineDetailWidget(this)), ); } } @@ -281,13 +257,14 @@ class InvenTreeSOExtraLineItem extends InvenTreeExtraLineItem { * Class representing a sales order shipment */ class InvenTreeSalesOrderShipment extends InvenTreeModel { - InvenTreeSalesOrderShipment() : super(); - InvenTreeSalesOrderShipment.fromJson(Map json) : super.fromJson(json); + InvenTreeSalesOrderShipment.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrderShipment.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSalesOrderShipment.fromJson(json); @override String get URL => "/order/so/shipment/"; @@ -318,19 +295,18 @@ class InvenTreeSalesOrderShipment extends InvenTreeModel { bool get shipped => shipment_date != null && shipment_date!.isNotEmpty; } - - /* * Class representing an attachment file against a SalesOrder object */ class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { - InvenTreeSalesOrderAttachment() : super(); - InvenTreeSalesOrderAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreeSalesOrderAttachment.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeSalesOrderAttachment.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeSalesOrderAttachment.fromJson(json); @override String get REFERENCE_FIELD => "order"; @@ -339,6 +315,7 @@ class InvenTreeSalesOrderAttachment extends InvenTreeAttachment { String get REF_MODEL_TYPE => "salesorder"; @override - String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "order/so/attachment/"; - + String get URL => InvenTreeAPI().supportsModernAttachments + ? "attachment/" + : "order/so/attachment/"; } diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index a052ed5..132974a 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -11,7 +11,6 @@ import "package:inventree/dsn.dart"; import "package:inventree/preferences.dart"; Future> getDeviceInfo() async { - // Extract device information final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); @@ -31,7 +30,6 @@ Future> getDeviceInfo() async { "identifierForVendor": iosDeviceInfo.identifierForVendor, "isPhysicalDevice": iosDeviceInfo.isPhysicalDevice, }; - } else if (Platform.isAndroid) { final androidDeviceInfo = await deviceInfo.androidInfo; @@ -57,13 +55,11 @@ Future> getDeviceInfo() async { return device_info; } - Map getServerInfo() => { "version": InvenTreeAPI().serverVersion, "apiVersion": InvenTreeAPI().apiVersion, }; - Future> getAppInfo() async { // Add app info final package_info = await PackageInfo.fromPlatform(); @@ -76,7 +72,6 @@ Future> getAppInfo() async { }; } - bool isInDebugMode() { bool inDebugMode = false; @@ -85,8 +80,10 @@ bool isInDebugMode() { return inDebugMode; } -Future sentryReportMessage(String message, {Map? context}) async { - +Future sentryReportMessage( + String message, { + Map? context, +}) async { if (SENTRY_DSN_KEY.isEmpty) { return false; } @@ -106,23 +103,22 @@ Future sentryReportMessage(String message, {Map? context}) // We don't care about the server address, only the path and query parameters! // Overwrite the provided URL context["url"] = uri.path + "?" + uri.query; - } catch (error) { // Ignore if any errors are thrown here } - } } print("Sending user message to Sentry: ${message}, ${context}"); if (isInDebugMode()) { - print("----- In dev mode. Not sending message to Sentry.io -----"); return true; } - final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; + final upload = + await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) + as bool; if (!upload) { print("----- Error reporting disabled -----"); @@ -152,12 +148,15 @@ Future sentryReportMessage(String message, {Map? context}) } } - /* * Report an error message to sentry.io */ -Future sentryReportError(String source, dynamic error, StackTrace? stackTrace, {Map context = const {}}) async { - +Future sentryReportError( + String source, + dynamic error, + StackTrace? stackTrace, { + Map context = const {}, +}) async { if (sentryIgnoreError(error)) { // No action on this error return; @@ -170,7 +169,6 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr // check if you are running in dev mode using an assertion and omit sending // the report. if (isInDebugMode()) { - print("----- In dev mode. Not sending report to Sentry.io -----"); return; } @@ -179,7 +177,9 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr return; } - final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; + final upload = + await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) + as bool; if (!upload) { print("----- Error reporting disabled -----"); @@ -188,11 +188,12 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr // Some errors are outside our control, and we do not want to "pollute" the uploaded data if (source == "FlutterError.onError") { - String errorString = error.toString(); // Missing media file - if (errorString.contains("HttpException") && errorString.contains("404") && errorString.contains("/media/")) { + if (errorString.contains("HttpException") && + errorString.contains("404") && + errorString.contains("/media/")) { return; } @@ -225,26 +226,28 @@ Future sentryReportError(String source, dynamic error, StackTrace? stackTr scope.setContexts("context", context); }); - Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { - print("Error uploading information to Sentry.io:"); - print(error); - return SentryId.empty(); - }).then((response) { - print("Uploaded information to Sentry.io : ${response.toString()}"); - }); + Sentry.captureException(error, stackTrace: stackTrace) + .catchError((error) { + print("Error uploading information to Sentry.io:"); + print(error); + return SentryId.empty(); + }) + .then((response) { + print("Uploaded information to Sentry.io : ${response.toString()}"); + }); } - /* * Test if a certain error should be ignored by Sentry */ bool sentryIgnoreError(dynamic error) { // Ignore 404 errors for media files if (error is HttpException) { - if (error.uri.toString().contains("/media/") && error.message.contains("404")) { + if (error.uri.toString().contains("/media/") && + error.message.contains("404")) { return true; } } return false; -} \ No newline at end of file +} diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart index 9b75280..0058fc8 100644 --- a/lib/inventree/status_codes.dart +++ b/lib/inventree/status_codes.dart @@ -11,12 +11,10 @@ import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/helpers.dart"; - /* * Base class definition for a "status code" definition. */ class InvenTreeStatusCode { - InvenTreeStatusCode(this.URL); final String URL; @@ -34,10 +32,7 @@ class InvenTreeStatusCode { dynamic _entry = data[key]; if (_entry is Map) { - _choices.add({ - "value": _entry["key"], - "display_name": _entry["label"] - }); + _choices.add({"value": _entry["key"], "display_name": _entry["label"]}); } } @@ -46,7 +41,6 @@ class InvenTreeStatusCode { // Load status code information from the server Future load({bool forceReload = false}) async { - // Return internally cached data if (data.isNotEmpty && !forceReload) { return; diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 96b2a2f..1a45e73 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -10,16 +10,14 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/stock/location_display.dart"; import "package:inventree/widget/stock/stock_detail.dart"; - - /* * Class representing a test result for a single stock item */ class InvenTreeStockItemTestResult extends InvenTreeModel { - InvenTreeStockItemTestResult() : super(); - InvenTreeStockItemTestResult.fromJson(Map json) : super.fromJson(json); + InvenTreeStockItemTestResult.fromJson(Map json) + : super.fromJson(json); @override String get URL => "stock/test/"; @@ -29,22 +27,16 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { @override Map defaultFilters() { - return { - "user_detail": "true", - "template_detail": "true", - }; + return {"user_detail": "true", "template_detail": "true"}; } @override Map> formFields() { - Map> fields = { "stock_item": {"hidden": true}, "test": {}, "template": { - "filters": { - "enabled": "true", - } + "filters": {"enabled": "true"}, }, "result": {}, "value": {}, @@ -68,44 +60,39 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { String get testName => getString("test"); bool get result => getBool("result"); - + String get value => getString("value"); - + String get attachment => getString("attachment"); String get username => getString("username", subKey: "user_detail"); String get date => getString("date"); - + @override InvenTreeStockItemTestResult createFromJson(Map json) { var result = InvenTreeStockItemTestResult.fromJson(json); return result; } - } - class InvenTreeStockItemHistory extends InvenTreeModel { - InvenTreeStockItemHistory() : super(); - InvenTreeStockItemHistory.fromJson(Map json) : super.fromJson(json); + InvenTreeStockItemHistory.fromJson(Map json) + : super.fromJson(json); @override - InvenTreeModel createFromJson(Map json) => InvenTreeStockItemHistory.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeStockItemHistory.fromJson(json); @override String get URL => "stock/track/"; @override Map defaultFilters() { - // By default, order by decreasing date - return { - "ordering": "-date", - "user_detail": "true", - }; + return {"ordering": "-date", "user_detail": "true"}; } DateTime? get date => getDate("date"); @@ -113,7 +100,7 @@ class InvenTreeStockItemHistory extends InvenTreeModel { String get dateString => getDateString("date"); String get label => getString("label"); - + // Return the "deltas" associated with this historical object Map get deltas => getMap("deltas"); @@ -133,7 +120,6 @@ class InvenTreeStockItemHistory extends InvenTreeModel { int? get user => getValue("user") as int?; String get userString { - if (user != null) { return getString("username", subKey: "user_detail"); } else { @@ -142,12 +128,10 @@ class InvenTreeStockItemHistory extends InvenTreeModel { } } - /* * Class representing a StockItem database instance */ class InvenTreeStockItem extends InvenTreeModel { - InvenTreeStockItem() : super(); InvenTreeStockItem.fromJson(Map json) : super.fromJson(json); @@ -164,39 +148,18 @@ class InvenTreeStockItem extends InvenTreeModel { Future goToDetailPage(BuildContext context) async { return Navigator.push( context, - MaterialPageRoute( - builder: (context) => StockDetailWidget(this) - ) + MaterialPageRoute(builder: (context) => StockDetailWidget(this)), ); } // Return a set of fields to transfer this stock item via dialog Map transferFields() { Map fields = { - "pk": { - "parent": "items", - "nested": true, - "hidden": true, - "value": pk, - }, - "quantity": { - "parent": "items", - "nested": true, - "value": quantity, - }, - "location": { - "value": locationId, - }, - "status": { - "parent": "items", - "nested": true, - "value": status, - }, - "packaging": { - "parent": "items", - "nested": true, - "value": packaging, - }, + "pk": {"parent": "items", "nested": true, "hidden": true, "value": pk}, + "quantity": {"parent": "items", "nested": true, "value": quantity}, + "location": {"value": locationId}, + "status": {"parent": "items", "nested": true, "value": status}, + "packaging": {"parent": "items", "nested": true, "value": packaging}, "notes": {}, }; @@ -233,10 +196,7 @@ class InvenTreeStockItem extends InvenTreeModel { "location": {}, "quantity": {}, "serial": {}, - "serial_numbers": { - "label": L10().serialNumbers, - "type": "string", - }, + "serial_numbers": {"label": L10().serialNumbers, "type": "string"}, "status": {}, "batch": {}, "purchase_price": {}, @@ -250,13 +210,12 @@ class InvenTreeStockItem extends InvenTreeModel { @override Map defaultFilters() { - return { "part_detail": "true", "location_detail": "true", "supplier_detail": "true", "supplier_part_detail": "true", - "cascade": "false" + "cascade": "false", }; } @@ -265,21 +224,18 @@ class InvenTreeStockItem extends InvenTreeModel { int get testTemplateCount => testTemplates.length; // Get all the test templates associated with this StockItem - Future getTestTemplates({bool showDialog=false}) async { - await InvenTreePartTestTemplate().list( - filters: { - "part": "${partId}", - "enabled": "true", - }, - ).then((var templates) { - testTemplates.clear(); + Future getTestTemplates({bool showDialog = false}) async { + await InvenTreePartTestTemplate() + .list(filters: {"part": "${partId}", "enabled": "true"}) + .then((var templates) { + testTemplates.clear(); - for (var t in templates) { - if (t is InvenTreePartTestTemplate) { - testTemplates.add(t); - } - } - }); + for (var t in templates) { + if (t is InvenTreePartTestTemplate) { + testTemplates.add(t); + } + } + }); } List testResults = []; @@ -287,21 +243,17 @@ class InvenTreeStockItem extends InvenTreeModel { int get testResultCount => testResults.length; Future getTestResults() async { + await InvenTreeStockItemTestResult() + .list(filters: {"stock_item": "${pk}", "user_detail": "true"}) + .then((var results) { + testResults.clear(); - await InvenTreeStockItemTestResult().list( - filters: { - "stock_item": "${pk}", - "user_detail": "true", - }, - ).then((var results) { - testResults.clear(); - - for (var r in results) { - if (r is InvenTreeStockItemTestResult) { - testResults.add(r); - } - } - }); + for (var r in results) { + if (r is InvenTreeStockItemTestResult) { + testResults.add(r); + } + } + }); } int get status => getInt("status"); @@ -313,7 +265,7 @@ class InvenTreeStockItem extends InvenTreeModel { String get batch => getString("batch"); int get partId => getInt("part"); - + double? get purchasePrice { String pp = getString("purchase_price"); @@ -334,7 +286,7 @@ class InvenTreeStockItem extends InvenTreeModel { int get purchaseOrderId => getInt("purchase_order"); int get trackingItemCount => getInt("tracking_items", backup: 0); - + bool get isBuilding => getBool("is_building"); int get salesOrderId => getInt("sales_order"); @@ -362,274 +314,275 @@ class InvenTreeStockItem extends InvenTreeModel { String get stocktakeDateString => getDateString("stocktake_date"); - String get partName { + String get partName { + String nm = ""; - String nm = ""; - - // Use the detailed part information as priority - if (jsondata.containsKey("part_detail")) { - nm = (jsondata["part_detail"]?["full_name"] ?? "") as String; - } - - // Backup if first value fails - if (nm.isEmpty) { - nm = getString("part__name"); - } - - return nm; + // Use the detailed part information as priority + if (jsondata.containsKey("part_detail")) { + nm = (jsondata["part_detail"]?["full_name"] ?? "") as String; } - String get partDescription { - String desc = ""; - - // Use the detailed part description as priority - if (jsondata.containsKey("part_detail")) { - desc = (jsondata["part_detail"]?["description"] ?? "") as String; - } - - if (desc.isEmpty) { - desc = getString("part__description"); - } - - return desc; + // Backup if first value fails + if (nm.isEmpty) { + nm = getString("part__name"); } - String get partImage { - String img = ""; + return nm; + } - if (jsondata.containsKey("part_detail")) { - img = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; - } + String get partDescription { + String desc = ""; - if (img.isEmpty) { - img = getString("part__thumbnail"); - } - - return img; + // Use the detailed part description as priority + if (jsondata.containsKey("part_detail")) { + desc = (jsondata["part_detail"]?["description"] ?? "") as String; } - /* + if (desc.isEmpty) { + desc = getString("part__description"); + } + + return desc; + } + + String get partImage { + String img = ""; + + if (jsondata.containsKey("part_detail")) { + img = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; + } + + if (img.isEmpty) { + img = getString("part__thumbnail"); + } + + return img; + } + + /* * Return the Part thumbnail for this stock item. */ - String get partThumbnail { + String get partThumbnail { + String thumb = ""; - String thumb = ""; + thumb = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; - thumb = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; - - // Use "image" as a backup - if (thumb.isEmpty) { - thumb = (jsondata["part_detail"]?["image"] ?? "") as String; - } - - // Try a different approach - if (thumb.isEmpty) { - thumb = getString("part__thumbnail"); - } - - // Still no thumbnail? Use the "no image" image - if (thumb.isEmpty) thumb = InvenTreeAPI.staticThumb; - - return thumb; + // Use "image" as a backup + if (thumb.isEmpty) { + thumb = (jsondata["part_detail"]?["image"] ?? "") as String; } - int get supplierPartId => getInt("supplier_part"); - - String get supplierImage { - String thumb = ""; - - if (jsondata.containsKey("supplier_part_detail")) { - thumb = (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") as String; - } else if (jsondata.containsKey("supplier_detail")) { - thumb = (jsondata["supplier_detail"]?["image"] ?? "") as String; - } - - return thumb; + // Try a different approach + if (thumb.isEmpty) { + thumb = getString("part__thumbnail"); } - String get supplierName => getString("supplier_name", subKey: "supplier_detail"); + // Still no thumbnail? Use the "no image" image + if (thumb.isEmpty) thumb = InvenTreeAPI.staticThumb; - String get units => getString("units", subKey: "part_detail"); + return thumb; + } - String get supplierSKU => getString("SKU", subKey: "supplier_part_detail"); + int get supplierPartId => getInt("supplier_part"); - String get serialNumber => getString("serial"); + String get supplierImage { + String thumb = ""; - double get quantity => getDouble("quantity"); + if (jsondata.containsKey("supplier_part_detail")) { + thumb = + (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") + as String; + } else if (jsondata.containsKey("supplier_detail")) { + thumb = (jsondata["supplier_detail"]?["image"] ?? "") as String; + } - String quantityString({bool includeUnits = true}){ + return thumb; + } - String q = ""; + String get supplierName => + getString("supplier_name", subKey: "supplier_detail"); - if (allocated > 0) { - q += simpleNumberString(available); - q += " / "; - } + String get units => getString("units", subKey: "part_detail"); - q += simpleNumberString(quantity); + String get supplierSKU => getString("SKU", subKey: "supplier_part_detail"); - if (includeUnits && units.isNotEmpty) { + String get serialNumber => getString("serial"); + + double get quantity => getDouble("quantity"); + + String quantityString({bool includeUnits = true}) { + String q = ""; + + if (allocated > 0) { + q += simpleNumberString(available); + q += " / "; + } + + q += simpleNumberString(quantity); + + if (includeUnits && units.isNotEmpty) { + q += " ${units}"; + } + + return q; + } + + double get allocated => getDouble("allocated"); + + double get available => quantity - allocated; + + int get locationId => getInt("location"); + + bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; + + String serialOrQuantityDisplay() { + if (isSerialized()) { + return "SN ${serialNumber}"; + } else if (allocated > 0) { + return "${available} / ${quantity}"; + } else { + return simpleNumberString(quantity); + } + } + + String get locationName { + if (locationId == -1 || !jsondata.containsKey("location_detail")) { + return "Unknown Location"; + } + + String loc = getString("name", subKey: "location_detail"); + + // Old-style name + if (loc.isEmpty) { + loc = getString("location__name"); + } + + return loc; + } + + String get locationPathString { + if (locationId == -1 || !jsondata.containsKey("location_detail")) { + return L10().locationNotSet; + } + + String _loc = getString("pathstring", subKey: "location_detail"); + if (_loc.isNotEmpty) { + return _loc; + } else { + return locationName; + } + } + + String get displayQuantity { + // Display either quantity or serial number! + + if (serialNumber.isNotEmpty) { + return "SN: $serialNumber"; + } else { + String q = simpleNumberString(quantity); + + if (units.isNotEmpty) { q += " ${units}"; } return q; } + } - double get allocated => getDouble("allocated"); + @override + InvenTreeModel createFromJson(Map json) => + InvenTreeStockItem.fromJson(json); - double get available => quantity - allocated; - - int get locationId => getInt("location"); - - bool isSerialized() => serialNumber.isNotEmpty && quantity.toInt() == 1; - - String serialOrQuantityDisplay() { - if (isSerialized()) { - return "SN ${serialNumber}"; - } else if (allocated > 0) { - return "${available} / ${quantity}"; - } else { - return simpleNumberString(quantity); - } - } - - String get locationName { - - if (locationId == -1 || !jsondata.containsKey("location_detail")) return "Unknown Location"; - - String loc = getString("name", subKey: "location_detail"); - - // Old-style name - if (loc.isEmpty) { - loc = getString("location__name"); - } - - return loc; - } - - String get locationPathString { - - if (locationId == -1 || !jsondata.containsKey("location_detail")) return L10().locationNotSet; - - String _loc = getString("pathstring", subKey: "location_detail"); - if (_loc.isNotEmpty) { - return _loc; - } else { - return locationName; - } - } - - String get displayQuantity { - // Display either quantity or serial number! - - if (serialNumber.isNotEmpty) { - return "SN: $serialNumber"; - } else { - String q = simpleNumberString(quantity); - - if (units.isNotEmpty) { - q += " ${units}"; - } - - return q; - } - } - - @override - InvenTreeModel createFromJson(Map json) => InvenTreeStockItem.fromJson(json); - - /* + /* * Perform stocktake action: * * - Add * - Remove * - Count */ - Future adjustStock(String endpoint, double q, {String? notes, int? location}) async { - - // Serialized stock cannot be adjusted (unless it is a "transfer") - if (isSerialized() && location == null) { - return false; - } - - // Cannot handle negative stock - if (q < 0) { - return false; - } - - Map data = {}; - - data = { - "items": [ - { - "pk": "${pk}", - "quantity": "${quantity}", - } - ], - "notes": notes ?? "", - }; - - if (location != null) { - data["location"] = location; - } - - var response = await api.post( - endpoint, - body: data, - ); - - return response.isValid() && (response.statusCode == 200 || response.statusCode == 201); + Future adjustStock( + String endpoint, + double q, { + String? notes, + int? location, + }) async { + // Serialized stock cannot be adjusted (unless it is a "transfer") + if (isSerialized() && location == null) { + return false; } - Future countStock(double q, {String? notes}) async { - - final bool result = await adjustStock("/stock/count/", q, notes: notes); - - return result; + // Cannot handle negative stock + if (q < 0) { + return false; } - Future addStock(double q, {String? notes}) async { + Map data = {}; - final bool result = await adjustStock("/stock/add/", q, notes: notes); + data = { + "items": [ + {"pk": "${pk}", "quantity": "${quantity}"}, + ], + "notes": notes ?? "", + }; - return result; + if (location != null) { + data["location"] = location; } - Future removeStock(double q, {String? notes}) async { + var response = await api.post(endpoint, body: data); - final bool result = await adjustStock("/stock/remove/", q, notes: notes); - - return result; - } - - Future transferStock(int location, {double? quantity, String? notes}) async { - - double q = this.quantity; - - if (quantity != null) { - q = quantity; - } - - final bool result = await adjustStock( - "/stock/transfer/", - q, - notes: notes, - location: location, - ); - - return result; - } + return response.isValid() && + (response.statusCode == 200 || response.statusCode == 201); } + Future countStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/count/", q, notes: notes); + + return result; + } + + Future addStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/add/", q, notes: notes); + + return result; + } + + Future removeStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/remove/", q, notes: notes); + + return result; + } + + Future transferStock( + int location, { + double? quantity, + String? notes, + }) async { + double q = this.quantity; + + if (quantity != null) { + q = quantity; + } + + final bool result = await adjustStock( + "/stock/transfer/", + q, + notes: notes, + location: location, + ); + + return result; + } +} /* * Class representing an attachment file against a StockItem object */ class InvenTreeStockItemAttachment extends InvenTreeAttachment { - InvenTreeStockItemAttachment() : super(); - InvenTreeStockItemAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreeStockItemAttachment.fromJson(Map json) + : super.fromJson(json); @override String get REFERENCE_FIELD => "stock_item"; @@ -638,18 +591,20 @@ class InvenTreeStockItemAttachment extends InvenTreeAttachment { String get REF_MODEL_TYPE => "stockitem"; @override - String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "stock/attachment/"; + String get URL => InvenTreeAPI().supportsModernAttachments + ? "attachment/" + : "stock/attachment/"; @override - InvenTreeModel createFromJson(Map json) => InvenTreeStockItemAttachment.fromJson(json); + InvenTreeModel createFromJson(Map json) => + InvenTreeStockItemAttachment.fromJson(json); } - class InvenTreeStockLocation extends InvenTreeModel { - InvenTreeStockLocation() : super(); - InvenTreeStockLocation.fromJson(Map json) : super.fromJson(json); + InvenTreeStockLocation.fromJson(Map json) + : super.fromJson(json); @override String get URL => "stock/location/"; @@ -665,9 +620,7 @@ class InvenTreeStockLocation extends InvenTreeModel { Future goToDetailPage(BuildContext context) async { return Navigator.push( context, - MaterialPageRoute( - builder: (context) => LocationDisplayWidget(this) - ) + MaterialPageRoute(builder: (context) => LocationDisplayWidget(this)), ); } @@ -684,7 +637,6 @@ class InvenTreeStockLocation extends InvenTreeModel { } String get parentPathString { - List psplit = pathstring.split("/"); if (psplit.isNotEmpty) { @@ -703,6 +655,6 @@ class InvenTreeStockLocation extends InvenTreeModel { int get itemcount => (jsondata["items"] ?? 0) as int; @override - InvenTreeModel createFromJson(Map json) => InvenTreeStockLocation.fromJson(json); - + InvenTreeModel createFromJson(Map json) => + InvenTreeStockLocation.fromJson(json); } diff --git a/lib/l10.dart b/lib/l10.dart index 76a7558..4b58a93 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -7,8 +7,7 @@ import "package:flutter/material.dart"; import "package:inventree/helpers.dart"; // Shortcut function to reduce boilerplate! -I18N L10() -{ +I18N L10() { // Testing mode - ignore context if (!hasContext()) { return I18NEn(); @@ -26,4 +25,4 @@ I18N L10() // Fallback for "null" context return I18NEn(); -} \ No newline at end of file +} diff --git a/lib/l10n/collect_translations.py b/lib/l10n/collect_translations.py index a768632..d47bd65 100644 --- a/lib/l10n/collect_translations.py +++ b/lib/l10n/collect_translations.py @@ -90,6 +90,7 @@ def generate_locale_list(locales): output.write( "// This file is auto-generated by the 'collect_translations.py' script - do not edit it directly!\n\n" ) + output.write("// dart format off\n\n") output.write('import "package:flutter/material.dart";\n\n') output.write("const List supported_locales = [\n") diff --git a/lib/labels.dart b/lib/labels.dart index ca145e9..10e2c20 100644 --- a/lib/labels.dart +++ b/lib/labels.dart @@ -18,7 +18,6 @@ Future selectAndPrintLabel( String labelType, String labelQuery, ) async { - if (!InvenTreeAPI().isConnected()) { return; } @@ -44,10 +43,7 @@ Future selectAndPrintLabel( int pk = (label["pk"] ?? -1) as int; if (name.isNotEmpty && pk > 0) { - label_options.add({ - "display_name": name, - "value": pk, - }); + label_options.add({"display_name": name, "value": pk}); } } @@ -57,13 +53,12 @@ Future selectAndPrintLabel( // Construct list of available plugins for (var plugin in plugins) { - plugin_options.add({ - "display_name": plugin.humanName, - "value": plugin.key, - }); + plugin_options.add({"display_name": plugin.humanName, "value": plugin.key}); } - String selectedPlugin = await InvenTreeAPI().getUserSetting("LABEL_DEFAULT_PRINTER"); + String selectedPlugin = await InvenTreeAPI().getUserSetting( + "LABEL_DEFAULT_PRINTER", + ); if (selectedPlugin.isNotEmpty) { initial_plugin = selectedPlugin; @@ -85,7 +80,7 @@ Future selectAndPrintLabel( "value": initial_plugin, "choices": plugin_options, "required": true, - } + }, }; launchApiForm( @@ -99,18 +94,12 @@ Future selectAndPrintLabel( final plugin = data["plugin"]; if (template == null) { - showSnackIcon( - L10().labelSelectTemplate, - success: false, - ); + showSnackIcon(L10().labelSelectTemplate, success: false); return false; } if (plugin == null) { - showSnackIcon( - L10().labelSelectPrinter, - success: false, - ); + showSnackIcon(L10().labelSelectPrinter, success: false); return false; } @@ -123,42 +112,42 @@ Future selectAndPrintLabel( bool result = false; if (labelId != -1 && pluginKey != null) { - showLoadingOverlay(); if (InvenTreeAPI().supportsModernLabelPrinting) { - // Modern label printing API uses a POST request to a single API endpoint. - await InvenTreeAPI().post( - "/label/print/", - body: { - "plugin": pluginKey, - "template": labelId, - "items": [instanceId] - } - ).then((APIResponse response) { + await InvenTreeAPI() + .post( + "/label/print/", + body: { + "plugin": pluginKey, + "template": labelId, + "items": [instanceId], + }, + ) + .then((APIResponse response) { + if (response.isValid() && + response.statusCode >= 200 && + response.statusCode <= 201) { + var data = response.asMap(); - if (response.isValid() && response.statusCode >= 200 && - response.statusCode <= 201) { - var data = response.asMap(); + if (data.containsKey("output")) { + String? label_file = (data["output"]) as String?; - if (data.containsKey("output")) { - String? label_file = (data["output"]) as String?; + if (label_file != null && label_file.isNotEmpty) { + // Attempt to open generated file + InvenTreeAPI().downloadFile(label_file); + } - if (label_file != null && label_file.isNotEmpty) { - // Attempt to open generated file - InvenTreeAPI().downloadFile(label_file); + result = true; + } } - - result = true; - } - } - }); - + }); } else { // Legacy label printing API // Uses a GET request to a specially formed URL which depends on the parameters - String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; + String url = + "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}"; await InvenTreeAPI().get(url).then((APIResponse response) { if (response.isValid() && response.statusCode == 200) { var data = response.asMap(); @@ -171,26 +160,20 @@ Future selectAndPrintLabel( } } }); - } + } - hideLoadingOverlay(); + hideLoadingOverlay(); - if (result) { - showSnackIcon( - L10().printLabelSuccess, - success: true - ); - } else { - showSnackIcon( - L10().printLabelFailure, - success: false, - ); + if (result) { + showSnackIcon(L10().printLabelSuccess, success: true); + } else { + showSnackIcon(L10().printLabelFailure, success: false); + } } - } - }); + }, + ); } - /* * Discover which label templates are available for a given item */ @@ -198,8 +181,8 @@ Future>> getLabelTemplates( String labelType, Map data, ) async { - - if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) { + if (!InvenTreeAPI().isConnected() || + !InvenTreeAPI().supportsMixin("labels")) { return []; } @@ -217,10 +200,7 @@ Future>> getLabelTemplates( List> labels = []; - await InvenTreeAPI().get( - url, - params: data, - ).then((APIResponse response) { + await InvenTreeAPI().get(url, params: data).then((APIResponse response) { if (response.isValid() && response.statusCode == 200) { for (var label in response.resultsList()) { if (label is Map) { @@ -231,4 +211,4 @@ Future>> getLabelTemplates( }); return labels; -} \ No newline at end of file +} diff --git a/lib/main.dart b/lib/main.dart index 033ef21..22dd25b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,72 +18,73 @@ import "package:inventree/l10n/collected/app_localizations.dart"; import "package:inventree/settings/release.dart"; import "package:inventree/widget/home.dart"; - Future main() async { - WidgetsFlutterBinding.ensureInitialized(); final savedThemeMode = await AdaptiveTheme.getThemeMode(); - await runZonedGuarded>(() async { + await runZonedGuarded>( + () async { + PackageInfo info = await PackageInfo.fromPlatform(); + String pkg = info.packageName; + String version = info.version; + String build = info.buildNumber; - PackageInfo info = await PackageInfo.fromPlatform(); - String pkg = info.packageName; - String version = info.version; - String build = info.buildNumber; + String release = "${pkg}@${version}:${build}"; - String release = "${pkg}@${version}:${build}"; + if (SENTRY_DSN_KEY.isNotEmpty) { + await Sentry.init((options) { + options.dsn = SENTRY_DSN_KEY; + options.release = release; + options.environment = isInDebugMode() ? "debug" : "release"; + options.diagnosticLevel = SentryLevel.debug; + options.attachStacktrace = true; + }); + } - if (SENTRY_DSN_KEY.isNotEmpty) { - await Sentry.init((options) { - options.dsn = SENTRY_DSN_KEY; - options.release = release; - options.environment = isInDebugMode() ? "debug" : "release"; - options.diagnosticLevel = SentryLevel.debug; - options.attachStacktrace = true; + // Pass any flutter errors off to the Sentry reporting context! + FlutterError.onError = (FlutterErrorDetails details) async { + // Ensure that the error gets reported to sentry! + await sentryReportError( + "FlutterError.onError", + details.exception, + details.stack, + context: { + "context": details.context.toString(), + "summary": details.summary.toString(), + "library": details.library ?? "null", + }, + ); + }; + + final int orientation = + await InvenTreeSettingsManager().getValue( + INV_SCREEN_ORIENTATION, + SCREEN_ORIENTATION_SYSTEM, + ) + as int; + + List orientations = []; + + switch (orientation) { + case SCREEN_ORIENTATION_PORTRAIT: + orientations.add(DeviceOrientation.portraitUp); + case SCREEN_ORIENTATION_LANDSCAPE: + orientations.add(DeviceOrientation.landscapeLeft); + default: + orientations.add(DeviceOrientation.portraitUp); + orientations.add(DeviceOrientation.landscapeLeft); + orientations.add(DeviceOrientation.landscapeRight); + } + + SystemChrome.setPreferredOrientations(orientations).then((_) { + runApp(InvenTreeApp(savedThemeMode)); }); - } - - // Pass any flutter errors off to the Sentry reporting context! - FlutterError.onError = (FlutterErrorDetails details) async { - - // Ensure that the error gets reported to sentry! - await sentryReportError( - "FlutterError.onError", - details.exception, details.stack, - context: { - "context": details.context.toString(), - "summary": details.summary.toString(), - "library": details.library ?? "null", - } - ); - }; - - final int orientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; - - List orientations = []; - - switch (orientation) { - case SCREEN_ORIENTATION_PORTRAIT: - orientations.add(DeviceOrientation.portraitUp); - case SCREEN_ORIENTATION_LANDSCAPE: - orientations.add(DeviceOrientation.landscapeLeft); - default: - orientations.add(DeviceOrientation.portraitUp); - orientations.add(DeviceOrientation.landscapeLeft); - orientations.add(DeviceOrientation.landscapeRight); - } - - SystemChrome.setPreferredOrientations(orientations).then((_) { - runApp( - InvenTreeApp(savedThemeMode) - ); - }); - - }, (Object error, StackTrace stackTrace) async { - sentryReportError("main.runZonedGuarded", error, stackTrace); - }); - + }, + (Object error, StackTrace stackTrace) async { + sentryReportError("main.runZonedGuarded", error, stackTrace); + }, + ); } class InvenTreeApp extends StatefulWidget { @@ -96,13 +97,11 @@ class InvenTreeApp extends StatefulWidget { @override InvenTreeAppState createState() => InvenTreeAppState(savedThemeMode); - static InvenTreeAppState? of(BuildContext context) => context.findAncestorStateOfType(); - + static InvenTreeAppState? of(BuildContext context) => + context.findAncestorStateOfType(); } - class InvenTreeAppState extends State { - InvenTreeAppState(this.savedThemeMode) : super(); // Custom _locale (default = null; use system default) @@ -120,16 +119,17 @@ class InvenTreeAppState extends State { // Run app init routines in the background Future runInitTasks() async { - // Set the app locale (language) Locale? locale = await InvenTreeSettingsManager().getSelectedLocale(); setLocale(locale); // Display release notes if this is a new version - final String version = await InvenTreeSettingsManager().getValue("recentVersion", "") as String; + final String version = + await InvenTreeSettingsManager().getValue("recentVersion", "") + as String; final PackageInfo info = await PackageInfo.fromPlatform(); - + if (version != info.version) { // Save latest version to the settings database await InvenTreeSettingsManager().setValue("recentVersion", info.version); @@ -139,7 +139,7 @@ class InvenTreeAppState extends State { // Show the release notes OneContext().push( - MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)) + MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)), ); } } @@ -155,7 +155,6 @@ class InvenTreeAppState extends State { @override Widget build(BuildContext context) { - return AdaptiveTheme( light: ThemeData( brightness: Brightness.light, @@ -168,7 +167,7 @@ class InvenTreeAppState extends State { useMaterial3: true, ), initial: savedThemeMode ?? AdaptiveThemeMode.light, - builder: (light, dark) => MaterialApp( + builder: (light, dark) => MaterialApp( theme: light, darkTheme: dark, debugShowCheckedModeBanner: false, @@ -185,7 +184,7 @@ class InvenTreeAppState extends State { ], supportedLocales: supported_locales, locale: _locale, - ) + ), ); } } diff --git a/lib/preferences.dart b/lib/preferences.dart index 0959ff5..e10c3d9 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -6,7 +6,6 @@ import "package:path_provider/path_provider.dart"; import "package:sembast/sembast_io.dart"; import "package:path/path.dart"; - // Settings key values const String INV_HOME_SHOW_SUBSCRIBED = "homeShowSubscribed"; const String INV_HOME_SHOW_PO = "homeShowPo"; @@ -62,7 +61,6 @@ const int BARCODE_CONTROLLER_WEDGE = 1; * Class for storing InvenTree preferences in a NoSql DB */ class InvenTreePreferencesDB { - InvenTreePreferencesDB._(); static final InvenTreePreferencesDB _singleton = InvenTreePreferencesDB._(); @@ -74,7 +72,6 @@ class InvenTreePreferencesDB { bool isOpen = false; Future get database async { - if (!isOpen) { // Calling _openDatabase will also complete the completer with database instance _openDatabase(); @@ -101,13 +98,11 @@ class InvenTreePreferencesDB { } } - /* * InvenTree setings manager class. * Provides functions for loading and saving settings, with provision for default values */ class InvenTreeSettingsManager { - factory InvenTreeSettingsManager() { return _manager; } @@ -144,7 +139,6 @@ class InvenTreeSettingsManager { } Future getValue(String key, dynamic backup) async { - dynamic value = await store.record(key).get(await _db); // Retrieve value @@ -174,7 +168,6 @@ class InvenTreeSettingsManager { // Store a key:value pair in the database Future setValue(String key, dynamic value) async { - // Encode null values as strings value ??= "__null__"; @@ -182,5 +175,6 @@ class InvenTreeSettingsManager { } // Ensure we only ever create a single instance of this class - static final InvenTreeSettingsManager _manager = InvenTreeSettingsManager._internal(); + static final InvenTreeSettingsManager _manager = + InvenTreeSettingsManager._internal(); } diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 27a5cd1..ce5ef69 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -13,34 +13,30 @@ import "package:url_launcher/url_launcher.dart"; const String DOCS_URL = "https://docs.inventree.org/app"; class InvenTreeAboutWidget extends StatelessWidget { - const InvenTreeAboutWidget(this.info) : super(); final PackageInfo info; - Future _releaseNotes(BuildContext context) async { - + Future _releaseNotes(BuildContext context) async { // Load release notes from external file String notes = await rootBundle.loadString("assets/release_notes.md"); Navigator.push( - context, - MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)) + context, + MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)), ); } - Future _credits(BuildContext context) async { - + Future _credits(BuildContext context) async { String notes = await rootBundle.loadString("assets/credits.md"); Navigator.push( context, - MaterialPageRoute(builder: (context) => CreditsWidget(notes)) + MaterialPageRoute(builder: (context) => CreditsWidget(notes)), ); } - Future _openDocs() async { - + Future _openDocs() async { var docsUrl = Uri.parse(DOCS_URL); if (await canLaunchUrl(docsUrl)) { @@ -48,23 +44,24 @@ class InvenTreeAboutWidget extends StatelessWidget { } } - Future _reportBug(BuildContext context) async { - + Future _reportBug(BuildContext context) async { var url = Uri( - scheme: "https", - host: "github.com", - path: "inventree/inventree-app/issues/new?title=Enter+bug+description"); + scheme: "https", + host: "github.com", + path: "inventree/inventree-app/issues/new?title=Enter+bug+description", + ); if (await canLaunchUrl(url)) { await launchUrl(url); } } - Future _translate() async { + Future _translate() async { var url = Uri( - scheme: "https", - host: "crowdin.com", - path: "/project/inventree"); + scheme: "https", + host: "crowdin.com", + path: "/project/inventree", + ); if (await canLaunchUrl(url)) { await launchUrl(url); @@ -73,7 +70,6 @@ class InvenTreeAboutWidget extends StatelessWidget { @override Widget build(BuildContext context) { - List tiles = []; tiles.add( @@ -82,41 +78,57 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().serverDetails, style: TextStyle(fontWeight: FontWeight.bold), ), - ) + ), ); if (InvenTreeAPI().isConnected()) { tiles.add( - ListTile( - title: Text(L10().address), - subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected), - leading: Icon(TablerIcons.globe), - trailing: InvenTreeAPI().isConnected() ? Icon(TablerIcons.circle_check, color: COLOR_SUCCESS) : Icon(TablerIcons.circle_x, color: COLOR_DANGER), - ) + ListTile( + title: Text(L10().address), + subtitle: Text( + InvenTreeAPI().baseUrl.isNotEmpty + ? InvenTreeAPI().baseUrl + : L10().notConnected, + ), + leading: Icon(TablerIcons.globe), + trailing: InvenTreeAPI().isConnected() + ? Icon(TablerIcons.circle_check, color: COLOR_SUCCESS) + : Icon(TablerIcons.circle_x, color: COLOR_DANGER), + ), ); tiles.add( ListTile( title: Text(L10().username), subtitle: Text(InvenTreeAPI().username), - leading: InvenTreeAPI().username.isNotEmpty ? Icon(TablerIcons.user) : Icon(TablerIcons.user_cancel, color: COLOR_DANGER), - ) + leading: InvenTreeAPI().username.isNotEmpty + ? Icon(TablerIcons.user) + : Icon(TablerIcons.user_cancel, color: COLOR_DANGER), + ), ); tiles.add( ListTile( title: Text(L10().version), - subtitle: Text(InvenTreeAPI().serverVersion.isNotEmpty ? InvenTreeAPI().serverVersion : L10().notConnected), + subtitle: Text( + InvenTreeAPI().serverVersion.isNotEmpty + ? InvenTreeAPI().serverVersion + : L10().notConnected, + ), leading: Icon(TablerIcons.info_circle), - ) + ), ); tiles.add( ListTile( title: Text(L10().serverInstance), - subtitle: Text(InvenTreeAPI().serverInstance.isNotEmpty ? InvenTreeAPI().serverInstance : L10().notConnected), + subtitle: Text( + InvenTreeAPI().serverInstance.isNotEmpty + ? InvenTreeAPI().serverInstance + : L10().notConnected, + ), leading: Icon(TablerIcons.server), - ) + ), ); // Display extra tile if the server supports plugins @@ -125,9 +137,8 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().pluginSupport), subtitle: Text(L10().pluginSupportDetail), leading: Icon(TablerIcons.plug), - ) + ), ); - } else { tiles.add( ListTile( @@ -136,8 +147,8 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().serverNotConnected, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: Icon(TablerIcons.exclamation_circle) - ) + leading: Icon(TablerIcons.exclamation_circle), + ), ); } @@ -147,23 +158,23 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().appDetails, style: TextStyle(fontWeight: FontWeight.bold), ), - ) + ), ); tiles.add( ListTile( title: Text(L10().packageName), subtitle: Text("${info.packageName}"), - leading: Icon(TablerIcons.box) - ) + leading: Icon(TablerIcons.box), + ), ); tiles.add( ListTile( title: Text(L10().version), subtitle: Text("${info.version} - Build ${info.buildNumber}"), - leading: Icon(TablerIcons.info_circle) - ) + leading: Icon(TablerIcons.info_circle), + ), ); tiles.add( @@ -174,7 +185,7 @@ class InvenTreeAboutWidget extends StatelessWidget { onTap: () { _releaseNotes(context); }, - ) + ), ); tiles.add( @@ -184,8 +195,8 @@ class InvenTreeAboutWidget extends StatelessWidget { leading: Icon(TablerIcons.balloon, color: COLOR_ACTION), onTap: () { _credits(context); - } - ) + }, + ), ); tiles.add( @@ -196,7 +207,7 @@ class InvenTreeAboutWidget extends StatelessWidget { onTap: () { _openDocs(); }, - ) + ), ); tiles.add( @@ -206,8 +217,8 @@ class InvenTreeAboutWidget extends StatelessWidget { leading: Icon(TablerIcons.language, color: COLOR_ACTION), onTap: () { _translate(); - } - ) + }, + ), ); tiles.add( @@ -216,9 +227,9 @@ class InvenTreeAboutWidget extends StatelessWidget { subtitle: Text(L10().reportBugDescription), leading: Icon(TablerIcons.bug, color: COLOR_ACTION), onTap: () { - _reportBug(context); + _reportBug(context); }, - ) + ), ); return Scaffold( @@ -227,11 +238,8 @@ class InvenTreeAboutWidget extends StatelessWidget { backgroundColor: COLOR_APP_BAR, ), body: ListView( - children: ListTile.divideTiles( - context: context, - tiles: tiles, - ).toList(), - ) + children: ListTile.divideTiles(context: context, tiles: tiles).toList(), + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 2443e81..ba2d7cb 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -16,17 +16,16 @@ import "package:inventree/preferences.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/progress.dart"; - class InvenTreeAppSettingsWidget extends StatefulWidget { @override _InvenTreeAppSettingsState createState() => _InvenTreeAppSettingsState(); } class _InvenTreeAppSettingsState extends State { - _InvenTreeAppSettingsState(); - final GlobalKey<_InvenTreeAppSettingsState> _settingsKey = GlobalKey<_InvenTreeAppSettingsState>(); + final GlobalKey<_InvenTreeAppSettingsState> _settingsKey = + GlobalKey<_InvenTreeAppSettingsState>(); // Sound settings bool barcodeSounds = true; @@ -48,16 +47,33 @@ class _InvenTreeAppSettingsState extends State { loadSettings(OneContext().context!); } - Future loadSettings(BuildContext context) async { - + Future loadSettings(BuildContext context) async { showLoadingOverlay(); - barcodeSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - serverSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; - reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; - strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; - screenOrientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; - enableLabelPrinting = await InvenTreeSettingsManager().getValue(INV_ENABLE_LABEL_PRINTING, true) as bool; + barcodeSounds = + await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) + as bool; + serverSounds = + await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) + as bool; + reportErrors = + await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) + as bool; + strictHttps = + await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) + as bool; + screenOrientation = + await InvenTreeSettingsManager().getValue( + INV_SCREEN_ORIENTATION, + SCREEN_ORIENTATION_SYSTEM, + ) + as int; + enableLabelPrinting = + await InvenTreeSettingsManager().getValue( + INV_ENABLE_LABEL_PRINTING, + true, + ) + as bool; darkMode = AdaptiveTheme.of(context).mode.isDark; @@ -71,19 +87,15 @@ class _InvenTreeAppSettingsState extends State { } Future _selectLocale(BuildContext context) async { - List> options = [ - { - "display_name": L10().languageDefault, - "value": null, - } + {"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() + "value": locale.toString(), }); } @@ -93,7 +105,7 @@ class _InvenTreeAppSettingsState extends State { "type": "choice", "choices": options, "value": locale?.toString(), - } + }, }; launchApiForm( @@ -103,7 +115,6 @@ class _InvenTreeAppSettingsState extends State { fields, icon: TablerIcons.circle_check, onSuccess: (Map data) async { - String locale_name = (data["locale"] ?? "") as String; Locale? selected_locale; @@ -124,18 +135,18 @@ class _InvenTreeAppSettingsState extends State { // Clear the cached status label information InvenTreeAPI().clearStatusCodeData(); - } + }, ); } - @override Widget build(BuildContext context) { - String languageName = L10().languageDefault; if (locale != null) { - languageName = LocaleNames.of(context)!.nameOf(locale.toString()) ?? L10().languageDefault; + languageName = + LocaleNames.of(context)!.nameOf(locale.toString()) ?? + L10().languageDefault; } IconData orientationIcon = Icons.screen_rotation; @@ -154,7 +165,7 @@ class _InvenTreeAppSettingsState extends State { key: _settingsKey, appBar: AppBar( title: Text(L10().appSettings), - backgroundColor: COLOR_APP_BAR + backgroundColor: COLOR_APP_BAR, ), body: Container( child: ListView( @@ -183,8 +194,8 @@ class _InvenTreeAppSettingsState extends State { setState(() { darkMode = value; }); - } - ) + }, + ), ), GestureDetector( child: ListTile( @@ -198,26 +209,43 @@ class _InvenTreeAppSettingsState extends State { L10().orientation, [ ListTile( - leading: Icon(Icons.screen_rotation, color: screenOrientation == SCREEN_ORIENTATION_SYSTEM ? COLOR_ACTION : null), + leading: Icon( + Icons.screen_rotation, + color: screenOrientation == SCREEN_ORIENTATION_SYSTEM + ? COLOR_ACTION + : null, + ), title: Text(L10().orientationSystem), ), ListTile( - leading: Icon(Icons.screen_lock_portrait, color: screenOrientation == SCREEN_ORIENTATION_PORTRAIT ? COLOR_ACTION : null), + leading: Icon( + Icons.screen_lock_portrait, + color: screenOrientation == SCREEN_ORIENTATION_PORTRAIT + ? COLOR_ACTION + : null, + ), title: Text(L10().orientationPortrait), ), ListTile( - leading: Icon(Icons.screen_lock_landscape, color: screenOrientation == SCREEN_ORIENTATION_LANDSCAPE ? COLOR_ACTION : null), + leading: Icon( + Icons.screen_lock_landscape, + color: screenOrientation == SCREEN_ORIENTATION_LANDSCAPE + ? COLOR_ACTION + : null, + ), title: Text(L10().orientationLandscape), - ) + ), ], onSelected: (idx) async { screenOrientation = idx as int; - InvenTreeSettingsManager().setValue(INV_SCREEN_ORIENTATION, screenOrientation); + InvenTreeSettingsManager().setValue( + INV_SCREEN_ORIENTATION, + screenOrientation, + ); - setState(() { - }); - } + setState(() {}); + }, ); }, ), @@ -228,11 +256,14 @@ class _InvenTreeAppSettingsState extends State { trailing: Switch( value: enableLabelPrinting, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_ENABLE_LABEL_PRINTING, value); + InvenTreeSettingsManager().setValue( + INV_ENABLE_LABEL_PRINTING, + value, + ); setState(() { enableLabelPrinting = value; }); - } + }, ), ), ListTile( @@ -271,7 +302,7 @@ class _InvenTreeAppSettingsState extends State { }, ), ), - ListTile( + ListTile( title: Text( L10().sounds, style: TextStyle(fontWeight: FontWeight.bold), @@ -300,7 +331,10 @@ class _InvenTreeAppSettingsState extends State { trailing: Switch( value: barcodeSounds, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); + InvenTreeSettingsManager().setValue( + INV_SOUNDS_BARCODE, + value, + ); setState(() { barcodeSounds = value; }); @@ -308,9 +342,9 @@ class _InvenTreeAppSettingsState extends State { ), ), Divider(height: 1), - ] - ) - ) + ], + ), + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart index f3776cd..0d70970 100644 --- a/lib/settings/barcode_settings.dart +++ b/lib/settings/barcode_settings.dart @@ -7,44 +7,52 @@ import "package:inventree/app_colors.dart"; import "package:inventree/widget/dialogs.dart"; - class InvenTreeBarcodeSettingsWidget extends StatefulWidget { @override - _InvenTreeBarcodeSettingsState createState() => _InvenTreeBarcodeSettingsState(); + _InvenTreeBarcodeSettingsState createState() => + _InvenTreeBarcodeSettingsState(); } +class _InvenTreeBarcodeSettingsState + extends State { + _InvenTreeBarcodeSettingsState(); -class _InvenTreeBarcodeSettingsState extends State { + int barcodeScanDelay = 500; + int barcodeScanType = BARCODE_CONTROLLER_CAMERA; + bool barcodeScanSingle = false; - _InvenTreeBarcodeSettingsState(); + final TextEditingController _barcodeScanDelayController = + TextEditingController(); - int barcodeScanDelay = 500; - int barcodeScanType = BARCODE_CONTROLLER_CAMERA; - bool barcodeScanSingle = false; - - final TextEditingController _barcodeScanDelayController = TextEditingController(); - - @override - void initState() { - super.initState(); - loadSettings(); - } + @override + void initState() { + super.initState(); + loadSettings(); + } Future loadSettings() async { - barcodeScanDelay = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) as int; - barcodeScanType = await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_TYPE, BARCODE_CONTROLLER_CAMERA) as int; - barcodeScanSingle = await InvenTreeSettingsManager().getBool(INV_BARCODE_SCAN_SINGLE, false); + barcodeScanDelay = + await InvenTreeSettingsManager().getValue(INV_BARCODE_SCAN_DELAY, 500) + as int; + barcodeScanType = + await InvenTreeSettingsManager().getValue( + INV_BARCODE_SCAN_TYPE, + BARCODE_CONTROLLER_CAMERA, + ) + as int; + barcodeScanSingle = await InvenTreeSettingsManager().getBool( + INV_BARCODE_SCAN_SINGLE, + false, + ); if (mounted) { - setState(() { - }); + setState(() {}); } } // Callback function to edit the barcode scan delay value // TODO: Next time any new settings are added, refactor this into a generic function Future _editBarcodeScanDelay(BuildContext context) async { - _barcodeScanDelayController.text = barcodeScanDelay.toString(); return showDialog( @@ -56,9 +64,7 @@ class _InvenTreeBarcodeSettingsState extends State[ MaterialButton( @@ -76,13 +82,18 @@ class _InvenTreeBarcodeSettingsState extends State 2500) delay = 2500; - InvenTreeSettingsManager().setValue(INV_BARCODE_SCAN_DELAY, delay); + InvenTreeSettingsManager().setValue( + INV_BARCODE_SCAN_DELAY, + delay, + ); setState(() { barcodeScanDelay = delay; Navigator.pop(context); @@ -91,13 +102,12 @@ class _InvenTreeBarcodeSettingsState extends State { - _HomeScreenSettingsState(); - final GlobalKey<_HomeScreenSettingsState> _settingsKey = GlobalKey<_HomeScreenSettingsState>(); + final GlobalKey<_HomeScreenSettingsState> _settingsKey = + GlobalKey<_HomeScreenSettingsState>(); // Home screen settings bool homeShowSubscribed = true; @@ -32,92 +31,113 @@ class _HomeScreenSettingsState extends State { loadSettings(); } - Future loadSettings() async { - + Future loadSettings() async { // Load initial settings - homeShowSubscribed = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUBSCRIBED, true) as bool; - homeShowPo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) as bool; - homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; - homeShowManufacturers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_MANUFACTURERS, true) as bool; - homeShowCustomers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) as bool; - homeShowSuppliers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) as bool; + homeShowSubscribed = + await InvenTreeSettingsManager().getValue( + INV_HOME_SHOW_SUBSCRIBED, + true, + ) + as bool; + homeShowPo = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) + as bool; + homeShowSo = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) + as bool; + homeShowManufacturers = + await InvenTreeSettingsManager().getValue( + INV_HOME_SHOW_MANUFACTURERS, + true, + ) + as bool; + homeShowCustomers = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) + as bool; + homeShowSuppliers = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) + as bool; - setState(() { - }); + setState(() {}); } @override Widget build(BuildContext context) { - return Scaffold( - key: _settingsKey, - appBar: AppBar( - title: Text(L10().homeScreen), - backgroundColor: COLOR_APP_BAR, - ), - body: Container( - child: ListView( - children: [ - ListTile( - title: Text(L10().homeShowSubscribed), - subtitle: Text(L10().homeShowSubscribedDescription), - leading: Icon(TablerIcons.bell), - trailing: Switch( - value: homeShowSubscribed, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SUBSCRIBED, value); - setState(() { - homeShowSubscribed = value; - }); - }, - ) - ), - ListTile( - title: Text(L10().homeShowPo), - subtitle: Text(L10().homeShowPoDescription), - leading: Icon(TablerIcons.shopping_cart), - trailing: Switch( - value: homeShowPo, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_PO, value); - setState(() { - homeShowPo = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().homeShowSo), - subtitle: Text(L10().homeShowSoDescription), - leading: Icon(TablerIcons.truck), - trailing: Switch( - value: homeShowSo, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SO, value); - setState(() { - homeShowSo = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().homeShowSuppliers), - subtitle: Text(L10().homeShowSuppliersDescription), - leading: Icon(TablerIcons.building), - trailing: Switch( - value: homeShowSuppliers, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SUPPLIERS, value); - setState(() { - homeShowSuppliers = value; - }); - }, - ), - ), - // TODO: When these features are improved, add them back in! - // Currently, the company display does not provide any value - /* + key: _settingsKey, + appBar: AppBar( + title: Text(L10().homeScreen), + backgroundColor: COLOR_APP_BAR, + ), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().homeShowSubscribed), + subtitle: Text(L10().homeShowSubscribedDescription), + leading: Icon(TablerIcons.bell), + trailing: Switch( + value: homeShowSubscribed, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_HOME_SHOW_SUBSCRIBED, + value, + ); + setState(() { + homeShowSubscribed = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().homeShowPo), + subtitle: Text(L10().homeShowPoDescription), + leading: Icon(TablerIcons.shopping_cart), + trailing: Switch( + value: homeShowPo, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_HOME_SHOW_PO, value); + setState(() { + homeShowPo = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().homeShowSo), + subtitle: Text(L10().homeShowSoDescription), + leading: Icon(TablerIcons.truck), + trailing: Switch( + value: homeShowSo, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SO, value); + setState(() { + homeShowSo = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().homeShowSuppliers), + subtitle: Text(L10().homeShowSuppliersDescription), + leading: Icon(TablerIcons.building), + trailing: Switch( + value: homeShowSuppliers, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_HOME_SHOW_SUPPLIERS, + value, + ); + setState(() { + homeShowSuppliers = value; + }); + }, + ), + ), + // TODO: When these features are improved, add them back in! + // Currently, the company display does not provide any value + /* ListTile( title: Text(L10().homeShowManufacturers), subtitle: Text(L10().homeShowManufacturersDescription), @@ -133,23 +153,26 @@ class _HomeScreenSettingsState extends State { ), ), */ - ListTile( - title: Text(L10().homeShowCustomers), - subtitle: Text(L10().homeShowCustomersDescription), - leading: Icon(TablerIcons.user), - trailing: Switch( - value: homeShowCustomers, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_CUSTOMERS, value); - setState(() { - homeShowCustomers = value; - }); - }, - ), - ), - ] - ) - ) + ListTile( + title: Text(L10().homeShowCustomers), + subtitle: Text(L10().homeShowCustomersDescription), + leading: Icon(TablerIcons.user), + trailing: Switch( + value: homeShowCustomers, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_HOME_SHOW_CUSTOMERS, + value, + ); + setState(() { + homeShowCustomers = value; + }); + }, + ), + ), + ], + ), + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 908d09a..2e04d49 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -9,21 +8,16 @@ import "package:inventree/api.dart"; import "package:inventree/widget/dialogs.dart"; import "package:inventree/widget/progress.dart"; - class InvenTreeLoginWidget extends StatefulWidget { - const InvenTreeLoginWidget(this.profile) : super(); final UserProfile profile; @override _InvenTreeLoginState createState() => _InvenTreeLoginState(); - } - class _InvenTreeLoginState extends State { - final formKey = GlobalKey(); String username = ""; @@ -35,14 +29,12 @@ class _InvenTreeLoginState extends State { // Attempt login Future _doLogin(BuildContext context) async { - // Save form formKey.currentState?.save(); bool valid = formKey.currentState?.validate() ?? false; if (valid) { - // Dismiss the keyboard FocusScopeNode currentFocus = FocusScope.of(context); @@ -53,7 +45,11 @@ class _InvenTreeLoginState extends State { showLoadingOverlay(); // Attempt login - final response = await InvenTreeAPI().fetchToken(widget.profile, username, password); + final response = await InvenTreeAPI().fetchToken( + widget.profile, + username, + password, + ); hideLoadingOverlay(); @@ -75,12 +71,10 @@ class _InvenTreeLoginState extends State { }); } } - } @override Widget build(BuildContext context) { - List before = [ ListTile( title: Text(L10().loginEnter), @@ -99,11 +93,13 @@ class _InvenTreeLoginState extends State { if (error.isNotEmpty) { after.add(Divider()); - after.add(ListTile( - leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), - title: Text(L10().error, style: TextStyle(color: COLOR_DANGER)), - subtitle: Text(error, style: TextStyle(color: COLOR_DANGER)), - )); + after.add( + ListTile( + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + title: Text(L10().error, style: TextStyle(color: COLOR_DANGER)), + subtitle: Text(error, style: TextStyle(color: COLOR_DANGER)), + ), + ); } return Scaffold( appBar: AppBar( @@ -115,8 +111,8 @@ class _InvenTreeLoginState extends State { onPressed: () async { _doLogin(context); }, - ) - ] + ), + ], ), body: Form( key: formKey, @@ -129,9 +125,9 @@ class _InvenTreeLoginState extends State { ...before, TextFormField( decoration: InputDecoration( - labelText: L10().username, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: L10().enterUsername + labelText: L10().username, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterUsername, ), initialValue: "", keyboardType: TextInputType.text, @@ -147,41 +143,41 @@ class _InvenTreeLoginState extends State { }, ), TextFormField( - decoration: InputDecoration( - labelText: L10().password, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: L10().enterPassword, - suffixIcon: IconButton( - icon: _obscured ? Icon(TablerIcons.eye) : Icon(TablerIcons.eye_off), - onPressed: () { - setState(() { - _obscured = !_obscured; - }); - }, - ), + decoration: InputDecoration( + labelText: L10().password, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterPassword, + suffixIcon: IconButton( + icon: _obscured + ? Icon(TablerIcons.eye) + : Icon(TablerIcons.eye_off), + onPressed: () { + setState(() { + _obscured = !_obscured; + }); + }, ), - initialValue: "", - keyboardType: TextInputType.visiblePassword, - obscureText: _obscured, - onSaved: (value) { - password = value?.trim() ?? ""; - }, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return L10().passwordEmpty; - } - - return null; + ), + initialValue: "", + keyboardType: TextInputType.visiblePassword, + obscureText: _obscured, + onSaved: (value) { + password = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().passwordEmpty; } + + return null; + }, ), ...after, ], ), padding: EdgeInsets.all(16), - ) - ) + ), + ), ); - } - -} \ No newline at end of file +} diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 5a8ccd2..b091931 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -6,15 +5,12 @@ import "package:inventree/l10.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; - class InvenTreePartSettingsWidget extends StatefulWidget { @override _InvenTreePartSettingsState createState() => _InvenTreePartSettingsState(); } - class _InvenTreePartSettingsState extends State { - _InvenTreePartSettingsState(); bool partShowParameters = true; @@ -32,16 +28,33 @@ class _InvenTreePartSettingsState extends State { } Future loadSettings() async { - partShowParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); - partShowBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); - partShowPricing = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PRICING, true); - stockShowHistory = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_HISTORY, false); - stockShowTests = await InvenTreeSettingsManager().getBool(INV_STOCK_SHOW_TESTS, true); - stockConfirmScan = await InvenTreeSettingsManager().getBool(INV_STOCK_CONFIRM_SCAN, false); + partShowParameters = await InvenTreeSettingsManager().getBool( + INV_PART_SHOW_PARAMETERS, + true, + ); + partShowBom = await InvenTreeSettingsManager().getBool( + INV_PART_SHOW_BOM, + true, + ); + partShowPricing = await InvenTreeSettingsManager().getBool( + INV_PART_SHOW_PRICING, + true, + ); + stockShowHistory = await InvenTreeSettingsManager().getBool( + INV_STOCK_SHOW_HISTORY, + false, + ); + stockShowTests = await InvenTreeSettingsManager().getBool( + INV_STOCK_SHOW_TESTS, + true, + ); + stockConfirmScan = await InvenTreeSettingsManager().getBool( + INV_STOCK_CONFIRM_SCAN, + false, + ); if (mounted) { - setState(() { - }); + setState(() {}); } } @@ -50,7 +63,7 @@ class _InvenTreePartSettingsState extends State { return Scaffold( appBar: AppBar( title: Text(L10().partSettings), - backgroundColor: COLOR_APP_BAR + backgroundColor: COLOR_APP_BAR, ), body: Container( child: ListView( @@ -62,7 +75,10 @@ class _InvenTreePartSettingsState extends State { trailing: Switch( value: partShowParameters, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PART_SHOW_PARAMETERS, value); + InvenTreeSettingsManager().setValue( + INV_PART_SHOW_PARAMETERS, + value, + ); setState(() { partShowParameters = value; }); @@ -90,7 +106,10 @@ class _InvenTreePartSettingsState extends State { trailing: Switch( value: partShowPricing, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PART_SHOW_PRICING, value); + InvenTreeSettingsManager().setValue( + INV_PART_SHOW_PRICING, + value, + ); setState(() { partShowPricing = value; }); @@ -105,7 +124,10 @@ class _InvenTreePartSettingsState extends State { trailing: Switch( value: stockShowHistory, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STOCK_SHOW_HISTORY, value); + InvenTreeSettingsManager().setValue( + INV_STOCK_SHOW_HISTORY, + value, + ); setState(() { stockShowHistory = value; }); @@ -115,11 +137,14 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().testResults), subtitle: Text(L10().testResultsDetail), - leading: Icon(TablerIcons.test_pipe), + leading: Icon(TablerIcons.test_pipe), trailing: Switch( value: stockShowTests, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STOCK_SHOW_TESTS, value); + InvenTreeSettingsManager().setValue( + INV_STOCK_SHOW_TESTS, + value, + ); setState(() { stockShowTests = value; }); @@ -133,16 +158,19 @@ class _InvenTreePartSettingsState extends State { trailing: Switch( value: stockConfirmScan, onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STOCK_CONFIRM_SCAN, value); + InvenTreeSettingsManager().setValue( + INV_STOCK_CONFIRM_SCAN, + value, + ); setState(() { stockConfirmScan = value; }); - } + }, ), - ) - ] - ) - ) + ), + ], + ), + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/purchase_order_settings.dart b/lib/settings/purchase_order_settings.dart index 888b89b..8b6452c 100644 --- a/lib/settings/purchase_order_settings.dart +++ b/lib/settings/purchase_order_settings.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; @@ -6,15 +5,14 @@ import "package:inventree/app_colors.dart"; import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; - class InvenTreePurchaseOrderSettingsWidget extends StatefulWidget { @override - _InvenTreePurchaseOrderSettingsState createState() => _InvenTreePurchaseOrderSettingsState(); + _InvenTreePurchaseOrderSettingsState createState() => + _InvenTreePurchaseOrderSettingsState(); } - -class _InvenTreePurchaseOrderSettingsState extends State { - +class _InvenTreePurchaseOrderSettingsState + extends State { _InvenTreePurchaseOrderSettingsState(); bool poEnable = true; @@ -30,70 +28,81 @@ class _InvenTreePurchaseOrderSettingsState extends State loadSettings() async { poEnable = await InvenTreeSettingsManager().getBool(INV_PO_ENABLE, true); - poShowCamera = await InvenTreeSettingsManager().getBool(INV_PO_SHOW_CAMERA, true); - poConfirmScan = await InvenTreeSettingsManager().getBool(INV_PO_CONFIRM_SCAN, true); + poShowCamera = await InvenTreeSettingsManager().getBool( + INV_PO_SHOW_CAMERA, + true, + ); + poConfirmScan = await InvenTreeSettingsManager().getBool( + INV_PO_CONFIRM_SCAN, + true, + ); if (mounted) { - setState(() { - }); + setState(() {}); } } @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(L10().purchaseOrderSettings), - backgroundColor: COLOR_APP_BAR, + appBar: AppBar( + title: Text(L10().purchaseOrderSettings), + backgroundColor: COLOR_APP_BAR, + ), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().purchaseOrderEnable), + subtitle: Text(L10().purchaseOrderEnableDetail), + leading: Icon(TablerIcons.shopping_cart), + trailing: Switch( + value: poEnable, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_PO_ENABLE, value); + setState(() { + poEnable = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().purchaseOrderShowCamera), + subtitle: Text(L10().purchaseOrderShowCameraDetail), + leading: Icon(TablerIcons.camera), + trailing: Switch( + value: poShowCamera, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_PO_SHOW_CAMERA, + value, + ); + setState(() { + poShowCamera = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().purchaseOrderConfirmScan), + subtitle: Text(L10().purchaseOrderConfirmScanDetail), + leading: Icon(TablerIcons.barcode), + trailing: Switch( + value: poConfirmScan, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_PO_CONFIRM_SCAN, + value, + ); + setState(() { + poConfirmScan = value; + }); + }, + ), + ), + ], ), - body: Container( - child: ListView( - children: [ - ListTile( - title: Text(L10().purchaseOrderEnable), - subtitle: Text(L10().purchaseOrderEnableDetail), - leading: Icon(TablerIcons.shopping_cart), - trailing: Switch( - value: poEnable, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PO_ENABLE, value); - setState(() { - poEnable = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().purchaseOrderShowCamera), - subtitle: Text(L10().purchaseOrderShowCameraDetail), - leading: Icon(TablerIcons.camera), - trailing: Switch( - value: poShowCamera, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PO_SHOW_CAMERA, value); - setState(() { - poShowCamera = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().purchaseOrderConfirmScan), - subtitle: Text(L10().purchaseOrderConfirmScanDetail), - leading: Icon(TablerIcons.barcode), - trailing: Switch ( - value: poConfirmScan, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PO_CONFIRM_SCAN, value); - setState(() { - poConfirmScan = value; - }); - }, - ), - ) - ] - ) - ) + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/release.dart b/lib/settings/release.dart index 20e10b2..7f8e11d 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -6,15 +6,13 @@ import "package:url_launcher/url_launcher.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; - class ReleaseNotesWidget extends StatelessWidget { - const ReleaseNotesWidget(this.releaseNotes); final String releaseNotes; @override - Widget build (BuildContext context) { + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(L10().releaseNotes), @@ -29,21 +27,18 @@ class ReleaseNotesWidget extends StatelessWidget { openLink(link); } }, - ) + ), ); } } - class CreditsWidget extends StatelessWidget { - const CreditsWidget(this.credits); final String credits; // Callback function when a link is clicked in the markdown Future openLink(String url) async { - final link = Uri.parse(url); if (await canLaunchUrl(link)) { @@ -52,7 +47,7 @@ class CreditsWidget extends StatelessWidget { } @override - Widget build (BuildContext context) { + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(L10().credits), @@ -67,7 +62,7 @@ class CreditsWidget extends StatelessWidget { openLink(link); } }, - ) + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/sales_order_settings.dart b/lib/settings/sales_order_settings.dart index cbeacb6..e009f86 100644 --- a/lib/settings/sales_order_settings.dart +++ b/lib/settings/sales_order_settings.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -6,15 +5,14 @@ import "package:inventree/l10.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/preferences.dart"; - class InvenTreeSalesOrderSettingsWidget extends StatefulWidget { @override - _InvenTreeSalesOrderSettingsState createState() => _InvenTreeSalesOrderSettingsState(); + _InvenTreeSalesOrderSettingsState createState() => + _InvenTreeSalesOrderSettingsState(); } - -class _InvenTreeSalesOrderSettingsState extends State { - +class _InvenTreeSalesOrderSettingsState + extends State { _InvenTreeSalesOrderSettingsState(); bool soEnable = true; @@ -29,55 +27,60 @@ class _InvenTreeSalesOrderSettingsState extends State loadSettings() async { soEnable = await InvenTreeSettingsManager().getBool(INV_SO_ENABLE, true); - soShowCamera = await InvenTreeSettingsManager().getBool(INV_SO_SHOW_CAMERA, true); + soShowCamera = await InvenTreeSettingsManager().getBool( + INV_SO_SHOW_CAMERA, + true, + ); if (mounted) { - setState(() { - }); + setState(() {}); } } @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(L10().salesOrderSettings), - backgroundColor: COLOR_APP_BAR, + appBar: AppBar( + title: Text(L10().salesOrderSettings), + backgroundColor: COLOR_APP_BAR, + ), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().salesOrderEnable), + subtitle: Text(L10().salesOrderEnableDetail), + leading: Icon(TablerIcons.shopping_cart), + trailing: Switch( + value: soEnable, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_SO_ENABLE, value); + setState(() { + soEnable = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().salesOrderShowCamera), + subtitle: Text(L10().salesOrderShowCameraDetail), + leading: Icon(TablerIcons.camera), + trailing: Switch( + value: soShowCamera, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_SO_SHOW_CAMERA, + value, + ); + setState(() { + soShowCamera = value; + }); + }, + ), + ), + ], ), - body: Container( - child: ListView( - children: [ - ListTile( - title: Text(L10().salesOrderEnable), - subtitle: Text(L10().salesOrderEnableDetail), - leading: Icon(TablerIcons.shopping_cart), - trailing: Switch( - value: soEnable, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_SO_ENABLE, value); - setState(() { - soEnable = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().salesOrderShowCamera), - subtitle: Text(L10().salesOrderShowCameraDetail), - leading: Icon(TablerIcons.camera), - trailing: Switch( - value: soShowCamera, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_SO_SHOW_CAMERA, value); - setState(() { - soShowCamera = value; - }); - }, - ), - ), - ] - ) - ) + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/select_server.dart b/lib/settings/select_server.dart index 2244cad..bfeae98 100644 --- a/lib/settings/select_server.dart +++ b/lib/settings/select_server.dart @@ -12,39 +12,37 @@ import "package:inventree/api.dart"; import "package:inventree/user_profile.dart"; class InvenTreeSelectServerWidget extends StatefulWidget { - @override _InvenTreeSelectServerState createState() => _InvenTreeSelectServerState(); } - class _InvenTreeSelectServerState extends State { - _InvenTreeSelectServerState() { _reload(); } - final GlobalKey<_InvenTreeSelectServerState> _loginKey = GlobalKey<_InvenTreeSelectServerState>(); + final GlobalKey<_InvenTreeSelectServerState> _loginKey = + GlobalKey<_InvenTreeSelectServerState>(); List profiles = []; - Future _reload() async { - + Future _reload() async { profiles = await UserProfileDBManager().getAllProfiles(); if (!mounted) { return; } - setState(() { - }); + setState(() {}); } /* * Logout the selected profile (delete the stored token) */ - Future _logoutProfile(BuildContext context, {UserProfile? userProfile}) async { - + Future _logoutProfile( + BuildContext context, { + UserProfile? userProfile, + }) async { if (userProfile != null) { userProfile.token = ""; await UserProfileDBManager().updateProfile(userProfile); @@ -54,26 +52,25 @@ class _InvenTreeSelectServerState extends State { InvenTreeAPI().disconnectFromServer(); _reload(); - } /* * Edit the selected profile */ - void _editProfile(BuildContext context, {UserProfile? userProfile, bool createNew = false}) { - + void _editProfile( + BuildContext context, { + UserProfile? userProfile, + bool createNew = false, + }) { Navigator.push( context, - MaterialPageRoute( - builder: (context) => ProfileEditWidget(userProfile) - ) + MaterialPageRoute(builder: (context) => ProfileEditWidget(userProfile)), ).then((context) { _reload(); }); } - Future _selectProfile(BuildContext context, UserProfile profile) async { - + Future _selectProfile(BuildContext context, UserProfile profile) async { // Disconnect InvenTree InvenTreeAPI().disconnectFromServer(); @@ -94,8 +91,9 @@ class _InvenTreeSelectServerState extends State { // First check if the profile has an associate token if (!prf.hasToken) { // Redirect user to login screen - Navigator.push(context, - MaterialPageRoute(builder: (context) => InvenTreeLoginWidget(profile)) + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeLoginWidget(profile)), ).then((value) async { _reload(); // Reload profile @@ -125,8 +123,7 @@ class _InvenTreeSelectServerState extends State { _reload(); } - Future _deleteProfile(UserProfile profile) async { - + Future _deleteProfile(UserProfile profile) async { await UserProfileDBManager().deleteProfile(profile); if (!mounted) { @@ -135,13 +132,13 @@ class _InvenTreeSelectServerState extends State { _reload(); - if (InvenTreeAPI().isConnected() && profile.key == (InvenTreeAPI().profile?.key ?? "")) { + if (InvenTreeAPI().isConnected() && + profile.key == (InvenTreeAPI().profile?.key ?? "")) { InvenTreeAPI().disconnectFromServer(); } } Widget? _getProfileIcon(UserProfile profile) { - // Not selected? No icon for you! if (!profile.selected) return null; @@ -152,45 +149,38 @@ class _InvenTreeSelectServerState extends State { // Reflect the connection status of the server if (InvenTreeAPI().isConnected()) { - return Icon( - TablerIcons.circle_check, - color: COLOR_SUCCESS - ); + return Icon(TablerIcons.circle_check, color: COLOR_SUCCESS); } else if (InvenTreeAPI().isConnecting()) { - return Spinner( - icon: TablerIcons.loader_2, - color: COLOR_PROGRESS, - ); + return Spinner(icon: TablerIcons.loader_2, color: COLOR_PROGRESS); } else { - return Icon( - TablerIcons.circle_x, - color: COLOR_DANGER, - ); + return Icon(TablerIcons.circle_x, color: COLOR_DANGER); } } @override Widget build(BuildContext context) { - List children = []; if (profiles.isNotEmpty) { for (int idx = 0; idx < profiles.length; idx++) { UserProfile profile = profiles[idx]; - children.add(ListTile( - title: Text( - profile.name, - ), - tileColor: profile.selected ? Theme.of(context).secondaryHeaderColor : null, - subtitle: Text("${profile.server}"), - leading: profile.hasToken ? Icon(TablerIcons.user_check, color: COLOR_SUCCESS) : Icon(TablerIcons.user_cancel, color: COLOR_WARNING), - trailing: _getProfileIcon(profile), - onTap: () { - _selectProfile(context, profile); - }, - onLongPress: () { - OneContext().showDialog( + children.add( + ListTile( + title: Text(profile.name), + tileColor: profile.selected + ? Theme.of(context).secondaryHeaderColor + : null, + subtitle: Text("${profile.server}"), + leading: profile.hasToken + ? Icon(TablerIcons.user_check, color: COLOR_SUCCESS) + : Icon(TablerIcons.user_cancel, color: COLOR_WARNING), + trailing: _getProfileIcon(profile), + onTap: () { + _selectProfile(context, profile); + }, + onLongPress: () { + OneContext().showDialog( builder: (BuildContext context) { return SimpleDialog( title: Text(profile.name), @@ -204,7 +194,7 @@ class _InvenTreeSelectServerState extends State { child: ListTile( title: Text(L10().profileConnect), leading: Icon(TablerIcons.server), - ) + ), ), SimpleDialogOption( onPressed: () { @@ -213,8 +203,8 @@ class _InvenTreeSelectServerState extends State { }, child: ListTile( title: Text(L10().profileEdit), - leading: Icon(TablerIcons.edit) - ) + leading: Icon(TablerIcons.edit), + ), ), SimpleDialogOption( onPressed: () { @@ -224,7 +214,7 @@ class _InvenTreeSelectServerState extends State { child: ListTile( title: Text(L10().profileLogout), leading: Icon(TablerIcons.logout), - ) + ), ), Divider(), SimpleDialogOption( @@ -238,28 +228,28 @@ class _InvenTreeSelectServerState extends State { icon: TablerIcons.trash, onAccept: () { _deleteProfile(profile); - } + }, ); }, child: ListTile( - title: Text(L10().profileDelete, style: TextStyle(color: Colors.red)), + title: Text( + L10().profileDelete, + style: TextStyle(color: Colors.red), + ), leading: Icon(TablerIcons.trash, color: Colors.red), - ) - ) + ), + ), ], ); - } - ); - }, - )); + }, + ); + }, + ), + ); } } else { // No profile available! - children.add( - ListTile( - title: Text(L10().profileNone), - ) - ); + children.add(ListTile(title: Text(L10().profileNone))); } return Scaffold( @@ -273,27 +263,25 @@ class _InvenTreeSelectServerState extends State { onPressed: () { _editProfile(context, createNew: true); }, - ) + ), ], ), body: Container( child: ListView( children: ListTile.divideTiles( context: context, - tiles: children + tiles: children, ).toList(), - ) + ), ), ); } } - /* * Widget for editing server details */ class ProfileEditWidget extends StatefulWidget { - const ProfileEditWidget(this.profile) : super(); final UserProfile? profile; @@ -303,7 +291,6 @@ class ProfileEditWidget extends StatefulWidget { } class _ProfileEditState extends State { - _ProfileEditState() : super(); final formKey = GlobalKey(); @@ -316,7 +303,9 @@ class _ProfileEditState extends State { return Scaffold( appBar: AppBar( backgroundColor: COLOR_APP_BAR, - title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), + title: Text( + widget.profile == null ? L10().profileAdd : L10().profileEdit, + ), actions: [ IconButton( icon: Icon(TablerIcons.circle_check), @@ -327,14 +316,10 @@ class _ProfileEditState extends State { UserProfile? prf = widget.profile; if (prf == null) { - UserProfile profile = UserProfile( - name: name, - server: server, - ); + UserProfile profile = UserProfile(name: name, server: server); await UserProfileDBManager().addProfile(profile); } else { - prf.name = name; prf.server = server; @@ -345,8 +330,8 @@ class _ProfileEditState extends State { Navigator.of(context).pop(); } }, - ) - ] + ), + ], ), body: Form( key: formKey, @@ -373,7 +358,7 @@ class _ProfileEditState extends State { } return null; - } + }, ), TextFormField( decoration: InputDecoration( @@ -398,7 +383,8 @@ class _ProfileEditState extends State { return L10().invalidHost; } - if (!value.startsWith("http:") && !value.startsWith("https:")) { + if (!value.startsWith("http:") && + !value.startsWith("https:")) { // return L10().serverStart; } @@ -410,7 +396,10 @@ class _ProfileEditState extends State { Uri uri = Uri.parse(value); if (uri.hasScheme) { - if (!["http", "https"].contains(uri.scheme.toLowerCase())) { + if (![ + "http", + "https", + ].contains(uri.scheme.toLowerCase())) { return L10().serverStart; } } else { @@ -422,12 +411,11 @@ class _ProfileEditState extends State { return null; }, ), - ] + ], ), padding: EdgeInsets.all(16), ), - ) + ), ); } - -} \ No newline at end of file +} diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 30f4f2b..12b51af 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -16,15 +16,11 @@ import "package:inventree/settings/sales_order_settings.dart"; // InvenTree settings view class InvenTreeSettingsWidget extends StatefulWidget { - @override _InvenTreeSettingsState createState() => _InvenTreeSettingsState(); - } - class _InvenTreeSettingsState extends State { - final _scaffoldKey = GlobalKey(); /* @@ -32,8 +28,10 @@ class _InvenTreeSettingsState extends State { */ Future _about() async { PackageInfo.fromPlatform().then((PackageInfo info) { - Navigator.push(context, - MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info))); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info)), + ); }); } @@ -48,72 +46,108 @@ class _InvenTreeSettingsState extends State { body: Center( child: ListView( children: [ - ListTile( - title: Text(L10().server), - subtitle: Text(L10().configureServer), - leading: Icon(TablerIcons.server, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget())); - }, - ), - Divider(), - ListTile( - title: Text(L10().appSettings), - subtitle: Text(L10().appSettingsDetails), - leading: Icon(TablerIcons.settings, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); - } - ), - ListTile( - title: Text(L10().homeScreen), - subtitle: Text(L10().homeScreenSettings), - leading: Icon(TablerIcons.home, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); - } - ), - ListTile( - title: Text(L10().barcodes), - subtitle: Text(L10().barcodeSettings), - leading: Icon(TablerIcons.barcode, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeBarcodeSettingsWidget())); - } - ), - ListTile( - title: Text(L10().part), - subtitle: Text(L10().partSettings), - leading: Icon(TablerIcons.box, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePartSettingsWidget())); - } - ), - ListTile( - title: Text(L10().purchaseOrder), - subtitle: Text(L10().purchaseOrderSettings), - leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreePurchaseOrderSettingsWidget())); - }, - ), - ListTile( - title: Text(L10().salesOrder), - subtitle: Text(L10().salesOrderSettings), - leading: Icon(TablerIcons.truck, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSalesOrderSettingsWidget())); - }, - ), - Divider(), - ListTile( - title: Text(L10().about), - leading: Icon(TablerIcons.info_circle, color: COLOR_ACTION), - onTap: _about, - ) - ] - ) - ) + ListTile( + title: Text(L10().server), + subtitle: Text(L10().configureServer), + leading: Icon(TablerIcons.server, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeSelectServerWidget(), + ), + ); + }, + ), + Divider(), + ListTile( + title: Text(L10().appSettings), + subtitle: Text(L10().appSettingsDetails), + leading: Icon(TablerIcons.settings, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeAppSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().homeScreen), + subtitle: Text(L10().homeScreenSettings), + leading: Icon(TablerIcons.home, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => HomeScreenSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().barcodes), + subtitle: Text(L10().barcodeSettings), + leading: Icon(TablerIcons.barcode, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeBarcodeSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().part), + subtitle: Text(L10().partSettings), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreePartSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().purchaseOrder), + subtitle: Text(L10().purchaseOrderSettings), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + InvenTreePurchaseOrderSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().salesOrder), + subtitle: Text(L10().salesOrderSettings), + leading: Icon(TablerIcons.truck, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeSalesOrderSettingsWidget(), + ), + ); + }, + ), + Divider(), + ListTile( + title: Text(L10().about), + leading: Icon(TablerIcons.info_circle, color: COLOR_ACTION), + onTap: _about, + ), + ], + ), + ), ); } -} \ No newline at end of file +} diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 9d17b06..f53b412 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -1,11 +1,9 @@ - import "package:sembast/sembast.dart"; import "package:inventree/helpers.dart"; import "package:inventree/preferences.dart"; class UserProfile { - UserProfile({ this.key, this.name = "", @@ -14,7 +12,11 @@ class UserProfile { this.selected = false, }); - factory UserProfile.fromJson(int key, Map json, bool isSelected) => UserProfile( + factory UserProfile.fromJson( + int key, + Map json, + bool isSelected, + ) => UserProfile( key: key, name: (json["name"] ?? "") as String, server: (json["server"] ?? "") as String, @@ -58,7 +60,6 @@ class UserProfile { * Class for storing and managing user (server) profiles */ class UserProfileDBManager { - final store = StoreRef("profiles"); Future get _db async => InvenTreePreferencesDB.instance.database; @@ -67,7 +68,6 @@ class UserProfileDBManager { * Check if a profile with the specified name exists in the database */ Future profileNameExists(String name) async { - final profiles = await getAllProfiles(); for (var prf in profiles) { @@ -84,9 +84,10 @@ class UserProfileDBManager { * Add a new UserProfile to the profiles database. */ Future addProfile(UserProfile profile) async { - if (profile.name.isEmpty) { - debug("addProfile() : Profile missing required values - not adding to database"); + debug( + "addProfile() : Profile missing required values - not adding to database", + ); return false; } @@ -113,7 +114,6 @@ class UserProfileDBManager { * The unique integer is used to determine if the profile already exists. */ Future updateProfile(UserProfile profile) async { - // Prevent invalid profile data from being updated if (profile.name.isEmpty) { debug("updateProfile() : Profile missing required values - not updating"); @@ -144,15 +144,15 @@ class UserProfileDBManager { * The key of the UserProfile should match the "selected" property */ Future getSelectedProfile() async { - final selected = await store.record("selected").get(await _db); final profiles = await store.find(await _db); - debug("getSelectedProfile() : ${profiles.length} profiles available - selected = ${selected}"); + debug( + "getSelectedProfile() : ${profiles.length} profiles available - selected = ${selected}", + ); for (int idx = 0; idx < profiles.length; idx++) { - if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( profiles[idx].key! as int, @@ -169,7 +169,6 @@ class UserProfileDBManager { * Return all user profile objects */ Future> getAllProfiles() async { - final selected = await store.record("selected").get(await _db); final profiles = await store.find(await _db); @@ -177,25 +176,26 @@ class UserProfileDBManager { List profileList = []; for (int idx = 0; idx < profiles.length; idx++) { - if (profiles[idx].key is int) { profileList.add( UserProfile.fromJson( profiles[idx].key! as int, profiles[idx].value! as Map, profiles[idx].key == selected, - ) + ), ); } } // If there are no available profiles, create a demo profile if (profileList.isEmpty) { - bool added = await InvenTreeSettingsManager().getBool("demo_profile_added", false); + bool added = await InvenTreeSettingsManager().getBool( + "demo_profile_added", + false, + ); // Don't add a new profile if we have added it previously if (!added) { - await InvenTreeSettingsManager().setValue("demo_profile_added", true); UserProfile demoProfile = UserProfile( @@ -212,7 +212,6 @@ class UserProfileDBManager { return profileList; } - /* * Retrieve a profile by key (or null if no match exists) */ @@ -231,7 +230,6 @@ class UserProfileDBManager { return prf; } - /* * Retrieve a profile by name (or null if no match exists) */ diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index f92fbb6..b4c9746 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -1,4 +1,3 @@ - import "dart:io"; import "package:flutter/material.dart"; @@ -17,7 +16,6 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/refreshable_state.dart"; - /* * A generic widget for displaying a list of attachments. * @@ -25,8 +23,12 @@ import "package:inventree/widget/refreshable_state.dart"; * we pass a subclassed instance of the InvenTreeAttachment model. */ class AttachmentWidget extends StatefulWidget { - - const AttachmentWidget(this.attachmentClass, this.modelId, this.imagePrefix, this.hasUploadPermission) : super(); + const AttachmentWidget( + this.attachmentClass, + this.modelId, + this.imagePrefix, + this.hasUploadPermission, + ) : super(); final InvenTreeAttachment attachmentClass; final int modelId; @@ -37,9 +39,7 @@ class AttachmentWidget extends StatefulWidget { _AttachmentWidgetState createState() => _AttachmentWidgetState(); } - class _AttachmentWidgetState extends RefreshableState { - _AttachmentWidgetState(); List attachments = []; @@ -64,7 +64,7 @@ class _AttachmentWidgetState extends RefreshableState { refresh(context); }); }); - } + }, ), IconButton( icon: Icon(TablerIcons.file_upload), @@ -74,20 +74,19 @@ class _AttachmentWidgetState extends RefreshableState { refresh(context); }); }); - } - ) + }, + ), ]; } Future upload(BuildContext context, File? file) async { - if (file == null) return; showLoadingOverlay(); final bool result = await widget.attachmentClass.uploadAttachment( - file, - widget.modelId + file, + widget.modelId, ); hideLoadingOverlay(); @@ -101,35 +100,39 @@ class _AttachmentWidgetState extends RefreshableState { refresh(context); } - - Future editAttachment(BuildContext context, InvenTreeAttachment attachment) async - { - attachment.editForm(context, L10().editAttachment).then((result) => { - refresh(context) - }); + Future editAttachment( + BuildContext context, + InvenTreeAttachment attachment, + ) async { + attachment + .editForm(context, L10().editAttachment) + .then((result) => {refresh(context)}); } /* * Delete the specified attachment */ - Future deleteAttachment(BuildContext context, InvenTreeAttachment attachment) async { - + Future deleteAttachment( + BuildContext context, + InvenTreeAttachment attachment, + ) async { final bool result = await attachment.delete(); showSnackIcon( result ? L10().deleteSuccess : L10().deleteFailed, - success: result + success: result, ); refresh(context); - } /* * Display an option context menu for the selected attachment */ - Future showOptionsMenu(BuildContext context, InvenTreeAttachment attachment) async { - + Future showOptionsMenu( + BuildContext context, + InvenTreeAttachment attachment, + ) async { OneContext().showDialog( builder: (BuildContext ctx) { return SimpleDialog( @@ -144,7 +147,7 @@ class _AttachmentWidgetState extends RefreshableState { child: ListTile( title: Text(L10().edit), leading: Icon(TablerIcons.edit), - ) + ), ), SimpleDialogOption( onPressed: () async { @@ -154,29 +157,27 @@ class _AttachmentWidgetState extends RefreshableState { child: ListTile( title: Text(L10().delete), leading: Icon(TablerIcons.trash, color: COLOR_DANGER), - ) - ) - ] + ), + ), + ], ); - } + }, ); } @override Future request(BuildContext context) async { - Map filters = {}; if (InvenTreeAPI().supportsModernAttachments) { filters["model_type"] = widget.attachmentClass.REF_MODEL_TYPE; filters["model_id"] = widget.modelId.toString(); } else { - filters[widget.attachmentClass.REFERENCE_FIELD] = widget.modelId.toString(); + filters[widget.attachmentClass.REFERENCE_FIELD] = widget.modelId + .toString(); } - await widget.attachmentClass.list( - filters: filters - ).then((var results) { + await widget.attachmentClass.list(filters: filters).then((var results) { attachments.clear(); for (var result in results) { @@ -186,57 +187,58 @@ class _AttachmentWidgetState extends RefreshableState { } }); - setState(() { - }); + setState(() {}); } @override List getTiles(BuildContext context) { - List tiles = []; // An "attachment" can either be a file, or a URL for (var attachment in attachments) { - if (attachment.filename.isNotEmpty) { - tiles.add(ListTile( - title: Text(attachment.filename), - subtitle: Text(attachment.comment), - leading: Icon(attachment.icon, color: COLOR_ACTION), - onTap: () async { - showLoadingOverlay(); - await attachment.downloadAttachment(); - hideLoadingOverlay(); - }, - onLongPress: () { - showOptionsMenu(context, attachment); - }, - )); - } - - else if (attachment.link.isNotEmpty) { - tiles.add(ListTile( - title: Text(attachment.link), - subtitle: Text(attachment.comment), - leading: Icon(TablerIcons.link, color: COLOR_ACTION), - onTap: () async { - var uri = Uri.tryParse(attachment.link.trimLeft()); - if (uri != null && await canLaunchUrl(uri)) { - await launchUrl(uri); - } - }, - onLongPress: () { - showOptionsMenu(context, attachment); - }, - )); + tiles.add( + ListTile( + title: Text(attachment.filename), + subtitle: Text(attachment.comment), + leading: Icon(attachment.icon, color: COLOR_ACTION), + onTap: () async { + showLoadingOverlay(); + await attachment.downloadAttachment(); + hideLoadingOverlay(); + }, + onLongPress: () { + showOptionsMenu(context, attachment); + }, + ), + ); + } else if (attachment.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text(attachment.link), + subtitle: Text(attachment.comment), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () async { + var uri = Uri.tryParse(attachment.link.trimLeft()); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); + } + }, + onLongPress: () { + showOptionsMenu(context, attachment); + }, + ), + ); } } if (tiles.isEmpty) { - tiles.add(ListTile( - leading: Icon(TablerIcons.file_x, color: COLOR_WARNING), - title: Text(L10().attachmentNone), - )); + tiles.add( + ListTile( + leading: Icon(TablerIcons.file_x, color: COLOR_WARNING), + title: Text(L10().attachmentNone), + ), + ); } return tiles; diff --git a/lib/widget/back.dart b/lib/widget/back.dart index 27a9c23..f5d342a 100644 --- a/lib/widget/back.dart +++ b/lib/widget/back.dart @@ -6,7 +6,6 @@ import "package:flutter/material.dart"; * Long-pressing on this will return the user to the home screen */ Widget backButton(BuildContext context, GlobalKey key) { - return GestureDetector( onLongPress: () { // Display the menu @@ -21,4 +20,4 @@ Widget backButton(BuildContext context, GlobalKey key) { }, ), ); -} \ No newline at end of file +} diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart index 1007386..076a1e6 100644 --- a/lib/widget/company/company_detail.dart +++ b/lib/widget/company/company_detail.dart @@ -16,24 +16,19 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/company/supplier_part_list.dart"; - /* * Widget for displaying detail view of a single Company instance */ class CompanyDetailWidget extends StatefulWidget { - const CompanyDetailWidget(this.company, {Key? key}) : super(key: key); final InvenTreeCompany company; @override _CompanyDetailState createState() => _CompanyDetailState(); - } - class _CompanyDetailState extends RefreshableState { - _CompanyDetailState(); int supplierPartCount = 0; @@ -61,15 +56,15 @@ class _CompanyDetailState extends RefreshableState { if (InvenTreeCompany().canEdit) { actions.add( IconButton( - icon: Icon(TablerIcons.edit), - tooltip: L10().companyEdit, - onPressed: () { - editCompany(context); - } - ) + icon: Icon(TablerIcons.edit), + tooltip: L10().companyEdit, + onPressed: () { + editCompany(context); + }, + ), ); } - + return actions; } @@ -78,23 +73,27 @@ class _CompanyDetailState extends RefreshableState { List actions = []; if (widget.company.isCustomer && InvenTreeSalesOrder().canCreate) { - actions.add(SpeedDialChild( - child: Icon(TablerIcons.truck), - label: L10().salesOrderCreate, - onTap: () async { - _createSalesOrder(context); - } - )); + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.truck), + label: L10().salesOrderCreate, + onTap: () async { + _createSalesOrder(context); + }, + ), + ); } if (widget.company.isSupplier && InvenTreePurchaseOrder().canCreate) { - actions.add(SpeedDialChild( - child: Icon(TablerIcons.shopping_cart), - label: L10().purchaseOrderCreate, - onTap: () async { - _createPurchaseOrder(context); - } - )); + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.shopping_cart), + label: L10().purchaseOrderCreate, + onTap: () async { + _createPurchaseOrder(context); + }, + ), + ); } return actions; @@ -109,17 +108,17 @@ class _CompanyDetailState extends RefreshableState { fields["customer"]?["value"] = widget.company.pk; InvenTreeSalesOrder().createForm( - context, - L10().salesOrderCreate, - fields: fields, - onSuccess: (result) async { - Map data = result as Map; + context, + L10().salesOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; - if (data.containsKey("pk")) { - var order = InvenTreeSalesOrder.fromJson(data); - order.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var order = InvenTreeSalesOrder.fromJson(data); + order.goToDetailPage(context); } + }, ); } @@ -132,17 +131,17 @@ class _CompanyDetailState extends RefreshableState { fields["supplier"]?["value"] = widget.company.pk; InvenTreePurchaseOrder().createForm( - context, - L10().purchaseOrderCreate, - fields: fields, - onSuccess: (result) async { - Map data = result as Map; + context, + L10().purchaseOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; - if (data.containsKey("pk")) { - var order = InvenTreePurchaseOrder.fromJson(data); - order.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var order = InvenTreePurchaseOrder.fromJson(data); + order.goToDetailPage(context); } + }, ); } @@ -156,32 +155,37 @@ class _CompanyDetailState extends RefreshableState { return; } - outstandingPurchaseOrders = widget.company.isSupplier ? - await InvenTreePurchaseOrder().count(filters: { - "supplier": widget.company.pk.toString(), - "outstanding": "true" - }) : 0; + outstandingPurchaseOrders = widget.company.isSupplier + ? await InvenTreePurchaseOrder().count( + filters: { + "supplier": widget.company.pk.toString(), + "outstanding": "true", + }, + ) + : 0; - outstandingSalesOrders = widget.company.isCustomer ? - await InvenTreeSalesOrder().count(filters: { - "customer": widget.company.pk.toString(), - "outstanding": "true" - }) : 0; - - InvenTreeSupplierPart().count( - filters: { - "supplier": widget.company.pk.toString() - } - ).then((value) { - if (mounted) { - setState(() { - supplierPartCount = value; + outstandingSalesOrders = widget.company.isCustomer + ? await InvenTreeSalesOrder().count( + filters: { + "customer": widget.company.pk.toString(), + "outstanding": "true", + }, + ) + : 0; + + InvenTreeSupplierPart() + .count(filters: {"supplier": widget.company.pk.toString()}) + .then((value) { + if (mounted) { + setState(() { + supplierPartCount = value; + }); + } }); - } - }); - InvenTreeCompanyAttachment().countAttachments(widget.company.pk) - .then((value) { + InvenTreeCompanyAttachment().countAttachments(widget.company.pk).then(( + value, + ) { if (mounted) { setState(() { attachmentCount = value; @@ -190,15 +194,14 @@ class _CompanyDetailState extends RefreshableState { }); } - Future editCompany(BuildContext context) async { - + Future editCompany(BuildContext context) async { widget.company.editForm( context, L10().companyEdit, onSuccess: (data) async { refresh(context); showSnackIcon(L10().companyUpdated, success: true); - } + }, ); } @@ -207,87 +210,86 @@ class _CompanyDetailState extends RefreshableState { */ @override List getTiles(BuildContext context) { - List tiles = []; bool sep = false; - tiles.add(Card( - child: ListTile( - title: Text("${widget.company.name}"), - subtitle: Text("${widget.company.description}"), - leading: InvenTreeAPI().getThumbnail(widget.company.image), + tiles.add( + Card( + child: ListTile( + title: Text("${widget.company.name}"), + subtitle: Text("${widget.company.description}"), + leading: InvenTreeAPI().getThumbnail(widget.company.image), + ), ), - )); + ); if (!widget.company.active) { tiles.add( - ListTile( - title: Text( - L10().inactive, - style: TextStyle( - color: COLOR_DANGER - ) - ), - subtitle: Text( - L10().inactiveCompany, - style: TextStyle( - color: COLOR_DANGER - ) - ), - leading: Icon( - TablerIcons.exclamation_circle, - color: COLOR_DANGER - ), - ) + ListTile( + title: Text(L10().inactive, style: TextStyle(color: COLOR_DANGER)), + subtitle: Text( + L10().inactiveCompany, + style: TextStyle(color: COLOR_DANGER), + ), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + ), ); } - if (widget.company.website.isNotEmpty) { - tiles.add(ListTile( - title: Text("${widget.company.website}"), - leading: Icon(TablerIcons.globe, color: COLOR_ACTION), - onTap: () async { - openLink(widget.company.website); - }, - )); + if (widget.company.website.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${widget.company.website}"), + leading: Icon(TablerIcons.globe, color: COLOR_ACTION), + onTap: () async { + openLink(widget.company.website); + }, + ), + ); - sep = true; - } + sep = true; + } - if (widget.company.email.isNotEmpty) { - tiles.add(ListTile( - title: Text("${widget.company.email}"), - leading: Icon(TablerIcons.at, color: COLOR_ACTION), - onTap: () async { - openLink("mailto:${widget.company.email}"); - }, - )); + if (widget.company.email.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${widget.company.email}"), + leading: Icon(TablerIcons.at, color: COLOR_ACTION), + onTap: () async { + openLink("mailto:${widget.company.email}"); + }, + ), + ); - sep = true; - } + sep = true; + } - if (widget.company.phone.isNotEmpty) { - tiles.add(ListTile( - title: Text("${widget.company.phone}"), - leading: Icon(TablerIcons.phone, color: COLOR_ACTION), - onTap: () { - openLink("tel:${widget.company.phone}"); - }, - )); + if (widget.company.phone.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${widget.company.phone}"), + leading: Icon(TablerIcons.phone, color: COLOR_ACTION), + onTap: () { + openLink("tel:${widget.company.phone}"); + }, + ), + ); - sep = true; - } + sep = true; + } // External link if (widget.company.link.isNotEmpty) { - tiles.add(ListTile( - title: Text("${widget.company.link}"), - leading: Icon(TablerIcons.link, color: COLOR_ACTION), - onTap: () { - widget.company.openLink(); - }, - )); + tiles.add( + ListTile( + title: Text("${widget.company.link}"), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () { + widget.company.openLink(); + }, + ), + ); sep = true; } @@ -297,7 +299,6 @@ class _CompanyDetailState extends RefreshableState { } if (widget.company.isSupplier) { - if (supplierPartCount > 0) { tiles.add( ListTile( @@ -309,12 +310,12 @@ class _CompanyDetailState extends RefreshableState { context, MaterialPageRoute( builder: (context) => SupplierPartList({ - "supplier": widget.company.pk.toString() - }) - ) + "supplier": widget.company.pk.toString(), + }), + ), ); - } - ) + }, + ), ); } @@ -328,14 +329,12 @@ class _CompanyDetailState extends RefreshableState { context, MaterialPageRoute( builder: (context) => PurchaseOrderListWidget( - filters: { - "supplier": "${widget.company.pk}" - } - ) - ) + filters: {"supplier": "${widget.company.pk}"}, + ), + ), ); - } - ) + }, + ), ); // TODO: Display "supplied parts" count (click through to list of supplier parts) @@ -365,46 +364,46 @@ class _CompanyDetailState extends RefreshableState { context, MaterialPageRoute( builder: (context) => SalesOrderListWidget( - filters: { - "customer": widget.company.pk.toString() - } - ) - ) + filters: {"customer": widget.company.pk.toString()}, + ), + ), ); - } - ) + }, + ), ); } if (widget.company.notes.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().notes), - leading: Icon(TablerIcons.note), - onTap: null, - )); + tiles.add( + ListTile( + title: Text(L10().notes), + leading: Icon(TablerIcons.note), + onTap: null, + ), + ); } - - tiles.add(ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeCompanyAttachment(), - widget.company.pk, - widget.company.name, - InvenTreeCompany().canEdit - ) - ) - ); - } - )); + tiles.add( + ListTile( + title: Text(L10().attachments), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeCompanyAttachment(), + widget.company.pk, + widget.company.name, + InvenTreeCompany().canEdit, + ), + ), + ); + }, + ), + ); return tiles; } - -} \ No newline at end of file +} diff --git a/lib/widget/company/company_list.dart b/lib/widget/company/company_list.dart index 8b0f03c..69b851d 100644 --- a/lib/widget/company/company_list.dart +++ b/lib/widget/company/company_list.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -12,13 +11,12 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; - /* * Widget for displaying a filterable list of Company instances */ class CompanyListWidget extends StatefulWidget { - - const CompanyListWidget(this.title, this.filters, {Key? key}) : super(key: key); + const CompanyListWidget(this.title, this.filters, {Key? key}) + : super(key: key); final String title; @@ -28,16 +26,13 @@ class CompanyListWidget extends StatefulWidget { _CompanyListWidgetState createState() => _CompanyListWidgetState(); } - class _CompanyListWidgetState extends RefreshableState { - _CompanyListWidgetState(); @override String getAppBarTitle() => widget.title; Future _addCompany(BuildContext context) async { - InvenTreeCompany().createForm( context, L10().companyAdd, @@ -49,7 +44,7 @@ class _CompanyListWidgetState extends RefreshableState { var company = InvenTreeCompany.fromJson(data); company.goToDetailPage(context); } - } + }, ); } @@ -59,13 +54,13 @@ class _CompanyListWidgetState extends RefreshableState { if (InvenTreeAPI().checkPermission("company", "add")) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.circle_plus, color: Colors.green), - label: L10().companyAdd, - onTap: () { - _addCompany(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().companyAdd, + onTap: () { + _addCompany(context); + }, + ), ); } @@ -76,12 +71,11 @@ class _CompanyListWidgetState extends RefreshableState { Widget getBody(BuildContext context) { return PaginatedCompanyList(widget.title, widget.filters); } - } class PaginatedCompanyList extends PaginatedSearchWidget { - - const PaginatedCompanyList(this.companyTitle, Map filters) : super(filters: filters); + const PaginatedCompanyList(this.companyTitle, Map filters) + : super(filters: filters); final String companyTitle; @@ -93,12 +87,10 @@ class PaginatedCompanyList extends PaginatedSearchWidget { } class _CompanyListState extends PaginatedSearchState { - _CompanyListState() : super(); @override Map> get filterOptions { - Map> filters = {}; if (InvenTreeAPI().supportsCompanyActiveStatus) { @@ -113,16 +105,22 @@ class _CompanyListState extends PaginatedSearchState { } @override - Future requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreeCompany().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeCompany().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeCompany company = model as InvenTreeCompany; return ListTile( diff --git a/lib/widget/company/manufacturer_part_detail.dart b/lib/widget/company/manufacturer_part_detail.dart index 6d8fd09..5267a31 100644 --- a/lib/widget/company/manufacturer_part_detail.dart +++ b/lib/widget/company/manufacturer_part_detail.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -19,19 +18,18 @@ import "package:url_launcher/url_launcher.dart"; * Detail widget for viewing a single ManufacturerPart instance */ class ManufacturerPartDetailWidget extends StatefulWidget { - const ManufacturerPartDetailWidget(this.manufacturerPart, {Key? key}) - : super(key: key); + : super(key: key); final InvenTreeManufacturerPart manufacturerPart; @override - _ManufacturerPartDisplayState createState() => _ManufacturerPartDisplayState(); + _ManufacturerPartDisplayState createState() => + _ManufacturerPartDisplayState(); } - -class _ManufacturerPartDisplayState extends RefreshableState { - +class _ManufacturerPartDisplayState + extends RefreshableState { _ManufacturerPartDisplayState(); @override @@ -39,7 +37,8 @@ class _ManufacturerPartDisplayState extends RefreshableState request(BuildContext context) async { - final bool result = widget.manufacturerPart.pk > 0 && + final bool result = + widget.manufacturerPart.pk > 0 && await widget.manufacturerPart.reload(); if (!result) { @@ -49,12 +48,12 @@ class _ManufacturerPartDisplayState extends RefreshableState editManufacturerPart(BuildContext context) async { widget.manufacturerPart.editForm( - context, - L10().manufacturerPartEdit, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().itemUpdated, success: true); - } + context, + L10().manufacturerPartEdit, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().itemUpdated, success: true); + }, ); } @@ -73,13 +72,13 @@ class _ManufacturerPartDisplayState extends RefreshableState _SupplierPartDisplayState(); } - -class _SupplierPartDisplayState extends RefreshableState { - +class _SupplierPartDisplayState + extends RefreshableState { _SupplierPartDisplayState(); @override @@ -44,12 +42,12 @@ class _SupplierPartDisplayState extends RefreshableState editSupplierPart(BuildContext context) async { widget.supplierPart.editForm( - context, - L10().supplierPartEdit, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().supplierPartUpdated, success: true); - } + context, + L10().supplierPartEdit, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().supplierPartUpdated, success: true); + }, ); } @@ -60,11 +58,12 @@ class _SupplierPartDisplayState extends RefreshableState request(BuildContext context) async { - final bool result = widget.supplierPart.pk > 0 && await widget.supplierPart.reload(); + final bool result = + widget.supplierPart.pk > 0 && await widget.supplierPart.reload(); if (!result) { Navigator.of(context).pop(); @@ -113,43 +113,33 @@ class _SupplierPartDisplayState extends RefreshableState ManufacturerPartDetailWidget(manufacturerPart) - )); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ManufacturerPartDetailWidget(manufacturerPart), + ), + ); } }, - ) + ), ); } // Packaging - if (widget.supplierPart.packaging.isNotEmpty || widget.supplierPart.pack_quantity.isNotEmpty) { + if (widget.supplierPart.packaging.isNotEmpty || + widget.supplierPart.pack_quantity.isNotEmpty) { tiles.add( ListTile( title: Text(L10().packaging), - subtitle: widget.supplierPart.packaging.isNotEmpty ? Text(widget.supplierPart.packaging) : null, + subtitle: widget.supplierPart.packaging.isNotEmpty + ? Text(widget.supplierPart.packaging) + : null, leading: Icon(TablerIcons.package), - trailing: widget.supplierPart.pack_quantity.isNotEmpty ? Text(widget.supplierPart.pack_quantity) : null, - ) + trailing: widget.supplierPart.pack_quantity.isNotEmpty + ? Text(widget.supplierPart.pack_quantity) + : null, + ), ); } @@ -244,7 +253,7 @@ class _SupplierPartDisplayState extends RefreshableState filters; @@ -24,9 +22,7 @@ class SupplierPartList extends StatefulWidget { _SupplierPartListState createState() => _SupplierPartListState(); } - class _SupplierPartListState extends RefreshableState { - @override String getAppBarTitle() => L10().supplierParts; @@ -34,25 +30,22 @@ class _SupplierPartListState extends RefreshableState { Widget getBody(BuildContext context) { return PaginatedSupplierPartList(widget.filters); } - } - class PaginatedSupplierPartList extends PaginatedSearchWidget { - - const PaginatedSupplierPartList(Map filters) : super(filters: filters); + const PaginatedSupplierPartList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().supplierParts; @override - _PaginatedSupplierPartListState createState() => _PaginatedSupplierPartListState(); - + _PaginatedSupplierPartListState createState() => + _PaginatedSupplierPartListState(); } - -class _PaginatedSupplierPartListState extends PaginatedSearchState { - +class _PaginatedSupplierPartListState + extends PaginatedSearchState { _PaginatedSupplierPartListState() : super(); @override @@ -63,7 +56,6 @@ class _PaginatedSupplierPartListState extends PaginatedSearchState> get filterOptions { - Map> filters = {}; if (InvenTreeAPI().supportsCompanyActiveStatus) { @@ -78,8 +70,16 @@ class _PaginatedSupplierPartListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - final page = await InvenTreeSupplierPart().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeSupplierPart().listPaginated( + limit, + offset, + filters: params, + ); return page; } @@ -96,10 +96,10 @@ class _PaginatedSupplierPartListState extends PaginatedSearchState SupplierPartDetailWidget(supplierPart) - ) + builder: (context) => SupplierPartDetailWidget(supplierPart), + ), ); }, ); } -} \ No newline at end of file +} diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index f92bac3..feb267e 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -9,12 +9,14 @@ import "package:inventree/l10.dart"; import "package:inventree/preferences.dart"; import "package:inventree/widget/snacks.dart"; - /* * Launch a dialog allowing the user to select from a list of options */ -Future choiceDialog(String title, List items, {Function? onSelected}) async { - +Future choiceDialog( + String title, + List items, { + Function? onSelected, +}) async { List choices = []; for (int idx = 0; idx < items.length; idx++) { @@ -27,7 +29,7 @@ Future choiceDialog(String title, List items, {Function? onSelecte onSelected(idx); } }, - ) + ), ); } @@ -39,31 +41,33 @@ Future choiceDialog(String title, List items, {Function? onSelecte builder: (BuildContext context) { return AlertDialog( title: Text(title), - content: SingleChildScrollView( - child: Column( - children: choices, - ) - ), + content: SingleChildScrollView(child: Column(children: choices)), actions: [ TextButton( child: Text(L10().cancel), onPressed: () { Navigator.pop(context); }, - ) + ), ], ); - } + }, ); - } - /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ -Future confirmationDialog(String title, String text, {Color? color, IconData icon = TablerIcons.help_circle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { - +Future confirmationDialog( + String title, + String text, { + Color? color, + IconData icon = TablerIcons.help_circle, + String? acceptText, + String? rejectText, + Function? onAccept, + Function? onReject, +}) async { String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; @@ -90,7 +94,7 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa if (onReject != null) { onReject(); } - } + }, ), TextButton( child: Text(_accept), @@ -102,14 +106,13 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa onAccept(); } }, - ) - ] + ), + ], ); - } + }, ); } - /* * Construct an error dialog showing information to the user * @@ -117,24 +120,23 @@ Future confirmationDialog(String title, String text, {Color? color, IconDa * @description = Simple string description of error * @data = Error response (e.g from server) */ -Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = TablerIcons.exclamation_circle, Function? onDismissed}) async { - +Future showErrorDialog( + String title, { + String description = "", + APIResponse? response, + IconData icon = TablerIcons.exclamation_circle, + Function? onDismissed, +}) async { List children = []; if (description.isNotEmpty) { - children.add( - ListTile( - title: Text(description), - ) - ); + children.add(ListTile(title: Text(description))); } else if (response != null) { // Look for extra error information in the provided APIResponse object switch (response.statusCode) { - case 400: // Bad request (typically bad input) + case 400: // Bad request (typically bad input) if (response.data is Map) { - for (String field in response.asMap().keys) { - dynamic error = response.data[field]; if (error is List) { @@ -143,15 +145,15 @@ Future showErrorDialog(String title, {String description = "", APIResponse ListTile( title: Text(field), subtitle: Text(error[ii].toString()), - ) + ), ); } } else { children.add( - ListTile( - title: Text(field), - subtitle: Text(response.data[field].toString()), - ) + ListTile( + title: Text(field), + subtitle: Text(response.data[field].toString()), + ), ); } } @@ -159,8 +161,8 @@ Future showErrorDialog(String title, {String description = "", APIResponse children.add( ListTile( title: Text(L10().responseInvalid), - subtitle: Text(response.data.toString()) - ) + subtitle: Text(response.data.toString()), + ), ); } default: @@ -169,16 +171,15 @@ Future showErrorDialog(String title, {String description = "", APIResponse ListTile( title: Text(L10().statusCode), subtitle: Text(response.statusCode.toString()), - ) + ), ); children.add( ListTile( title: Text(L10().responseData), subtitle: Text(response.data.toString()), - ) + ), ); - } } @@ -186,26 +187,28 @@ Future showErrorDialog(String title, {String description = "", APIResponse return; } - OneContext().showDialog( - builder: (context) => SimpleDialog( - title: ListTile( - title: Text(title), - leading: Icon(icon), - ), - children: children - ) - ).then((value) { - if (onDismissed != null) { - onDismissed(); - } - }); + OneContext() + .showDialog( + builder: (context) => SimpleDialog( + title: ListTile(title: Text(title), leading: Icon(icon)), + children: children, + ), + ) + .then((value) { + if (onDismissed != null) { + onDismissed(); + } + }); } /* * Display a message indicating the nature of a server / API error */ -Future showServerError(String url, String title, String description) async { - +Future showServerError( + String url, + String title, + String description, +) async { if (!hasContext()) { return; } @@ -220,7 +223,9 @@ Future showServerError(String url, String title, String description) async } // Play a sound - final bool tones = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; + final bool tones = + await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) + as bool; if (tones) { playAudioFile("sounds/server_error.mp3"); @@ -234,19 +239,22 @@ Future showServerError(String url, String title, String description) async actionText: L10().details, onAction: () { showErrorDialog( - title, - description: description, - icon: TablerIcons.server + title, + description: description, + icon: TablerIcons.server, ); - } + }, ); } /* * Displays an error indicating that the server returned an unexpected status code */ -Future showStatusCodeError(String url, int status, {String details=""}) async { - +Future showStatusCodeError( + String url, + int status, { + String details = "", +}) async { String msg = statusCodeToString(status); String extra = url + "\n" + "${L10().statusCode}: ${status}"; @@ -255,14 +263,9 @@ Future showStatusCodeError(String url, int status, {String details=""}) as extra += details; } - showServerError( - url, - msg, - extra, - ); + showServerError(url, msg, extra); } - /* * Provide a human-readable descriptor for a particular error code */ @@ -297,7 +300,6 @@ String statusCodeToString(int status) { } } - /* * Displays a message indicating that the server timed out on a certain request */ diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 2288e34..90bae32 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -16,12 +16,10 @@ import "package:inventree/widget/notifications.dart"; import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/stock/location_display.dart"; - /* * Custom "drawer" widget for the InvenTree app. */ class InvenTreeDrawer extends StatelessWidget { - const InvenTreeDrawer(this.context); final BuildContext context; @@ -53,8 +51,8 @@ class InvenTreeDrawer extends StatelessWidget { if (_checkConnection()) { Navigator.push( - context, - MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)) + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)), ); } } @@ -65,8 +63,8 @@ class InvenTreeDrawer extends StatelessWidget { if (_checkConnection()) { Navigator.push( - context, - MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)) + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)), ); } } @@ -77,24 +75,24 @@ class InvenTreeDrawer extends StatelessWidget { if (_checkConnection()) { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SalesOrderListWidget(filters: {}) - ) + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget(filters: {}), + ), ); } } - + // Load "purchase orders" page void _purchaseOrders() { _closeDrawer(); if (_checkConnection()) { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PurchaseOrderListWidget(filters: {}) - ) + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderListWidget(filters: {}), + ), ); } } @@ -104,15 +102,20 @@ class InvenTreeDrawer extends StatelessWidget { _closeDrawer(); if (_checkConnection()) { - Navigator.push(context, - MaterialPageRoute(builder: (context) => NotificationWidget())); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NotificationWidget()), + ); } } // Load settings widget void _settings() { _closeDrawer(); - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget())); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget()), + ); } // Construct list of tiles to display in the "drawer" menu @@ -120,14 +123,16 @@ class InvenTreeDrawer extends StatelessWidget { List tiles = []; // "Home" access - tiles.add(ListTile( - leading: Icon(TablerIcons.home, color: COLOR_ACTION), - title: Text( - L10().appTitle, - style: TextStyle(fontWeight: FontWeight.bold), + tiles.add( + ListTile( + leading: Icon(TablerIcons.home, color: COLOR_ACTION), + title: Text( + L10().appTitle, + style: TextStyle(fontWeight: FontWeight.bold), + ), + onTap: _home, ), - onTap: _home, - )); + ); tiles.add(Divider()); @@ -137,7 +142,7 @@ class InvenTreeDrawer extends StatelessWidget { title: Text(L10().parts), leading: Icon(TablerIcons.box, color: COLOR_ACTION), onTap: _parts, - ) + ), ); } @@ -147,7 +152,7 @@ class InvenTreeDrawer extends StatelessWidget { title: Text(L10().stock), leading: Icon(TablerIcons.package, color: COLOR_ACTION), onTap: _stock, - ) + ), ); } @@ -157,7 +162,7 @@ class InvenTreeDrawer extends StatelessWidget { title: Text(L10().purchaseOrders), leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), onTap: _purchaseOrders, - ) + ), ); } @@ -167,7 +172,7 @@ class InvenTreeDrawer extends StatelessWidget { title: Text(L10().salesOrders), leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), onTap: _salesOrders, - ) + ), ); } @@ -180,10 +185,12 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add( ListTile( leading: Icon(TablerIcons.bell, color: COLOR_ACTION), - trailing: notification_count > 0 ? Text(notification_count.toString()) : null, + trailing: notification_count > 0 + ? Text(notification_count.toString()) + : null, title: Text(L10().notifications), onTap: _notifications, - ) + ), ); tiles.add(Divider()); @@ -198,14 +205,9 @@ class InvenTreeDrawer extends StatelessWidget { }, title: Text(L10().colorScheme), subtitle: Text(L10().colorSchemeDetail), - leading: Icon( - TablerIcons.sun_moon, - color: COLOR_ACTION - ), - trailing: Icon( - darkMode ? TablerIcons.moon : TablerIcons.sun, - ) - ) + leading: Icon(TablerIcons.sun_moon, color: COLOR_ACTION), + trailing: Icon(darkMode ? TablerIcons.moon : TablerIcons.sun), + ), ); tiles.add( @@ -213,7 +215,7 @@ class InvenTreeDrawer extends StatelessWidget { title: Text(L10().settings), leading: Icon(Icons.settings, color: COLOR_ACTION), onTap: _settings, - ) + ), ); return tiles; @@ -221,11 +223,6 @@ class InvenTreeDrawer extends StatelessWidget { @override Widget build(BuildContext context) { - - return Drawer( - child: ListView( - children: drawerTiles(context), - ) - ); + return Drawer(child: ListView(children: drawerTiles(context))); } } diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index 8a7d600..406c0fe 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -9,11 +9,8 @@ import "package:one_context/one_context.dart"; import "package:inventree/l10.dart"; - class FilePickerDialog { - static Future pickImageFromCamera() async { - final picker = ImagePicker(); final pickedImage = await picker.pickImage(source: ImageSource.camera); @@ -26,7 +23,6 @@ class FilePickerDialog { } static Future pickImageFromGallery() async { - final picker = ImagePicker(); final pickedImage = await picker.pickImage(source: ImageSource.gallery); @@ -39,7 +35,6 @@ class FilePickerDialog { } static Future pickFileFromDevice() async { - final FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { @@ -54,8 +49,12 @@ class FilePickerDialog { } // Present a dialog to pick a file, either from local file system or from camera - static Future pickFile({String message = "", bool allowImages = true, bool allowFiles = true, Function(File)? onPicked}) async { - + static Future pickFile({ + String message = "", + bool allowImages = true, + bool allowFiles = true, + Function(File)? onPicked, + }) async { String title = ""; if (allowImages && !allowFiles) { @@ -65,16 +64,10 @@ class FilePickerDialog { } // Construct actions - List actions = [ - - ]; + List actions = []; if (message.isNotEmpty) { - actions.add( - ListTile( - title: Text(message) - ) - ); + actions.add(ListTile(title: Text(message))); } actions.add( @@ -84,7 +77,6 @@ class FilePickerDialog { title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { - // Close the dialog OneContext().popDialog(); @@ -101,7 +93,7 @@ class FilePickerDialog { } } }, - ) + ), ); if (allowImages) { @@ -122,100 +114,104 @@ class FilePickerDialog { onPicked(file); } } - } - ) + }, + ), ); } OneContext().showDialog( - builder: (context) { - return SimpleDialog( - title: Text(title), - children: actions, - ); - } + builder: (context) { + return SimpleDialog(title: Text(title), children: actions); + }, ); } - } - class CheckBoxField extends FormField { CheckBoxField({ - String? label, - bool? initial = false, - bool tristate = false, - Function(bool?)? onSaved, - TextStyle? labelStyle, - String? helperText, - TextStyle? helperStyle, - }) : - super( - onSaved: onSaved, - initialValue: initial, - builder: (FormFieldState state) { - - return CheckboxListTile( - title: label != null ? Text(label, style: labelStyle) : null, - value: state.value, - tristate: tristate, - onChanged: state.didChange, - subtitle: helperText != null ? Text(helperText, style: helperStyle) : null, - contentPadding: EdgeInsets.zero, - ); - } - ); + String? label, + bool? initial = false, + bool tristate = false, + Function(bool?)? onSaved, + TextStyle? labelStyle, + String? helperText, + TextStyle? helperStyle, + }) : super( + onSaved: onSaved, + initialValue: initial, + builder: (FormFieldState state) { + return CheckboxListTile( + title: label != null ? Text(label, style: labelStyle) : null, + value: state.value, + tristate: tristate, + onChanged: state.didChange, + subtitle: helperText != null + ? Text(helperText, style: helperStyle) + : null, + contentPadding: EdgeInsets.zero, + ); + }, + ); } class StringField extends TextFormField { + StringField({ + String label = "", + String? hint, + String? initial, + Function(String?)? onSaved, + Function(String?)? validator, + bool allowEmpty = false, + bool isEnabled = true, + }) : super( + decoration: InputDecoration( + labelText: allowEmpty ? label : label + "*", + hintText: hint, + ), + initialValue: initial, + onSaved: onSaved, + enabled: isEnabled, + validator: (value) { + if (!allowEmpty && value != null && value.isEmpty) { + return L10().valueCannotBeEmpty; + } - StringField({String label = "", String? hint, String? initial, Function(String?)? onSaved, Function(String?)? validator, bool allowEmpty = false, bool isEnabled = true}) : - super( - decoration: InputDecoration( - labelText: allowEmpty ? label : label + "*", - hintText: hint - ), - initialValue: initial, - onSaved: onSaved, - enabled: isEnabled, - validator: (value) { - if (!allowEmpty && value != null && value.isEmpty) { - return L10().valueCannotBeEmpty; - } + if (validator != null) { + return validator(value) as String?; + } - if (validator != null) { - return validator(value) as String?; - } - - return null; - } - ); + return null; + }, + ); } - /* * Helper class for quantity values */ class QuantityField extends TextFormField { + QuantityField({ + String label = "", + String hint = "", + double? max, + TextEditingController? controller, + }) : super( + decoration: InputDecoration(labelText: label, hintText: hint), + controller: controller, + keyboardType: TextInputType.numberWithOptions( + signed: false, + decimal: true, + ), + validator: (value) { + if (value != null && value.isEmpty) return L10().quantityEmpty; - QuantityField({String label = "", String hint = "", double? max, TextEditingController? controller}) : - super( - decoration: InputDecoration( - labelText: label, - hintText: hint, - ), - controller: controller, - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), - validator: (value) { + double quantity = double.tryParse(value.toString()) ?? 0; - if (value != null && value.isEmpty) return L10().quantityEmpty; + if (quantity <= 0) return L10().quantityPositive; + if ((max != null) && (quantity > max)) { + return "Quantity must not exceed ${max}"; + } - double quantity = double.tryParse(value.toString()) ?? 0; - - if (quantity <= 0) return L10().quantityPositive; - if ((max != null) && (quantity > max)) return "Quantity must not exceed ${max}"; - - return null; - }, - ); -} \ No newline at end of file + return null; + }, + ); +} diff --git a/lib/widget/home.dart b/lib/widget/home.dart index f7a8404..2a2b615 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -26,18 +26,15 @@ import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/spinner.dart"; import "package:inventree/widget/company/company_list.dart"; - class InvenTreeHomePage extends StatefulWidget { - const InvenTreeHomePage({Key? key}) : super(key: key); @override _InvenTreeHomePageState createState() => _InvenTreeHomePageState(); } - -class _InvenTreeHomePageState extends State with BaseWidgetProperties { - +class _InvenTreeHomePageState extends State + with BaseWidgetProperties { _InvenTreeHomePageState() : super() { // Load display settings _loadSettings(); @@ -46,7 +43,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr _loadProfile(); InvenTreeAPI().registerCallback(() { - if (mounted) { setState(() { // Reload the widget @@ -70,7 +66,10 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr void _showParts(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)), + ); } void _showStarredParts(BuildContext context) { @@ -78,18 +77,17 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr Navigator.push( context, - MaterialPageRoute( - builder: (context) => PartList({ - "starred": "true" - }) - ) + MaterialPageRoute(builder: (context) => PartList({"starred": "true"})), ); } void _showStock(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)), + ); } void _showPurchaseOrders(BuildContext context) { @@ -98,8 +96,8 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr Navigator.push( context, MaterialPageRoute( - builder: (context) => PurchaseOrderListWidget(filters: {}) - ) + builder: (context) => PurchaseOrderListWidget(filters: {}), + ), ); } @@ -107,17 +105,23 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr if (!InvenTreeAPI().checkConnection()) return; Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SalesOrderListWidget(filters: {}) - ) + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget(filters: {}), + ), ); } void _showSuppliers(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; - Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"}))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + CompanyListWidget(L10().suppliers, {"is_supplier": "true"}), + ), + ); } /* @@ -131,39 +135,60 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr void _showCustomers(BuildContext context) { if (!InvenTreeAPI().checkConnection()) return; - Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"}))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + CompanyListWidget(L10().customers, {"is_customer": "true"}), + ), + ); } void _selectProfile() { Navigator.push( - context, MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget()) + context, + MaterialPageRoute(builder: (context) => InvenTreeSelectServerWidget()), ).then((context) { // Once we return _loadProfile(); }); } - Future _loadSettings() async { + Future _loadSettings() async { + homeShowSubscribed = + await InvenTreeSettingsManager().getValue( + INV_HOME_SHOW_SUBSCRIBED, + true, + ) + as bool; + homeShowPo = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) + as bool; + homeShowSo = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) + as bool; + homeShowManufacturers = + await InvenTreeSettingsManager().getValue( + INV_HOME_SHOW_MANUFACTURERS, + true, + ) + as bool; + homeShowCustomers = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) + as bool; + homeShowSuppliers = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) + as bool; - homeShowSubscribed = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUBSCRIBED, true) as bool; - homeShowPo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, true) as bool; - homeShowSo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SO, true) as bool; - homeShowManufacturers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_MANUFACTURERS, true) as bool; - homeShowCustomers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_CUSTOMERS, true) as bool; - homeShowSuppliers = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUPPLIERS, true) as bool; - - setState(() { - }); + setState(() {}); } - Future _loadProfile() async { - + Future _loadProfile() async { _profile = await UserProfileDBManager().getSelectedProfile(); // A valid profile was loaded! if (_profile != null) { if (!InvenTreeAPI().isConnected() && !InvenTreeAPI().isConnecting()) { - // Attempt server connection InvenTreeAPI().connectToServer(_profile!).then((result) { if (mounted) { @@ -176,8 +201,15 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr setState(() {}); } - Widget _listTile(BuildContext context, String label, IconData icon, {Function()? callback, String role = "", String permission = "", Widget? trailing}) { - + Widget _listTile( + BuildContext context, + String label, + IconData icon, { + Function()? callback, + String role = "", + String permission = "", + Widget? trailing, + }) { bool connected = InvenTreeAPI().isConnected(); bool allowed = true; @@ -192,20 +224,15 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr child: Align( child: ListTile( leading: Icon( - icon, - size: 32, - color: connected && allowed ? COLOR_ACTION : Colors.grey - ), - title: Text( - label, - style: TextStyle( - fontSize: 20 - ), + icon, + size: 32, + color: connected && allowed ? COLOR_ACTION : Colors.grey, ), + title: Text(label, style: TextStyle(fontSize: 20)), trailing: trailing, ), alignment: Alignment.center, - ) + ), ), onTap: () { if (!allowed) { @@ -228,78 +255,89 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr * Constructs a list of tiles for the main screen */ List getListTiles(BuildContext context) { - List tiles = []; // Parts if (InvenTreePart().canView) { - tiles.add(_listTile( - context, - L10().parts, - TablerIcons.box, - callback: () { - _showParts(context); - }, - )); + tiles.add( + _listTile( + context, + L10().parts, + TablerIcons.box, + callback: () { + _showParts(context); + }, + ), + ); } // Starred parts if (homeShowSubscribed && InvenTreePart().canView) { - tiles.add(_listTile( - context, - L10().partsStarred, - TablerIcons.bell, - callback: () { - _showStarredParts(context); - } - )); + tiles.add( + _listTile( + context, + L10().partsStarred, + TablerIcons.bell, + callback: () { + _showStarredParts(context); + }, + ), + ); } // Stock button if (InvenTreeStockItem().canView) { - tiles.add(_listTile( + tiles.add( + _listTile( context, L10().stock, TablerIcons.package, callback: () { _showStock(context); - } - )); + }, + ), + ); } // Purchase orders if (homeShowPo && InvenTreePurchaseOrder().canView) { - tiles.add(_listTile( + tiles.add( + _listTile( context, L10().purchaseOrders, TablerIcons.shopping_cart, callback: () { _showPurchaseOrders(context); - } - )); + }, + ), + ); } if (homeShowSo && InvenTreeSalesOrder().canView) { - tiles.add(_listTile( - context, - L10().salesOrders, - TablerIcons.truck_delivery, - callback: () { - _showSalesOrders(context); - } - )); + tiles.add( + _listTile( + context, + L10().salesOrders, + TablerIcons.truck_delivery, + callback: () { + _showSalesOrders(context); + }, + ), + ); } // Suppliers if (homeShowSuppliers && InvenTreePurchaseOrder().canView) { - tiles.add(_listTile( + tiles.add( + _listTile( context, L10().suppliers, TablerIcons.building, callback: () { _showSuppliers(context); - } - )); + }, + ), + ); } // TODO: Add these tiles back in once the features are fleshed out @@ -320,14 +358,16 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr */ // Customers if (homeShowCustomers) { - tiles.add(_listTile( + tiles.add( + _listTile( context, L10().customers, TablerIcons.building_store, callback: () { _showCustomers(context); - } - )); + }, + ), + ); } return tiles; @@ -338,10 +378,10 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr * display a connection status widget */ Widget _connectionStatusWidget(BuildContext context) { - String? serverAddress = InvenTreeAPI().serverAddress; bool validAddress = serverAddress != null; - bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); + bool connecting = + !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); Widget leading = Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER); Widget trailing = Icon(TablerIcons.server, color: COLOR_ACTION); @@ -373,8 +413,8 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr trailing: trailing, leading: leading, onTap: _selectProfile, - ) - ] + ), + ], ), ); } @@ -384,7 +424,6 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr */ @override Widget getBody(BuildContext context) { - if (!InvenTreeAPI().isConnected()) { return _connectionStatusWidget(context); } @@ -398,7 +437,7 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr int hTiles = smallScreen ? 1 : 2; double aspect = smallScreen ? 5 : 3; double padding = smallScreen ? 2 : 10; - + return GridView.count( crossAxisCount: w > h ? vTiles : hTiles, children: getListTiles(context), @@ -408,12 +447,10 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr mainAxisSpacing: padding, padding: EdgeInsets.all(padding), ); - } @override Widget build(BuildContext context) { - var connected = InvenTreeAPI().isConnected(); var connecting = !connected && InvenTreeAPI().isConnecting(); @@ -426,15 +463,19 @@ class _InvenTreeHomePageState extends State with BaseWidgetPr IconButton( icon: Icon( TablerIcons.server, - color: connected ? COLOR_SUCCESS : (connecting ? COLOR_PROGRESS: COLOR_DANGER), + color: connected + ? COLOR_SUCCESS + : (connecting ? COLOR_PROGRESS : COLOR_DANGER), ), onPressed: _selectProfile, - ) + ), ], ), drawer: InvenTreeDrawer(context), body: getBody(context), - bottomNavigationBar: InvenTreeAPI().isConnected() ? buildBottomAppBar(context, homeKey) : null, + bottomNavigationBar: InvenTreeAPI().isConnected() + ? buildBottomAppBar(context, homeKey) + : null, ); } } diff --git a/lib/widget/notes_widget.dart b/lib/widget/notes_widget.dart index d871dd0..196eb91 100644 --- a/lib/widget/notes_widget.dart +++ b/lib/widget/notes_widget.dart @@ -5,7 +5,6 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:flutter_markdown/flutter_markdown.dart"; import "package:inventree/l10.dart"; - /* * A widget for displaying the notes associated with a given model. * We need to pass in the following parameters: @@ -14,7 +13,6 @@ import "package:inventree/l10.dart"; * - Title for the app bar */ class NotesWidget extends StatefulWidget { - const NotesWidget(this.model, {Key? key}) : super(key: key); final InvenTreeModel model; @@ -23,12 +21,10 @@ class NotesWidget extends StatefulWidget { _NotesState createState() => _NotesState(); } - /* * Class representing the state of the NotesWidget */ class _NotesState extends RefreshableState { - _NotesState(); @override @@ -41,7 +37,6 @@ class _NotesState extends RefreshableState { @override List appBarActions(BuildContext context) { - List actions = []; if (widget.model.canEdit) { @@ -54,16 +49,14 @@ class _NotesState extends RefreshableState { context, L10().editNotes, fields: { - "notes": { - "multiline": true, - } + "notes": {"multiline": true}, }, onSuccess: (data) async { refresh(context); - } + }, ); - } - ) + }, + ), ); } @@ -72,10 +65,6 @@ class _NotesState extends RefreshableState { @override Widget getBody(BuildContext context) { - return Markdown( - selectable: false, - data: widget.model.notes, - ); + return Markdown(selectable: false, data: widget.model.notes); } - -} \ No newline at end of file +} diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart index 9b5dabe..d29b8c9 100644 --- a/lib/widget/notifications.dart +++ b/lib/widget/notifications.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -8,17 +7,12 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/notification.dart"; import "package:inventree/widget/refreshable_state.dart"; - class NotificationWidget extends StatefulWidget { - @override _NotificationState createState() => _NotificationState(); - } - class _NotificationState extends RefreshableState { - _NotificationState() : super(); List notifications = []; @@ -29,8 +23,7 @@ class _NotificationState extends RefreshableState { String getAppBarTitle() => L10().notifications; @override - Future request (BuildContext context) async { - + Future request(BuildContext context) async { final results = await InvenTreeNotification().list(); notifications.clear(); @@ -45,8 +38,10 @@ class _NotificationState extends RefreshableState { /* * Dismiss an individual notification entry (mark it as "read") */ - Future dismissNotification(BuildContext context, InvenTreeNotification notification) async { - + Future dismissNotification( + BuildContext context, + InvenTreeNotification notification, + ) async { if (mounted) { setState(() { isDismissing = true; @@ -71,18 +66,17 @@ class _NotificationState extends RefreshableState { */ @override List getTiles(BuildContext context) { - List tiles = []; tiles.add( ListTile( - title: Text( - L10().notifications, - ), + title: Text(L10().notifications), subtitle: notifications.isEmpty ? Text(L10().notificationsEmpty) : null, - leading: notifications.isEmpty ? Icon(TablerIcons.bell_exclamation) : Icon(TablerIcons.bell), + leading: notifications.isEmpty + ? Icon(TablerIcons.bell_exclamation) + : Icon(TablerIcons.bell), trailing: Text("${notifications.length}"), - ) + ), ); for (var notification in notifications) { @@ -92,15 +86,16 @@ class _NotificationState extends RefreshableState { subtitle: Text(notification.message), trailing: IconButton( icon: Icon(TablerIcons.bookmark), - onPressed: isDismissing ? null : () async { - dismissNotification(context, notification); - }, + onPressed: isDismissing + ? null + : () async { + dismissNotification(context, notification); + }, ), - ) + ), ); } return tiles; - } } diff --git a/lib/widget/order/extra_line_detail.dart b/lib/widget/order/extra_line_detail.dart index bdf7dbc..055a58e 100644 --- a/lib/widget/order/extra_line_detail.dart +++ b/lib/widget/order/extra_line_detail.dart @@ -8,7 +8,6 @@ import "package:inventree/widget/snacks.dart"; import "package:inventree/inventree/orders.dart"; - class ExtraLineDetailWidget extends StatefulWidget { const ExtraLineDetailWidget(this.item, {Key? key}) : super(key: key); @@ -18,8 +17,8 @@ class ExtraLineDetailWidget extends StatefulWidget { _ExtraLineDetailWidgetState createState() => _ExtraLineDetailWidgetState(); } -class _ExtraLineDetailWidgetState extends RefreshableState { - +class _ExtraLineDetailWidgetState + extends RefreshableState { _ExtraLineDetailWidgetState(); @override @@ -35,8 +34,8 @@ class _ExtraLineDetailWidgetState extends RefreshableState tiles = []; tiles.add( - ListTile( - title: Text(L10().reference), - trailing: Text(widget.item.reference), - ) + ListTile( + title: Text(L10().reference), + trailing: Text(widget.item.reference), + ), ); tiles.add( - ListTile( - title: Text(L10().description), - trailing: Text(widget.item.description), - ) + ListTile( + title: Text(L10().description), + trailing: Text(widget.item.description), + ), ); tiles.add( ListTile( title: Text(L10().quantity), trailing: Text(widget.item.quantity.toString()), - ) + ), ); tiles.add( ListTile( title: Text(L10().unitPrice), trailing: Text( - renderCurrency(widget.item.price, widget.item.priceCurrency) - ) - ) + renderCurrency(widget.item.price, widget.item.priceCurrency), + ), + ), ); if (widget.item.notes.isNotEmpty) { tiles.add( - ListTile( - title: Text(L10().notes), - subtitle: Text(widget.item.notes), - ) + ListTile(title: Text(L10().notes), subtitle: Text(widget.item.notes)), ); } return tiles; } -} \ No newline at end of file +} diff --git a/lib/widget/order/po_extra_line_list.dart b/lib/widget/order/po_extra_line_list.dart index 4c38297..3ede508 100644 --- a/lib/widget/order/po_extra_line_list.dart +++ b/lib/widget/order/po_extra_line_list.dart @@ -9,28 +9,27 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; - class POExtraLineListWidget extends StatefulWidget { - - const POExtraLineListWidget(this.order, {this.filters = const {}, Key? key}) : super(key: key); + const POExtraLineListWidget(this.order, {this.filters = const {}, Key? key}) + : super(key: key); final InvenTreePurchaseOrder order; final Map filters; @override - _PurchaseOrderExtraLineListWidgetState createState() => _PurchaseOrderExtraLineListWidgetState(); + _PurchaseOrderExtraLineListWidgetState createState() => + _PurchaseOrderExtraLineListWidgetState(); } -class _PurchaseOrderExtraLineListWidgetState extends RefreshableState { - +class _PurchaseOrderExtraLineListWidgetState + extends RefreshableState { _PurchaseOrderExtraLineListWidgetState(); @override String getAppBarTitle() => L10().extraLineItems; Future _addLineItem(BuildContext context) async { - var fields = InvenTreePOExtraLineItem().formFields(); fields["order"]?["value"] = widget.order.pk; @@ -42,7 +41,7 @@ class _PurchaseOrderExtraLineListWidgetState extends RefreshableState filters) : super(filters: filters); + const PaginatedPOExtraLineList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().extraLineItems; @override - _PaginatedPOExtraLineListState createState() => _PaginatedPOExtraLineListState(); - + _PaginatedPOExtraLineListState createState() => + _PaginatedPOExtraLineListState(); } -class _PaginatedPOExtraLineListState extends PaginatedSearchState { - +class _PaginatedPOExtraLineListState + extends PaginatedSearchState { _PaginatedPOExtraLineListState() : super(); @override String get prefix => "po_extra_line_"; @override - Future requestPage(int limit, int offset, Map params) async { - final page = await InvenTreePOExtraLineItem().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreePOExtraLineItem().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePOExtraLineItem line = model as InvenTreePOExtraLineItem; return ListTile( @@ -113,4 +118,4 @@ class _PaginatedPOExtraLineListState extends PaginatedSearchState _POLineDetailWidgetState(); - } - /* * State for the POLineDetailWidget */ class _POLineDetailWidgetState extends RefreshableState { - _POLineDetailWidgetState(); InvenTreeStockLocation? destination; @@ -55,7 +51,7 @@ class _POLineDetailWidgetState extends RefreshableState { onPressed: () { _editLineItem(context); }, - ) + ), ); } @@ -75,8 +71,8 @@ class _POLineDetailWidgetState extends RefreshableState { label: L10().receiveItem, onTap: () async { receiveLineItem(context); - } - ) + }, + ), ); } } @@ -89,7 +85,9 @@ class _POLineDetailWidgetState extends RefreshableState { await widget.item.reload(); if (widget.item.destinationId > 0) { - InvenTreeStockLocation().get(widget.item.destinationId).then((InvenTreeModel? loc) { + InvenTreeStockLocation().get(widget.item.destinationId).then(( + InvenTreeModel? loc, + ) { if (mounted) { if (loc != null && loc is InvenTreeStockLocation) { setState(() { @@ -109,7 +107,6 @@ class _POLineDetailWidgetState extends RefreshableState { }); } } - } // Callback to edit this line item @@ -123,21 +120,21 @@ class _POLineDetailWidgetState extends RefreshableState { onSuccess: (data) async { refresh(context); showSnackIcon(L10().lineItemUpdated, success: true); - } + }, ); } - // Launch a form to 'receive' this line item + // Launch a form to 'receive' this line item Future receiveLineItem(BuildContext context) async { widget.item.receive( context, onSuccess: () => { showSnackIcon(L10().receivedItem, success: true), - refresh(context) - } + refresh(context), + }, ); } - + @override List getTiles(BuildContext context) { List tiles = []; @@ -158,7 +155,7 @@ class _POLineDetailWidgetState extends RefreshableState { part.goToDetailPage(context); } }, - ) + ), ); // Reference to the supplier part @@ -169,26 +166,33 @@ class _POLineDetailWidgetState extends RefreshableState { leading: Icon(TablerIcons.building, color: COLOR_ACTION), onTap: () async { showLoadingOverlay(); - var part = await InvenTreeSupplierPart().get(widget.item.supplierPartId); + var part = await InvenTreeSupplierPart().get( + widget.item.supplierPartId, + ); hideLoadingOverlay(); if (part is InvenTreeSupplierPart) { - Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierPartDetailWidget(part))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SupplierPartDetailWidget(part), + ), + ); } }, - ) + ), ); // Destination if (destination != null) { - tiles.add(ListTile( + tiles.add( + ListTile( title: Text(L10().destination), subtitle: Text(destination!.name), leading: Icon(TablerIcons.map_pin, color: COLOR_ACTION), - onTap: () => { - destination!.goToDetailPage(context) - } - )); + onTap: () => {destination!.goToDetailPage(context)}, + ), + ); } // Received quantity @@ -197,23 +201,23 @@ class _POLineDetailWidgetState extends RefreshableState { title: Text(L10().received), subtitle: ProgressBar(widget.item.progressRatio), trailing: Text( - widget.item.progressString, - style: TextStyle( - color: widget.item.isComplete ? COLOR_SUCCESS: COLOR_WARNING - ) + widget.item.progressString, + style: TextStyle( + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, + ), ), leading: Icon(TablerIcons.progress), - ) + ), ); // Reference if (widget.item.reference.isNotEmpty) { tiles.add( - ListTile( - title: Text(L10().reference), - subtitle: Text(widget.item.reference), - leading: Icon(TablerIcons.hash), - ) + ListTile( + title: Text(L10().reference), + subtitle: Text(widget.item.reference), + leading: Icon(TablerIcons.hash), + ), ); } @@ -223,9 +227,12 @@ class _POLineDetailWidgetState extends RefreshableState { title: Text(L10().unitPrice), leading: Icon(TablerIcons.currency_dollar), trailing: Text( - renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) + renderCurrency( + widget.item.purchasePrice, + widget.item.purchasePriceCurrency, + ), ), - ) + ), ); // Note @@ -235,7 +242,7 @@ class _POLineDetailWidgetState extends RefreshableState { title: Text(L10().notes), subtitle: Text(widget.item.notes), leading: Icon(TablerIcons.note), - ) + ), ); } @@ -249,11 +256,10 @@ class _POLineDetailWidgetState extends RefreshableState { onTap: () async { await openLink(widget.item.link); }, - ) + ), ); } return tiles; } - -} \ No newline at end of file +} diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart index 5050477..45a2702 100644 --- a/lib/widget/order/po_line_list.dart +++ b/lib/widget/order/po_line_list.dart @@ -16,22 +16,21 @@ import "package:inventree/widget/progress.dart"; * Paginated widget class for displaying a list of purchase order line items */ class PaginatedPOLineList extends PaginatedSearchWidget { - - const PaginatedPOLineList(Map filters) : super(filters: filters); + const PaginatedPOLineList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().lineItems; @override _PaginatedPOLineListState createState() => _PaginatedPOLineListState(); - } /* * State class for PaginatedPOLineList */ -class _PaginatedPOLineListState extends PaginatedSearchState { - +class _PaginatedPOLineListState + extends PaginatedSearchState { _PaginatedPOLineListState() : super(); @override @@ -55,13 +54,20 @@ class _PaginatedPOLineListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreePOLineItem().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreePOLineItem().listPaginated( + limit, + offset, + filters: params, + ); return page; } @@ -71,24 +77,34 @@ class _PaginatedPOLineListState extends PaginatedSearchState POLineDetailWidget(item))); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => POLineDetailWidget(item)), + ); }, ); } else { // Return an error tile return ListTile( title: Text(L10().error), - subtitle: Text("supplier part not defined", style: TextStyle(color: COLOR_DANGER)), + subtitle: Text( + "supplier part not defined", + style: TextStyle(color: COLOR_DANGER), + ), ); } } diff --git a/lib/widget/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart index 12332ae..f515cf8 100644 --- a/lib/widget/order/purchase_order_detail.dart +++ b/lib/widget/order/purchase_order_detail.dart @@ -18,7 +18,6 @@ import "package:inventree/widget/order/po_extra_line_list.dart"; import "package:inventree/widget/stock/location_display.dart"; import "package:inventree/widget/order/po_line_list.dart"; - import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/progress.dart"; @@ -27,13 +26,11 @@ import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock/stock_list.dart"; import "package:inventree/preferences.dart"; - /* * Widget for viewing a single PurchaseOrder instance */ class PurchaseOrderDetailWidget extends StatefulWidget { - - const PurchaseOrderDetailWidget(this.order, {Key? key}): super(key: key); + const PurchaseOrderDetailWidget(this.order, {Key? key}) : super(key: key); final InvenTreePurchaseOrder order; @@ -41,11 +38,10 @@ class PurchaseOrderDetailWidget extends StatefulWidget { _PurchaseOrderDetailState createState() => _PurchaseOrderDetailState(); } - -class _PurchaseOrderDetailState extends RefreshableState { - +class _PurchaseOrderDetailState + extends RefreshableState { _PurchaseOrderDetailState(); - + List lines = []; int extraLineCount = 0; @@ -79,8 +75,8 @@ class _PurchaseOrderDetailState extends RefreshableState _addLineItem(BuildContext context) async { - var fields = InvenTreePOLineItem().formFields(); // Update part field definition fields["part"]?["hidden"] = false; - fields["part"]?["filters"] = { - "supplier": widget.order.supplierId - }; + fields["part"]?["filters"] = {"supplier": widget.order.supplierId}; fields["order"]?["value"] = widget.order.pk; @@ -163,24 +155,22 @@ class _PurchaseOrderDetailState extends RefreshableState _uploadImage(BuildContext context) async { - - InvenTreePurchaseOrderAttachment().uploadImage( - widget.order.pk, - prefix: widget.order.reference, - ).then((result) => refresh(context)); + InvenTreePurchaseOrderAttachment() + .uploadImage(widget.order.pk, prefix: widget.order.reference) + .then((result) => refresh(context)); } /// Issue this order Future _issueOrder(BuildContext context) async { - confirmationDialog( - L10().issueOrder, "", + L10().issueOrder, + "", icon: TablerIcons.send, color: Colors.blue, acceptText: L10().issue, @@ -188,15 +178,15 @@ class _PurchaseOrderDetailState extends RefreshableState _cancelOrder(BuildContext context) async { - confirmationDialog( - L10().cancelOrder, "", + L10().cancelOrder, + "", icon: TablerIcons.circle_x, color: Colors.red, acceptText: L10().cancel, @@ -204,7 +194,7 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { await widget.order.reload(); @@ -256,8 +245,16 @@ class _PurchaseOrderDetailState extends RefreshableState 0) { - InvenTreeStockLocation().get(widget.order.destinationId).then((InvenTreeModel? loc) { + if (api.supportsPurchaseOrderDestination && + widget.order.destinationId > 0) { + InvenTreeStockLocation().get(widget.order.destinationId).then(( + InvenTreeModel? loc, + ) { if (mounted) { if (loc != null && loc is InvenTreeStockLocation) { setState(() { @@ -298,17 +300,19 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { + Future editOrder(BuildContext context) async { var fields = widget.order.formFields(); // Cannot edit supplier field from here @@ -331,32 +335,29 @@ class _PurchaseOrderDetailState extends RefreshableState orderTiles(BuildContext context) { - List tiles = []; InvenTreeCompany? supplier = widget.order.supplier; @@ -364,165 +365,204 @@ class _PurchaseOrderDetailState extends RefreshableState { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationDisplayWidget(destination), + ), + ), + }, + ), + ); + } + + Color lineColor = completedLines < widget.order.lineItemCount + ? COLOR_WARNING + : COLOR_SUCCESS; + + tiles.add( + ListTile( + title: Text(L10().lineItems), + subtitle: ProgressBar( + completedLines.toDouble(), + maximum: widget.order.lineItemCount.toDouble(), + ), + leading: Icon(TablerIcons.clipboard_check), + trailing: Text( + "${completedLines} / ${widget.order.lineItemCount}", + style: TextStyle(color: lineColor), + ), + ), + ); + + // Extra line items + tiles.add( + ListTile( + title: Text(L10().extraLineItems), + leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), + trailing: Text(extraLineCount.toString()), onTap: () => { Navigator.push( context, MaterialPageRoute( - builder: (context) => LocationDisplayWidget(destination) - ) - ) - } - )); - } - - Color lineColor = completedLines < widget.order.lineItemCount ? COLOR_WARNING : COLOR_SUCCESS; - - tiles.add(ListTile( - title: Text(L10().lineItems), - subtitle: ProgressBar( - completedLines.toDouble(), - maximum: widget.order.lineItemCount.toDouble(), + builder: (context) => POExtraLineListWidget( + widget.order, + filters: {"order": widget.order.pk.toString()}, + ), + ), + ), + }, ), - leading: Icon(TablerIcons.clipboard_check), - trailing: Text("${completedLines} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), - )); + ); - // Extra line items - tiles.add(ListTile( - title: Text(L10().extraLineItems), - leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), - trailing: Text(extraLineCount.toString()), - onTap: () => { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => POExtraLineListWidget(widget.order, filters: {"order": widget.order.pk.toString()}) - ) - ) - }, - )); - - tiles.add(ListTile( - title: Text(L10().totalPrice), - leading: Icon(TablerIcons.currency_dollar), - trailing: Text( - renderCurrency(widget.order.totalPrice, widget.order.totalPriceCurrency) + tiles.add( + ListTile( + title: Text(L10().totalPrice), + leading: Icon(TablerIcons.currency_dollar), + trailing: Text( + renderCurrency( + widget.order.totalPrice, + widget.order.totalPriceCurrency, + ), + ), ), - )); + ); if (widget.order.issueDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().issueDate), - trailing: Text(widget.order.issueDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().issueDate), + trailing: Text(widget.order.issueDate), + leading: Icon(TablerIcons.calendar), + ), + ); } if (widget.order.startDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().startDate), - trailing: Text(widget.order.startDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().startDate), + trailing: Text(widget.order.startDate), + leading: Icon(TablerIcons.calendar), + ), + ); } if (widget.order.targetDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().targetDate), - trailing: Text(widget.order.targetDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().targetDate), + trailing: Text(widget.order.targetDate), + leading: Icon(TablerIcons.calendar), + ), + ); } if (widget.order.completionDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().completionDate), - trailing: Text(widget.order.completionDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().completionDate), + trailing: Text(widget.order.completionDate), + leading: Icon(TablerIcons.calendar), + ), + ); } // Responsible "owner" - if (widget.order.responsibleName.isNotEmpty && widget.order.responsibleLabel.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().responsible), - leading: Icon(widget.order.responsibleLabel == "group" ? TablerIcons.users : TablerIcons.user), - trailing: Text(widget.order.responsibleName) - )); + if (widget.order.responsibleName.isNotEmpty && + widget.order.responsibleLabel.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().responsible), + leading: Icon( + widget.order.responsibleLabel == "group" + ? TablerIcons.users + : TablerIcons.user, + ), + trailing: Text(widget.order.responsibleName), + ), + ); } // Notes tile tiles.add( - ListTile( - title: Text(L10().notes), - leading: Icon(TablerIcons.note, color: COLOR_ACTION), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => NotesWidget(widget.order) - ) - ); - }, - ) + ListTile( + title: Text(L10().notes), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NotesWidget(widget.order)), + ); + }, + ), ); // Attachments tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreePurchaseOrderAttachment(), - widget.order.pk, - widget.order.reference, - widget.order.canEdit - ) - ) - ); - }, - ) + ListTile( + title: Text(L10().attachments), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreePurchaseOrderAttachment(), + widget.order.pk, + widget.order.reference, + widget.order.canEdit, + ), + ), + ); + }, + ), ); return tiles; - } @override @@ -530,10 +570,10 @@ class _PurchaseOrderDetailState extends RefreshableState getTabs(BuildContext context) { return [ diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart index 8351ac4..033e306 100644 --- a/lib/widget/order/purchase_order_list.dart +++ b/lib/widget/order/purchase_order_list.dart @@ -16,18 +16,18 @@ import "package:inventree/inventree/purchase_order.dart"; * Widget class for displaying a list of Purchase Orders */ class PurchaseOrderListWidget extends StatefulWidget { - - const PurchaseOrderListWidget({this.filters = const {}, Key? key}) : super(key: key); + const PurchaseOrderListWidget({this.filters = const {}, Key? key}) + : super(key: key); final Map filters; @override - _PurchaseOrderListWidgetState createState() => _PurchaseOrderListWidgetState(); + _PurchaseOrderListWidgetState createState() => + _PurchaseOrderListWidgetState(); } - -class _PurchaseOrderListWidgetState extends RefreshableState { - +class _PurchaseOrderListWidgetState + extends RefreshableState { _PurchaseOrderListWidgetState(); @override @@ -44,8 +44,8 @@ class _PurchaseOrderListWidgetState extends RefreshableState filters) : super(filters: filters); + const PaginatedPurchaseOrderList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().purchaseOrders; @override - _PaginatedPurchaseOrderListState createState() => _PaginatedPurchaseOrderListState(); - + _PaginatedPurchaseOrderListState createState() => + _PaginatedPurchaseOrderListState(); } - -class _PaginatedPurchaseOrderListState extends PaginatedSearchState { - +class _PaginatedPurchaseOrderListState + extends PaginatedSearchState { _PaginatedPurchaseOrderListState() : super(); @override @@ -147,29 +142,37 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - + Future requestPage( + int limit, + int offset, + Map params, + ) async { await InvenTreeAPI().PurchaseOrderStatus.load(); - final page = await InvenTreePurchaseOrder().listPaginated(limit, offset, filters: params); + final page = await InvenTreePurchaseOrder().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePurchaseOrder order = model as InvenTreePurchaseOrder; InvenTreeCompany? supplier = order.supplier; - + return ListTile( title: Text(order.reference), subtitle: Text(order.description), - leading: supplier == null ? null : InvenTreeAPI().getThumbnail(supplier.thumbnail), + leading: supplier == null + ? null + : InvenTreeAPI().getThumbnail(supplier.thumbnail), trailing: Text( InvenTreeAPI().PurchaseOrderStatus.label(order.status), style: TextStyle( @@ -181,4 +184,4 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState _SalesOrderDetailState(); } - class _SalesOrderDetailState extends RefreshableState { - _SalesOrderDetailState(); List lines = []; @@ -68,7 +64,7 @@ class _SalesOrderDetailState extends RefreshableState { onPressed: () { editOrder(context); }, - ) + ), ); } @@ -77,7 +73,6 @@ class _SalesOrderDetailState extends RefreshableState { // Add a new shipment against this sales order Future _addShipment(BuildContext context) async { - var fields = InvenTreeSalesOrderShipment().formFields(); fields["order"]?["value"] = widget.order.pk; @@ -89,9 +84,8 @@ class _SalesOrderDetailState extends RefreshableState { fields: fields, onSuccess: (result) async { refresh(context); - } + }, ); - } // Add a new line item to this sales order @@ -102,52 +96,51 @@ class _SalesOrderDetailState extends RefreshableState { fields["order"]?["hidden"] = true; InvenTreeSOLineItem().createForm( - context, - L10().lineItemAdd, - fields: fields, - onSuccess: (result) async { - refresh(context); - } + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (result) async { + refresh(context); + }, ); } /// Upload an image for this order Future _uploadImage(BuildContext context) async { - InvenTreeSalesOrderAttachment().uploadImage( - widget.order.pk, - prefix: widget.order.reference, - ).then((result) => refresh(context)); + InvenTreeSalesOrderAttachment() + .uploadImage(widget.order.pk, prefix: widget.order.reference) + .then((result) => refresh(context)); } /// Issue this order Future _issueOrder(BuildContext context) async { - confirmationDialog( - L10().issueOrder, "", - icon: TablerIcons.send, - color: Colors.blue, - acceptText: L10().issue, - onAccept: () async { - widget.order.issueOrder().then((dynamic) { - refresh(context); - }); - } + L10().issueOrder, + "", + icon: TablerIcons.send, + color: Colors.blue, + acceptText: L10().issue, + onAccept: () async { + widget.order.issueOrder().then((dynamic) { + refresh(context); + }); + }, ); } /// Cancel this order Future _cancelOrder(BuildContext context) async { - confirmationDialog( - L10().cancelOrder, "", - icon: TablerIcons.circle_x, - color: Colors.red, - acceptText: L10().cancel, - onAccept: () async { - await widget.order.cancelOrder().then((dynamic) { - refresh(context); - }); - } + L10().cancelOrder, + "", + icon: TablerIcons.circle_x, + color: Colors.red, + acceptText: L10().cancel, + onAccept: () async { + await widget.order.cancelOrder().then((dynamic) { + refresh(context); + }); + }, ); } @@ -157,50 +150,51 @@ class _SalesOrderDetailState extends RefreshableState { if (showCameraShortcut && widget.order.canEdit) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.camera, color: Colors.blue), - label: L10().takePicture, - onTap: () async { - _uploadImage(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.camera, color: Colors.blue), + label: L10().takePicture, + onTap: () async { + _uploadImage(context); + }, + ), ); } if (widget.order.isPending) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.send, color: Colors.blue), - label: L10().issueOrder, - onTap: () async { - _issueOrder(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.send, color: Colors.blue), + label: L10().issueOrder, + onTap: () async { + _issueOrder(context); + }, + ), ); } if (widget.order.isOpen) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.circle_x, color: Colors.red), - label: L10().cancelOrder, - onTap: () async { - _cancelOrder(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.circle_x, color: Colors.red), + label: L10().cancelOrder, + onTap: () async { + _cancelOrder(context); + }, + ), ); } // Add line item - if ((widget.order.isPending || widget.order.isInProgress) && InvenTreeSOLineItem().canCreate) { + if ((widget.order.isPending || widget.order.isInProgress) && + InvenTreeSOLineItem().canCreate) { actions.add( SpeedDialChild( child: Icon(TablerIcons.circle_plus, color: Colors.green), label: L10().lineItemAdd, onTap: () async { _addLineItem(context); - } - ) + }, + ), ); actions.add( @@ -209,8 +203,8 @@ class _SalesOrderDetailState extends RefreshableState { label: L10().shipmentAdd, onTap: () async { _addShipment(context); - } - ) + }, + ), ); } @@ -221,7 +215,8 @@ class _SalesOrderDetailState extends RefreshableState { List barcodeButtons(BuildContext context) { List actions = []; - if ((widget.order.isInProgress || widget.order.isPending) && InvenTreeSOLineItem().canCreate) { + if ((widget.order.isInProgress || widget.order.isPending) && + InvenTreeSOLineItem().canCreate) { actions.add( SpeedDialChild( child: Icon(Icons.barcode_reader), @@ -231,8 +226,8 @@ class _SalesOrderDetailState extends RefreshableState { context, handler: SOAddItemBarcodeHandler(salesOrder: widget.order), ); - } - ) + }, + ), ); if (api.supportsBarcodeSOAllocateEndpoint) { @@ -243,12 +238,10 @@ class _SalesOrderDetailState extends RefreshableState { onTap: () async { scanBarcode( context, - handler: SOAllocateStockHandler( - salesOrder: widget.order, - ) + handler: SOAllocateStockHandler(salesOrder: widget.order), ); - } - ) + }, + ), ); } } @@ -261,10 +254,20 @@ class _SalesOrderDetailState extends RefreshableState { await widget.order.reload(); await api.SalesOrderStatus.load(); - supportsProjectCodes = api.supportsProjectCodes && await api.getGlobalBooleanSetting("PROJECT_CODES_ENABLED", backup: true); - showCameraShortcut = await InvenTreeSettingsManager().getBool(INV_SO_SHOW_CAMERA, true); + supportsProjectCodes = + api.supportsProjectCodes && + await api.getGlobalBooleanSetting( + "PROJECT_CODES_ENABLED", + backup: true, + ); + showCameraShortcut = await InvenTreeSettingsManager().getBool( + INV_SO_SHOW_CAMERA, + true, + ); - InvenTreeSalesOrderAttachment().countAttachments(widget.order.pk).then((int value) { + InvenTreeSalesOrderAttachment().countAttachments(widget.order.pk).then(( + int value, + ) { if (mounted) { setState(() { attachmentCount = value; @@ -273,13 +276,15 @@ class _SalesOrderDetailState extends RefreshableState { }); // Count number of "extra line items" against this order - InvenTreeSOExtraLineItem().count(filters: {"order": widget.order.pk.toString() }).then((int value) { - if (mounted) { - setState(() { - extraLineCount = value; + InvenTreeSOExtraLineItem() + .count(filters: {"order": widget.order.pk.toString()}) + .then((int value) { + if (mounted) { + setState(() { + extraLineCount = value; + }); + } }); - } - }); } // Edit the current SalesOrder instance @@ -305,7 +310,7 @@ class _SalesOrderDetailState extends RefreshableState { onSuccess: (data) async { refresh(context); showSnackIcon(L10().salesOrderUpdated, success: true); - } + }, ); } @@ -321,121 +326,154 @@ class _SalesOrderDetailState extends RefreshableState { trailing: Text( api.SalesOrderStatus.label(widget.order.status), style: TextStyle( - color: api.SalesOrderStatus.color(widget.order.status) + color: api.SalesOrderStatus.color(widget.order.status), ), ), - ) + ), ); } List orderTiles(BuildContext context) { - - List tiles = [ - headerTile(context) - ]; + List tiles = [headerTile(context)]; InvenTreeCompany? customer = widget.order.customer; if (supportsProjectCodes && widget.order.hasProjectCode) { - tiles.add(ListTile( - title: Text(L10().projectCode), - subtitle: Text("${widget.order.projectCode} - ${widget.order.projectCodeDescription}"), - leading: Icon(TablerIcons.list), - )); + tiles.add( + ListTile( + title: Text(L10().projectCode), + subtitle: Text( + "${widget.order.projectCode} - ${widget.order.projectCodeDescription}", + ), + leading: Icon(TablerIcons.list), + ), + ); } if (customer != null) { - tiles.add(ListTile( - title: Text(L10().customer), - subtitle: Text(customer.name), - leading: Icon(TablerIcons.user, color: COLOR_ACTION), - onTap: () { - customer.goToDetailPage(context); - } - )); + tiles.add( + ListTile( + title: Text(L10().customer), + subtitle: Text(customer.name), + leading: Icon(TablerIcons.user, color: COLOR_ACTION), + onTap: () { + customer.goToDetailPage(context); + }, + ), + ); } if (widget.order.customerReference.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().customerReference), - trailing: Text(widget.order.customerReference), - leading: Icon(TablerIcons.hash), - )); + tiles.add( + ListTile( + title: Text(L10().customerReference), + trailing: Text(widget.order.customerReference), + leading: Icon(TablerIcons.hash), + ), + ); } Color lineColor = widget.order.complete ? COLOR_SUCCESS : COLOR_WARNING; - tiles.add(ListTile( - title: Text(L10().lineItems), - subtitle: ProgressBar( - widget.order.completedLineItemCount.toDouble(), - maximum: widget.order.lineItemCount.toDouble() + tiles.add( + ListTile( + title: Text(L10().lineItems), + subtitle: ProgressBar( + widget.order.completedLineItemCount.toDouble(), + maximum: widget.order.lineItemCount.toDouble(), + ), + leading: Icon(TablerIcons.clipboard_check), + trailing: Text( + "${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", + style: TextStyle(color: lineColor), + ), ), - leading: Icon(TablerIcons.clipboard_check), - trailing: Text("${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", style: TextStyle(color: lineColor)), - )); + ); // Extra line items - tiles.add(ListTile( - title: Text(L10().extraLineItems), - leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), - trailing: Text(extraLineCount.toString()), - onTap: () => { - Navigator.push( + tiles.add( + ListTile( + title: Text(L10().extraLineItems), + leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), + trailing: Text(extraLineCount.toString()), + onTap: () => { + Navigator.push( context, MaterialPageRoute( - builder: (context) => SOExtraLineListWidget(widget.order, filters: {"order": widget.order.pk.toString()}) - ) - ) - }, - )); + builder: (context) => SOExtraLineListWidget( + widget.order, + filters: {"order": widget.order.pk.toString()}, + ), + ), + ), + }, + ), + ); // Shipment progress if (widget.order.shipmentCount > 0) { - tiles.add(ListTile( - title: Text(L10().shipments), - subtitle: ProgressBar( - widget.order.completedShipmentCount.toDouble(), - maximum: widget.order.shipmentCount.toDouble() + tiles.add( + ListTile( + title: Text(L10().shipments), + subtitle: ProgressBar( + widget.order.completedShipmentCount.toDouble(), + maximum: widget.order.shipmentCount.toDouble(), + ), + leading: Icon(TablerIcons.truck_delivery), + trailing: Text( + "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", + style: TextStyle(color: lineColor), + ), ), - leading: Icon(TablerIcons.truck_delivery), - trailing: Text("${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", style: TextStyle(color: lineColor)), - )); + ); } // TODO: total price if (widget.order.startDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().startDate), - trailing: Text(widget.order.startDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().startDate), + trailing: Text(widget.order.startDate), + leading: Icon(TablerIcons.calendar), + ), + ); } if (widget.order.targetDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().targetDate), - trailing: Text(widget.order.targetDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().targetDate), + trailing: Text(widget.order.targetDate), + leading: Icon(TablerIcons.calendar), + ), + ); } if (widget.order.shipmentDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().completionDate), - trailing: Text(widget.order.shipmentDate), - leading: Icon(TablerIcons.calendar), - )); + tiles.add( + ListTile( + title: Text(L10().completionDate), + trailing: Text(widget.order.shipmentDate), + leading: Icon(TablerIcons.calendar), + ), + ); } // Responsible "owner" - if (widget.order.responsibleName.isNotEmpty && widget.order.responsibleLabel.isNotEmpty) { - tiles.add(ListTile( + if (widget.order.responsibleName.isNotEmpty && + widget.order.responsibleLabel.isNotEmpty) { + tiles.add( + ListTile( title: Text(L10().responsible), - leading: Icon(widget.order.responsibleLabel == "group" ? TablerIcons.users : TablerIcons.user), - trailing: Text(widget.order.responsibleName) - )); + leading: Icon( + widget.order.responsibleLabel == "group" + ? TablerIcons.users + : TablerIcons.user, + ), + trailing: Text(widget.order.responsibleName), + ), + ); } // Notes tile @@ -446,12 +484,10 @@ class _SalesOrderDetailState extends RefreshableState { onTap: () { Navigator.push( context, - MaterialPageRoute( - builder: (context) => NotesWidget(widget.order) - ) + MaterialPageRoute(builder: (context) => NotesWidget(widget.order)), ); }, - ) + ), ); // Attachments @@ -462,18 +498,18 @@ class _SalesOrderDetailState extends RefreshableState { trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeSalesOrderAttachment(), - widget.order.pk, - widget.order.reference, - widget.order.canEdit - ) - ) - ); + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeSalesOrderAttachment(), + widget.order.pk, + widget.order.reference, + widget.order.canEdit, + ), + ), + ); }, - ) + ), ); return tiles; @@ -496,5 +532,4 @@ class _SalesOrderDetailState extends RefreshableState { PaginatedSOShipmentList({"order": widget.order.pk.toString()}), ]; } - } diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart index 46264c4..089363e 100644 --- a/lib/widget/order/sales_order_list.dart +++ b/lib/widget/order/sales_order_list.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -12,20 +11,18 @@ import "package:inventree/api.dart"; import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/model.dart"; - class SalesOrderListWidget extends StatefulWidget { - - const SalesOrderListWidget({this.filters = const {}, Key? key}) : super(key: key); + const SalesOrderListWidget({this.filters = const {}, Key? key}) + : super(key: key); final Map filters; @override _SalesOrderListWidgetState createState() => _SalesOrderListWidgetState(); - } -class _SalesOrderListWidgetState extends RefreshableState { - +class _SalesOrderListWidgetState + extends RefreshableState { _SalesOrderListWidgetState(); @override @@ -37,13 +34,13 @@ class _SalesOrderListWidgetState extends RefreshableState if (InvenTreeSalesOrder().canCreate) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.circle_plus), - label: L10().salesOrderCreate, - onTap: () { - _createSalesOrder(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.circle_plus), + label: L10().salesOrderCreate, + onTap: () { + _createSalesOrder(context); + }, + ), ); } @@ -58,17 +55,17 @@ class _SalesOrderListWidgetState extends RefreshableState fields.remove("contact"); InvenTreeSalesOrder().createForm( - context, - L10().salesOrderCreate, - fields: fields, - onSuccess: (result) async { - Map data = result as Map; + context, + L10().salesOrderCreate, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; - if (data.containsKey("pk")) { - var order = InvenTreeSalesOrder.fromJson(data); - order.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var order = InvenTreeSalesOrder.fromJson(data); + order.goToDetailPage(context); } + }, ); } @@ -82,25 +79,22 @@ class _SalesOrderListWidgetState extends RefreshableState Widget getBody(BuildContext context) { return PaginatedSalesOrderList(widget.filters); } - } - class PaginatedSalesOrderList extends PaginatedSearchWidget { - - const PaginatedSalesOrderList(Map filters) : super(filters: filters); + const PaginatedSalesOrderList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().salesOrders; @override - _PaginatedSalesOrderListState createState() => _PaginatedSalesOrderListState(); - + _PaginatedSalesOrderListState createState() => + _PaginatedSalesOrderListState(); } - -class _PaginatedSalesOrderListState extends PaginatedSearchState { - +class _PaginatedSalesOrderListState + extends PaginatedSearchState { _PaginatedSalesOrderListState() : super(); @override @@ -130,21 +124,27 @@ class _PaginatedSalesOrderListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - + Future requestPage( + int limit, + int offset, + Map params, + ) async { await InvenTreeAPI().SalesOrderStatus.load(); - final page = await InvenTreeSalesOrder().listPaginated(limit, offset, filters: params); + final page = await InvenTreeSalesOrder().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeSalesOrder order = model as InvenTreeSalesOrder; InvenTreeCompany? customer = order.customer; @@ -152,18 +152,18 @@ class _PaginatedSalesOrderListState extends PaginatedSearchState filters; @override - _SalesOrderExtraLineListWidgetState createState() => _SalesOrderExtraLineListWidgetState(); + _SalesOrderExtraLineListWidgetState createState() => + _SalesOrderExtraLineListWidgetState(); } -class _SalesOrderExtraLineListWidgetState extends RefreshableState { - +class _SalesOrderExtraLineListWidgetState + extends RefreshableState { _SalesOrderExtraLineListWidgetState(); @override String getAppBarTitle() => L10().extraLineItems; Future _addLineItem(BuildContext context) async { - var fields = InvenTreeSOExtraLineItem().formFields(); fields["order"]?["value"] = widget.order.pk; InvenTreeSOExtraLineItem().createForm( - context, - L10().lineItemAdd, - fields: fields, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().lineItemUpdated, success: true); - } + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().lineItemUpdated, success: true); + }, ); } @@ -54,13 +53,13 @@ class _SalesOrderExtraLineListWidgetState extends RefreshableState filters) : super(filters: filters); + const PaginatedSOExtraLineList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().extraLineItems; @override - _PaginatedSOExtraLineListState createState() => _PaginatedSOExtraLineListState(); - + _PaginatedSOExtraLineListState createState() => + _PaginatedSOExtraLineListState(); } -class _PaginatedSOExtraLineListState extends PaginatedSearchState { - +class _PaginatedSOExtraLineListState + extends PaginatedSearchState { _PaginatedSOExtraLineListState() : super(); @override String get prefix => "so_extra_line_"; @override - Future requestPage(int limit, int offset, Map params) async { - final page = await InvenTreeSOExtraLineItem().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeSOExtraLineItem().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeSOExtraLineItem line = model as InvenTreeSOExtraLineItem; return ListTile( @@ -115,4 +120,4 @@ class _PaginatedSOExtraLineListState extends PaginatedSearchState _SOLineDetailWidgetState(); - } - class _SOLineDetailWidgetState extends RefreshableState { - _SOLineDetailWidgetState(); InvenTreeSalesOrder? order; @@ -51,10 +44,11 @@ class _SOLineDetailWidgetState extends RefreshableState { if (widget.item.canEdit) { actions.add( IconButton( - icon: Icon(TablerIcons.edit), - onPressed: () { - _editLineItem(context); - }), + icon: Icon(TablerIcons.edit), + onPressed: () { + _editLineItem(context); + }, + ), ); } @@ -62,7 +56,6 @@ class _SOLineDetailWidgetState extends RefreshableState { } Future _allocateStock(BuildContext context) async { - if (order == null) { return; } @@ -73,12 +66,10 @@ class _SOLineDetailWidgetState extends RefreshableState { fields["stock_item"]?["filters"] = { "in_stock": true, "available": true, - "part": widget.item.partId.toString() + "part": widget.item.partId.toString(), }; fields["quantity"]?["value"] = widget.item.unallocatedQuantity.toString(); - fields["shipment"]?["filters"] = { - "order": order!.pk.toString() - }; + fields["shipment"]?["filters"] = {"order": order!.pk.toString()}; launchApiForm( context, @@ -89,9 +80,8 @@ class _SOLineDetailWidgetState extends RefreshableState { icon: TablerIcons.transition_right, onSuccess: (data) async { refresh(context); - } + }, ); - } Future _editLineItem(BuildContext context) async { @@ -109,13 +99,12 @@ class _SOLineDetailWidgetState extends RefreshableState { onSuccess: (data) async { refresh(context); showSnackIcon(L10().lineItemUpdated, success: true); - } + }, ); } @override List actionButtons(BuildContext context) { - List buttons = []; if (order != null && order!.isOpen) { @@ -125,8 +114,8 @@ class _SOLineDetailWidgetState extends RefreshableState { label: L10().allocateStock, onTap: () async { _allocateStock(context); - } - ) + }, + ), ); } @@ -138,22 +127,21 @@ class _SOLineDetailWidgetState extends RefreshableState { List actions = []; if (order != null && order!.isOpen && InvenTreeSOLineItem().canCreate) { - if (api.supportsBarcodeSOAllocateEndpoint) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.transition_right), - label: L10().allocateStock, - onTap: () async { - scanBarcode( - context, - handler: SOAllocateStockHandler( - salesOrder: order, - lineItem: widget.item - ) - ); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.transition_right), + label: L10().allocateStock, + onTap: () async { + scanBarcode( + context, + handler: SOAllocateStockHandler( + salesOrder: order, + lineItem: widget.item, + ), + ); + }, + ), ); } } @@ -193,8 +181,8 @@ class _SOLineDetailWidgetState extends RefreshableState { if (part is InvenTreePart) { part.goToDetailPage(context); } - } - ) + }, + ), ); // Available quantity @@ -202,8 +190,8 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().availableStock), leading: Icon(TablerIcons.packages), - trailing: Text(simpleNumberString(widget.item.availableStock)) - ) + trailing: Text(simpleNumberString(widget.item.availableStock)), + ), ); // Allocated quantity @@ -215,10 +203,10 @@ class _SOLineDetailWidgetState extends RefreshableState { trailing: Text( widget.item.allocatedString, style: TextStyle( - color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING - ) - ) - ) + color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING, + ), + ), + ), ); // Shipped quantity @@ -229,11 +217,11 @@ class _SOLineDetailWidgetState extends RefreshableState { trailing: Text( widget.item.progressString, style: TextStyle( - color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, ), ), - leading: Icon(TablerIcons.truck) - ) + leading: Icon(TablerIcons.truck), + ), ); // Reference @@ -242,36 +230,36 @@ class _SOLineDetailWidgetState extends RefreshableState { ListTile( title: Text(L10().reference), subtitle: Text(widget.item.reference), - leading: Icon(TablerIcons.hash) - ) + leading: Icon(TablerIcons.hash), + ), ); } // Note if (widget.item.notes.isNotEmpty) { tiles.add( - ListTile( - title: Text(L10().notes), - subtitle: Text(widget.item.notes), - leading: Icon(TablerIcons.note), - ) + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.item.notes), + leading: Icon(TablerIcons.note), + ), ); } // External link if (widget.item.link.isNotEmpty) { tiles.add( - ListTile( - title: Text(L10().link), - subtitle: Text(widget.item.link), - leading: Icon(TablerIcons.link, color: COLOR_ACTION), - onTap: () async { - await openLink(widget.item.link); - }, - ) + ListTile( + title: Text(L10().link), + subtitle: Text(widget.item.link), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () async { + await openLink(widget.item.link); + }, + ), ); } return tiles; } -} \ No newline at end of file +} diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart index a4c7454..2530d3e 100644 --- a/lib/widget/order/so_line_list.dart +++ b/lib/widget/order/so_line_list.dart @@ -9,28 +9,26 @@ import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/widget/progress.dart"; - /* * Paginated widget class for displaying a list of sales order line items */ class PaginatedSOLineList extends PaginatedSearchWidget { - const PaginatedSOLineList(Map filters) : super(filters: filters); + const PaginatedSOLineList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().lineItems; @override _PaginatedSOLineListState createState() => _PaginatedSOLineListState(); - } - /* * State class for PaginatedSOLineList */ -class _PaginatedSOLineListState extends PaginatedSearchState { - +class _PaginatedSOLineListState + extends PaginatedSearchState { _PaginatedSOLineListState() : super(); @override @@ -43,13 +41,19 @@ class _PaginatedSOLineListState extends PaginatedSearchState> get filterOptions => { - - }; + Map> get filterOptions => {}; @override - Future requestPage(int limit, int offset, Map params) async { - final page = await InvenTreeSOLineItem().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeSOLineItem().listPaginated( + limit, + offset, + filters: params, + ); return page; } @@ -63,24 +67,30 @@ class _PaginatedSOLineListState extends PaginatedSearchState SoLineDetailWidget(item)) + MaterialPageRoute(builder: (context) => SoLineDetailWidget(item)), ); - } + }, ); } else { return ListTile( title: Text(L10().error), - subtitle: Text("Missing part detail", style: TextStyle(color: COLOR_DANGER)), + subtitle: Text( + "Missing part detail", + style: TextStyle(color: COLOR_DANGER), + ), ); } } - } diff --git a/lib/widget/order/so_shipment_list.dart b/lib/widget/order/so_shipment_list.dart index a1e0dc7..a6c1472 100644 --- a/lib/widget/order/so_shipment_list.dart +++ b/lib/widget/order/so_shipment_list.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:inventree/app_colors.dart"; @@ -9,19 +8,19 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/l10.dart"; class PaginatedSOShipmentList extends PaginatedSearchWidget { - - const PaginatedSOShipmentList(Map filters) : super(filters: filters); + const PaginatedSOShipmentList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().shipments; @override - _PaginatedSOShipmentListState createState() => _PaginatedSOShipmentListState(); + _PaginatedSOShipmentListState createState() => + _PaginatedSOShipmentListState(); } - -class _PaginatedSOShipmentListState extends PaginatedSearchState { - +class _PaginatedSOShipmentListState + extends PaginatedSearchState { _PaginatedSOShipmentListState() : super(); @override @@ -34,22 +33,30 @@ class _PaginatedSOShipmentListState extends PaginatedSearchState> get filterOptions => {}; @override - Future requestPage(int limit, int offset, Map params) async { - final page = await InvenTreeSalesOrderShipment().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeSalesOrderShipment().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeSalesOrderShipment shipment = model as InvenTreeSalesOrderShipment; return ListTile( title: Text(shipment.reference), subtitle: Text(shipment.tracking_number), - leading: shipment.shipped ? Icon(TablerIcons.calendar_check, color: COLOR_SUCCESS) : Icon(TablerIcons.calendar_cancel, color: COLOR_WARNING), - trailing: shipment.shipped ? Text(shipment.shipment_date ?? "") : null + leading: shipment.shipped + ? Icon(TablerIcons.calendar_check, color: COLOR_SUCCESS) + : Icon(TablerIcons.calendar_cancel, color: COLOR_WARNING), + trailing: shipment.shipped ? Text(shipment.shipment_date ?? "") : null, ); - } -} \ No newline at end of file +} diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 0150727..c525de5 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -15,12 +15,10 @@ import "package:inventree/preferences.dart"; import "package:inventree/widget/refreshable_state.dart"; - /* * Abstract base widget class for rendering a PaginatedSearchState */ abstract class PaginatedSearchWidget extends StatefulWidget { - const PaginatedSearchWidget({this.filters = const {}, this.title = ""}); final String title; @@ -30,12 +28,12 @@ abstract class PaginatedSearchWidget extends StatefulWidget { final Map filters; } - /* * Generic stateful widget for displaying paginated data retrieved via the API */ -abstract class PaginatedSearchState extends State with BaseWidgetProperties { - +abstract class PaginatedSearchState + extends State + with BaseWidgetProperties { static const _pageSize = 25; bool showSearchWidget = false; @@ -73,7 +71,6 @@ abstract class PaginatedSearchState extends Sta // Construct the boolean filter options for this list Future> constructFilters() async { - Map f = {}; for (String k in filterOptions.keys) { @@ -95,7 +92,10 @@ abstract class PaginatedSearchState extends Sta // Return the selected ordering "field" for this list widget Future orderingField() async { - dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", null); + dynamic field = await InvenTreeSettingsManager().getValue( + "${prefix}ordering_field", + null, + ); if (field != null && orderingOptions.containsKey(field.toString())) { // A valid ordering field has been found @@ -110,7 +110,10 @@ abstract class PaginatedSearchState extends Sta // Return the selected ordering "order" ("+" or "-") for this list widget Future orderingOrder() async { - dynamic order = await InvenTreeSettingsManager().getValue("${prefix}ordering_order", "+"); + dynamic order = await InvenTreeSettingsManager().getValue( + "${prefix}ordering_order", + "+", + ); return order == "+" ? "+" : "-"; } @@ -137,10 +140,10 @@ abstract class PaginatedSearchState extends Sta // Construct the 'ordering' options List> _opts = []; - orderingOptions.forEach((k, v) => _opts.add({ - "value": k.toString(), - "display_name": v.toString() - })); + orderingOptions.forEach( + (k, v) => + _opts.add({"value": k.toString(), "display_name": v.toString()}), + ); if (_field == null && _opts.isNotEmpty) { _field = _opts.first["value"]; @@ -160,16 +163,10 @@ abstract class PaginatedSearchState extends Sta "required": true, "value": _order, "choices": [ - { - "value": "+", - "display_name": "Ascending", - }, - { - "value": "-", - "display_name": "Descending", - } - ] - } + {"value": "+", "display_name": "Ascending"}, + {"value": "-", "display_name": "Descending"}, + ], + }, }; // Add in selected filter options @@ -219,7 +216,6 @@ abstract class PaginatedSearchState extends Sta fields, icon: TablerIcons.circle_check, onSuccess: (Map data) async { - // Extract data from the processed form String f = (data["ordering_field"] ?? _field) as String; String o = (data["ordering_order"] ?? _order) as String; @@ -235,7 +231,7 @@ abstract class PaginatedSearchState extends Sta // Refresh data from the server _pagingController.refresh(); - } + }, ); } @@ -245,7 +241,6 @@ abstract class PaginatedSearchState extends Sta int resultCount = 0; String resultsString() { - if (resultCount <= 0) { return noResultsText; } else { @@ -260,7 +255,8 @@ abstract class PaginatedSearchState extends Sta Timer? _debounceTimer; // Pagination controller - final PagingController _pagingController = PagingController(firstPageKey: 0); + final PagingController _pagingController = + PagingController(firstPageKey: 0); void refresh() { _pagingController.refresh(); @@ -286,8 +282,11 @@ abstract class PaginatedSearchState extends Sta * Each implementing class must override this function, * and return an InvenTreePageResponse object with the correct data format */ - Future requestPage(int limit, int offset, Map params) async { - + Future requestPage( + int limit, + int offset, + Map params, + ) async { // Default implementation returns null - must be overridden return null; } @@ -301,7 +300,6 @@ abstract class PaginatedSearchState extends Sta // Include user search term if (searchTerm.isNotEmpty) { - String _search = searchTerm; // Include original search in search test @@ -329,11 +327,7 @@ abstract class PaginatedSearchState extends Sta params.addAll(f); } - final page = await requestPage( - _pageSize, - pageKey, - params - ); + final page = await requestPage(_pageSize, pageKey, params); // We may have disposed of the widget while the request was in progress // If this is the case, abort @@ -350,7 +344,7 @@ abstract class PaginatedSearchState extends Sta if (page != null) { for (var result in page.results) { - items.add(result); + items.add(result); } } @@ -367,16 +361,12 @@ abstract class PaginatedSearchState extends Sta } catch (error, stackTrace) { _pagingController.error = error; - sentryReportError( - "paginator.fetchPage", - error, stackTrace, - ); + sentryReportError("paginator.fetchPage", error, stackTrace); } } // Callback function when the search term is updated void updateSearchTerm() { - if (searchTerm == searchController.text) { // No change return; @@ -410,7 +400,6 @@ abstract class PaginatedSearchState extends Sta // Function to construct a single paginated item // Must be overridden in an implementing subclass Widget buildItem(BuildContext context, InvenTreeModel item) { - // This method must be overridden by the child class return ListTile( title: Text("*** UNIMPLEMENTED ***"), @@ -423,12 +412,8 @@ abstract class PaginatedSearchState extends Sta String get noResultsText => L10().noResults; @override - Widget build (BuildContext context) { - - List children = [ - buildTitleWidget(context), - Divider(), - ]; + Widget build(BuildContext context) { + List children = [buildTitleWidget(context), Divider()]; if (showSearchWidget) { children.add(buildSearchInput(context)); @@ -436,26 +421,26 @@ abstract class PaginatedSearchState extends Sta children.add( Expanded( - child: CustomScrollView( - shrinkWrap: true, - physics: AlwaysScrollableScrollPhysics(), - scrollDirection: Axis.vertical, - slivers: [ - PagedSliverList.separated( - pagingController: _pagingController, - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (ctx, item, index) { - return buildItem(ctx, item); - }, - noItemsFoundIndicatorBuilder: (context) { - return NoResultsWidget(noResultsText); - } - ), - separatorBuilder: (context, item) => const Divider(height: 1), - ) - ] - ) - ) + child: CustomScrollView( + shrinkWrap: true, + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + slivers: [ + PagedSliverList.separated( + pagingController: _pagingController, + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (ctx, item, index) { + return buildItem(ctx, item); + }, + noItemsFoundIndicatorBuilder: (context) { + return NoResultsWidget(noResultsText); + }, + ), + separatorBuilder: (context, item) => const Divider(height: 1), + ), + ], + ), + ), ); return RefreshIndicator( @@ -473,28 +458,34 @@ abstract class PaginatedSearchState extends Sta * Build the title widget for this list */ Widget buildTitleWidget(BuildContext context) { - const double icon_size = 32; List _icons = []; if (filterOptions.isNotEmpty || orderingOptions.isNotEmpty) { - _icons.add(IconButton( - onPressed: () async { - _setOrderingOptions(context); - }, - icon: Icon(Icons.filter_alt, size: icon_size) - )); + _icons.add( + IconButton( + onPressed: () async { + _setOrderingOptions(context); + }, + icon: Icon(Icons.filter_alt, size: icon_size), + ), + ); } - _icons.add(IconButton( + _icons.add( + IconButton( onPressed: () { setState(() { showSearchWidget = !showSearchWidget; }); }, - icon: Icon(showSearchWidget ? Icons.zoom_out : Icons.search, size: icon_size) - )); + icon: Icon( + showSearchWidget ? Icons.zoom_out : Icons.search, + size: icon_size, + ), + ), + ); // _icons.add(IconButton( // onPressed: () async { @@ -506,20 +497,13 @@ abstract class PaginatedSearchState extends Sta return ListTile( title: Text( widget.searchTitle, - style: TextStyle( - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( "${L10().results}: ${resultCount}", - style: TextStyle( - fontStyle: FontStyle.italic - ), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: _icons, + style: TextStyle(fontStyle: FontStyle.italic), ), + trailing: Row(mainAxisSize: MainAxisSize.min, children: _icons), ); } @@ -530,7 +514,9 @@ abstract class PaginatedSearchState extends Sta return ListTile( trailing: GestureDetector( child: Icon( - searchController.text.isEmpty ? TablerIcons.search : TablerIcons.backspace, + searchController.text.isEmpty + ? TablerIcons.search + : TablerIcons.backspace, color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_ACTION, ), onTap: () { @@ -545,31 +531,22 @@ abstract class PaginatedSearchState extends Sta onChanged: (value) { updateSearchTerm(); }, - decoration: InputDecoration( - hintText: L10().search, - ), - ) + decoration: InputDecoration(hintText: L10().search), + ), ); } } - class NoResultsWidget extends StatelessWidget { - const NoResultsWidget(this.description); final String description; @override Widget build(BuildContext context) { - return ListTile( - title: Text( - description, - style: TextStyle(fontStyle: FontStyle.italic), - ), + title: Text(description, style: TextStyle(fontStyle: FontStyle.italic)), leading: Icon(TablerIcons.exclamation_circle, color: COLOR_WARNING), ); } - } diff --git a/lib/widget/part/bom_list.dart b/lib/widget/part/bom_list.dart index 77a169b..5e17e53 100644 --- a/lib/widget/part/bom_list.dart +++ b/lib/widget/part/bom_list.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -14,13 +13,15 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; - /* * Widget for displaying a Bill of Materials for a specified Part instance */ class BillOfMaterialsWidget extends StatefulWidget { - - const BillOfMaterialsWidget(this.part, {this.isParentComponent = true, Key? key}) : super(key: key); + const BillOfMaterialsWidget( + this.part, { + this.isParentComponent = true, + Key? key, + }) : super(key: key); final InvenTreePart part; @@ -53,12 +54,11 @@ class _BillOfMaterialsState extends RefreshableState { showFilterOptions = !showFilterOptions; }); }, - ) + ), ]; @override Widget getBody(BuildContext context) { - Map filters = {}; if (widget.isParentComponent) { @@ -72,7 +72,11 @@ class _BillOfMaterialsState extends RefreshableState { ListTile( leading: InvenTreeAPI().getThumbnail(widget.part.thumbnail), title: Text(widget.part.fullname), - subtitle: Text(widget.isParentComponent ? L10().billOfMaterials : L10().usedInDetails), + subtitle: Text( + widget.isParentComponent + ? L10().billOfMaterials + : L10().usedInDetails, + ), trailing: Text(L10().quantity), ), Divider(thickness: 1.25), @@ -87,13 +91,14 @@ class _BillOfMaterialsState extends RefreshableState { } } - /* * Create a paginated widget displaying a list of BomItem objects */ class PaginatedBomList extends PaginatedSearchWidget { - - const PaginatedBomList(Map filters, {this.isParentPart = true}) : super(filters: filters); + const PaginatedBomList( + Map filters, { + this.isParentPart = true, + }) : super(filters: filters); final bool isParentPart; @@ -104,9 +109,7 @@ class PaginatedBomList extends PaginatedSearchWidget { _PaginatedBomListState createState() => _PaginatedBomListState(); } - class _PaginatedBomListState extends PaginatedSearchState { - _PaginatedBomListState() : super(); @override @@ -123,23 +126,31 @@ class _PaginatedBomListState extends PaginatedSearchState { "sub_part_assembly": { "label": L10().filterAssembly, "help_text": L10().filterAssemblyDetail, - } + }, }; @override - Future requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreeBomItem().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeBomItem().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeBomItem bomItem = model as InvenTreeBomItem; - InvenTreePart? subPart = widget.isParentPart ? bomItem.subPart : bomItem.part; + InvenTreePart? subPart = widget.isParentPart + ? bomItem.subPart + : bomItem.part; String title = subPart?.fullname ?? "error - no name"; @@ -151,16 +162,17 @@ class _PaginatedBomListState extends PaginatedSearchState { style: TextStyle(fontWeight: FontWeight.bold), ), leading: InvenTreeAPI().getThumbnail(subPart?.thumbnail ?? ""), - onTap: subPart == null ? null : () async { + onTap: subPart == null + ? null + : () async { + showLoadingOverlay(); + var part = await InvenTreePart().get(subPart.pk); + hideLoadingOverlay(); - showLoadingOverlay(); - var part = await InvenTreePart().get(subPart.pk); - hideLoadingOverlay(); - - if (part is InvenTreePart) { - part.goToDetailPage(context); - } - }, + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + }, ); } -} \ No newline at end of file +} diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart index 7ca833e..19138c9 100644 --- a/lib/widget/part/category_display.dart +++ b/lib/widget/part/category_display.dart @@ -13,9 +13,7 @@ import "package:inventree/widget/progress.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/refreshable_state.dart"; - class CategoryDisplayWidget extends StatefulWidget { - const CategoryDisplayWidget(this.category, {Key? key}) : super(key: key); final InvenTreePartCategory? category; @@ -24,9 +22,7 @@ class CategoryDisplayWidget extends StatefulWidget { _CategoryDisplayState createState() => _CategoryDisplayState(); } - class _CategoryDisplayState extends RefreshableState { - _CategoryDisplayState(); @override @@ -40,12 +36,12 @@ class _CategoryDisplayState extends RefreshableState { if (InvenTreePartCategory().canEdit) { actions.add( IconButton( - icon: Icon(TablerIcons.edit), + icon: Icon(TablerIcons.edit), tooltip: L10().editCategory, onPressed: () { _editCategoryDialog(context); }, - ) + ), ); } } @@ -58,13 +54,13 @@ class _CategoryDisplayState extends RefreshableState { List actions = []; if (InvenTreePart().canCreate) { - actions.add( - SpeedDialChild( - child: Icon(TablerIcons.box), - label: L10().partCreateDetail, - onTap: _newPart, - ) - ); + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.box), + label: L10().partCreateDetail, + onTap: _newPart, + ), + ); } if (InvenTreePartCategory().canCreate) { @@ -74,8 +70,8 @@ class _CategoryDisplayState extends RefreshableState { label: L10().categoryCreateDetail, onTap: () { _newCategory(context); - } - ) + }, + ), ); } @@ -91,12 +87,12 @@ class _CategoryDisplayState extends RefreshableState { } _cat.editForm( - context, - L10().editCategory, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().categoryUpdated, success: true); - } + context, + L10().editCategory, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().categoryUpdated, success: true); + }, ); } @@ -107,7 +103,6 @@ class _CategoryDisplayState extends RefreshableState { @override Future request(BuildContext context) async { - // Update the category if (widget.category != null) { final bool result = await widget.category?.reload() ?? false; @@ -126,79 +121,69 @@ class _CategoryDisplayState extends RefreshableState { title: Text( L10().partCategoryTopLevel, style: TextStyle(fontStyle: FontStyle.italic), - ) - ) + ), + ), ); } else { - List children = [ ListTile( - title: Text("${widget.category?.name}", - style: TextStyle(fontWeight: FontWeight.bold) + title: Text( + "${widget.category?.name}", + style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text("${widget.category?.description}"), - leading: widget.category!.customIcon != null ? Icon(widget.category!.customIcon) : Icon(TablerIcons.sitemap) + leading: widget.category!.customIcon != null + ? Icon(widget.category!.customIcon) + : Icon(TablerIcons.sitemap), ), ]; if (extra) { children.add( - ListTile( - title: Text(L10().parentCategory), - subtitle: Text("${widget.category?.parentPathString}"), - leading: Icon( - TablerIcons.arrow_move_up, - color: COLOR_ACTION, - ), - onTap: () async { + ListTile( + title: Text(L10().parentCategory), + subtitle: Text("${widget.category?.parentPathString}"), + leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), + onTap: () async { + int parentId = widget.category?.parentId ?? -1; - int parentId = widget.category?.parentId ?? -1; + if (parentId < 0) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CategoryDisplayWidget(null), + ), + ); + } else { + showLoadingOverlay(); + var cat = await InvenTreePartCategory().get(parentId); + hideLoadingOverlay(); - if (parentId < 0) { - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); - } else { - - showLoadingOverlay(); - var cat = await InvenTreePartCategory().get(parentId); - hideLoadingOverlay(); - - if (cat is InvenTreePartCategory) { - cat.goToDetailPage(context); - } + if (cat is InvenTreePartCategory) { + cat.goToDetailPage(context); } - }, - ) + } + }, + ), ); } - return Card( - child: Column( - children: children - ), - ); + return Card(child: Column(children: children)); } } @override List getTabIcons(BuildContext context) { - - return [ - Tab(text: L10().details), - Tab(text: L10().parts), - ]; + return [Tab(text: L10().details), Tab(text: L10().parts)]; } @override List getTabs(BuildContext context) { - return [ - Column(children: detailTiles()), - Column(children: partsTiles()), - ]; + return [Column(children: detailTiles()), Column(children: partsTiles())]; } // Construct the "details" panel List detailTiles() { - Map filters = {}; int? parent = widget.category?.pk; @@ -212,12 +197,9 @@ class _CategoryDisplayState extends RefreshableState { List tiles = [ getCategoryDescriptionCard(), Expanded( - child: PaginatedPartCategoryList( - filters, - title: L10().subcategories, - ), + child: PaginatedPartCategoryList(filters, title: L10().subcategories), flex: 10, - ) + ), ]; return tiles; @@ -225,31 +207,21 @@ class _CategoryDisplayState extends RefreshableState { // Construct the "parts" panel List partsTiles() { - Map filters = { "category": widget.category?.pk.toString() ?? "null", }; - return [ - Expanded( - child: PaginatedPartList(filters), - flex: 10, - ) - ]; + return [Expanded(child: PaginatedPartList(filters), flex: 10)]; } Future _newCategory(BuildContext context) async { - int pk = widget.category?.pk ?? -1; InvenTreePartCategory().createForm( context, L10().categoryCreate, - data: { - "parent": (pk > 0) ? pk : null, - }, + data: {"parent": (pk > 0) ? pk : null}, onSuccess: (result) async { - Map data = result as Map; if (data.containsKey("pk")) { @@ -260,29 +232,25 @@ class _CategoryDisplayState extends RefreshableState { } else { refresh(context); } - } + }, ); } Future _newPart() async { - int pk = widget.category?.pk ?? -1; InvenTreePart().createForm( context, L10().partCreate, - data: { - "category": (pk > 0) ? pk : null - }, + data: {"category": (pk > 0) ? pk : null}, onSuccess: (result) async { - Map data = result as Map; if (data.containsKey("pk")) { var part = InvenTreePart.fromJson(data); part.goToDetailPage(context); } - } + }, ); } } diff --git a/lib/widget/part/category_list.dart b/lib/widget/part/category_list.dart index c0aaa86..41442d9 100644 --- a/lib/widget/part/category_list.dart +++ b/lib/widget/part/category_list.dart @@ -9,19 +9,15 @@ import "package:inventree/api.dart"; import "package:inventree/l10.dart"; class PartCategoryList extends StatefulWidget { - const PartCategoryList(this.filters); final Map filters; @override _PartCategoryListState createState() => _PartCategoryListState(); - } - class _PartCategoryListState extends RefreshableState { - _PartCategoryListState(); @override @@ -34,19 +30,21 @@ class _PartCategoryListState extends RefreshableState { } class PaginatedPartCategoryList extends PaginatedSearchWidget { - - const PaginatedPartCategoryList(Map filters, {String title = ""}) : super(filters: filters, title: title); + const PaginatedPartCategoryList( + Map filters, { + String title = "", + }) : super(filters: filters, title: title); @override String get searchTitle => title.isNotEmpty ? title : L10().partCategories; @override - _PaginatedPartCategoryListState createState() => _PaginatedPartCategoryListState(); + _PaginatedPartCategoryListState createState() => + _PaginatedPartCategoryListState(); } - -class _PaginatedPartCategoryListState extends PaginatedSearchState { - +class _PaginatedPartCategoryListState + extends PaginatedSearchState { // _PaginatedPartCategoryListState(Map filters, bool searchEnabled) : super(filters, searchEnabled); @override @@ -59,16 +57,12 @@ class _PaginatedPartCategoryListState extends PaginatedSearchState get orderingOptions { - - Map options = { - "name": L10().name, - "level": L10().level, - }; + Map options = {"name": L10().name, "level": L10().level}; // Note: API v69 changed 'parts' to 'part_count' if (InvenTreeAPI().apiVersion >= 69) { @@ -81,16 +75,22 @@ class _PaginatedPartCategoryListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreePartCategory().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreePartCategory().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePartCategory category = model as InvenTreePartCategory; return ListTile( @@ -103,4 +103,4 @@ class _PaginatedPartCategoryListState extends PaginatedSearchState _PartDisplayState(part); - } - class _PartDisplayState extends RefreshableState { - _PartDisplayState(this.part); InvenTreePart part; @@ -76,13 +71,13 @@ class _PartDisplayState extends RefreshableState { if (InvenTreePart().canEdit) { actions.add( - IconButton( - icon: Icon(TablerIcons.edit), - tooltip: L10().editPart, - onPressed: () { - _editPartDialog(context); - } - ) + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editPart, + onPressed: () { + _editPartDialog(context); + }, + ), ); } return actions; @@ -94,11 +89,13 @@ class _PartDisplayState extends RefreshableState { if (InvenTreePart().canEdit) { actions.add( - customBarcodeAction( - context, this, - widget.part.customBarcode, "part", - widget.part.pk - ) + customBarcodeAction( + context, + this, + widget.part.customBarcode, + "part", + widget.part.pk, + ), ); } @@ -111,13 +108,13 @@ class _PartDisplayState extends RefreshableState { if (InvenTreeStockItem().canCreate) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.packages), - label: L10().stockItemCreate, - onTap: () { - _newStockItem(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.packages), + label: L10().stockItemCreate, + onTap: () { + _newStockItem(context); + }, + ), ); } @@ -132,10 +129,10 @@ class _PartDisplayState extends RefreshableState { labels, widget.part.pk, "part", - "part=${widget.part.pk}" + "part=${widget.part.pk}", ); - } - ) + }, + ), ); } @@ -153,14 +150,22 @@ class _PartDisplayState extends RefreshableState { @override Future request(BuildContext context) async { - final bool result = await part.reload(); // Load page settings from local storage - showPricing = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PRICING, true); - showParameters = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_PARAMETERS, true); + showPricing = await InvenTreeSettingsManager().getBool( + INV_PART_SHOW_PRICING, + true, + ); + showParameters = await InvenTreeSettingsManager().getBool( + INV_PART_SHOW_PARAMETERS, + true, + ); showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); - allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + allowLabelPrinting = await InvenTreeSettingsManager().getBool( + INV_ENABLE_LABEL_PRINTING, + true, + ); if (!result || part.pk == -1) { // Part could not be loaded, for some reason @@ -211,11 +216,9 @@ class _PartDisplayState extends RefreshableState { } // Request the number of BOM items - InvenTreePart().count( - filters: { - "in_bom_for": part.pk.toString(), - } - ).then((int value) { + InvenTreePart().count(filters: {"in_bom_for": part.pk.toString()}).then(( + int value, + ) { if (mounted) { setState(() { bomCount = value; @@ -224,11 +227,9 @@ class _PartDisplayState extends RefreshableState { }); // Request number of "used in" parts - InvenTreeBomItem().count( - filters: { - "uses": part.pk.toString(), - } - ).then((int value) { + InvenTreeBomItem().count(filters: {"uses": part.pk.toString()}).then(( + int value, + ) { if (mounted) { setState(() { usedInCount = value; @@ -237,11 +238,9 @@ class _PartDisplayState extends RefreshableState { }); // Request the number of variant items - InvenTreePart().count( - filters: { - "variant_of": part.pk.toString(), - } - ).then((int value) { + InvenTreePart().count(filters: {"variant_of": part.pk.toString()}).then(( + int value, + ) { if (mounted) { setState(() { variantCount = value; @@ -253,16 +252,14 @@ class _PartDisplayState extends RefreshableState { allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { - - String model_type = api.supportsModernLabelPrinting ? InvenTreePart.MODEL_TYPE : "part"; + String model_type = api.supportsModernLabelPrinting + ? InvenTreePart.MODEL_TYPE + : "part"; String item_key = api.supportsModernLabelPrinting ? "items" : "part"; - _labels = await getLabelTemplates( - model_type, - { - item_key: widget.part.pk.toString() - } - ); + _labels = await getLabelTemplates(model_type, { + item_key: widget.part.pk.toString(), + }); } if (mounted) { @@ -273,41 +270,34 @@ class _PartDisplayState extends RefreshableState { } void _editPartDialog(BuildContext context) { - part.editForm( context, L10().editPart, onSuccess: (data) async { refresh(context); showSnackIcon(L10().partEdited, success: true); - } + }, ); } Widget headerTile() { return Card( - child: ListTile( - title: Text(part.fullname), - subtitle: Text(part.description), - trailing: Text( - part.stockString(), - style: TextStyle( - fontSize: 20, - ) - ), - leading: GestureDetector( - child: api.getImage(part.thumbnail), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartImageWidget(part) - ) - ).then((value) { - refresh(context); - }); - }), + child: ListTile( + title: Text(part.fullname), + subtitle: Text(part.description), + trailing: Text(part.stockString(), style: TextStyle(fontSize: 20)), + leading: GestureDetector( + child: api.getImage(part.thumbnail), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => PartImageWidget(part)), + ).then((value) { + refresh(context); + }); + }, ), + ), ); } @@ -315,13 +305,10 @@ class _PartDisplayState extends RefreshableState { * Build a list of tiles to display under the part description */ List partTiles() { - List tiles = []; // Image / name / description - tiles.add( - headerTile() - ); + tiles.add(headerTile()); if (loading) { tiles.add(progressIndicator()); @@ -331,23 +318,13 @@ class _PartDisplayState extends RefreshableState { if (!part.isActive) { tiles.add( ListTile( - title: Text( - L10().inactive, - style: TextStyle( - color: COLOR_DANGER - ) - ), + title: Text(L10().inactive, style: TextStyle(color: COLOR_DANGER)), subtitle: Text( L10().inactiveDetail, - style: TextStyle( - color: COLOR_DANGER - ) + style: TextStyle(color: COLOR_DANGER), ), - leading: Icon( - TablerIcons.exclamation_circle, - color: COLOR_DANGER - ), - ) + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + ), ); } @@ -356,15 +333,11 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().templatePart), subtitle: Text(parentPart!.fullname), - leading: api.getImage( - parentPart!.thumbnail, - width: 32, - height: 32, - ), + leading: api.getImage(parentPart!.thumbnail, width: 32, height: 32), onTap: () { parentPart?.goToDetailPage(context); - } - ) + }, + ), ); } @@ -372,58 +345,58 @@ class _PartDisplayState extends RefreshableState { if (part.categoryName.isNotEmpty) { tiles.add( ListTile( - title: Text(L10().partCategory), - subtitle: Text("${part.categoryName}"), - leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), - onTap: () async { - if (part.categoryId > 0) { + title: Text(L10().partCategory), + subtitle: Text("${part.categoryName}"), + leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), + onTap: () async { + if (part.categoryId > 0) { + showLoadingOverlay(); + var cat = await InvenTreePartCategory().get(part.categoryId); + hideLoadingOverlay(); - showLoadingOverlay(); - var cat = await InvenTreePartCategory().get(part.categoryId); - hideLoadingOverlay(); - - if (cat is InvenTreePartCategory) { - cat.goToDetailPage(context); - } + if (cat is InvenTreePartCategory) { + cat.goToDetailPage(context); } - }, - ) + } + }, + ), ); } else { tiles.add( - ListTile( - title: Text(L10().partCategory), - subtitle: Text(L10().partCategoryTopLevel), - leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(null))); - }, - ) + ListTile( + title: Text(L10().partCategory), + subtitle: Text(L10().partCategoryTopLevel), + leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CategoryDisplayWidget(null), + ), + ); + }, + ), ); } // Display number of "variant" parts if any exist if (variantCount > 0) { tiles.add( - ListTile( - title: Text(L10().variants), - leading: Icon(TablerIcons.versions, color: COLOR_ACTION), - trailing: Text(variantCount.toString()), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartList( - { - "variant_of": part.pk.toString(), - }, - title: L10().variants - ) - ) - ); - }, - ) + ListTile( + title: Text(L10().variants), + leading: Icon(TablerIcons.versions, color: COLOR_ACTION), + trailing: Text(variantCount.toString()), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PartList({ + "variant_of": part.pk.toString(), + }, title: L10().variants), + ), + ); + }, + ), ); } @@ -434,19 +407,16 @@ class _PartDisplayState extends RefreshableState { leading: Icon(TablerIcons.packages), trailing: Text( part.stockString(), - style: TextStyle( - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontWeight: FontWeight.bold), ), ), ); if (showPricing && partPricing != null) { - String pricing = formatPriceRange( partPricing?.overallMin, partPricing?.overallMax, - currency: partPricing?.currency + currency: partPricing?.currency, ); tiles.add( @@ -455,15 +425,14 @@ class _PartDisplayState extends RefreshableState { leading: Icon(TablerIcons.currency_dollar, color: COLOR_ACTION), trailing: Text( pricing.isNotEmpty ? pricing : L10().noPricingAvailable, - style: TextStyle( - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontWeight: FontWeight.bold), ), onTap: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => PartPricingWidget(part: part, partPricing: partPricing), + builder: (context) => + PartPricingWidget(part: part, partPricing: partPricing), ), ); }, @@ -473,7 +442,6 @@ class _PartDisplayState extends RefreshableState { // Tiles for "purchaseable" parts if (part.isPurchaseable) { - // On order tiles.add( ListTile( @@ -484,39 +452,41 @@ class _PartDisplayState extends RefreshableState { onTap: () { // TODO - Order views }, - ) + ), ); - } // Tiles for an "assembly" part if (part.isAssembly) { - if (showBom && bomCount > 0) { tiles.add( - ListTile( - title: Text(L10().billOfMaterials), - leading: Icon(TablerIcons.list_tree, color: COLOR_ACTION), - trailing: Text(bomCount.toString()), - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) => BillOfMaterialsWidget(part, isParentComponent: true) - )); - }, - ) + ListTile( + title: Text(L10().billOfMaterials), + leading: Icon(TablerIcons.list_tree, color: COLOR_ACTION), + trailing: Text(bomCount.toString()), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + BillOfMaterialsWidget(part, isParentComponent: true), + ), + ); + }, + ), ); } if (part.building > 0) { tiles.add( - ListTile( - title: Text(L10().building), - leading: Icon(TablerIcons.tools), - trailing: Text("${simpleNumberString(part.building)}"), - onTap: () { - // TODO - }, - ) + ListTile( + title: Text(L10().building), + leading: Icon(TablerIcons.tools), + trailing: Text("${simpleNumberString(part.building)}"), + onTap: () { + // TODO + }, + ), ); } } @@ -529,15 +499,16 @@ class _PartDisplayState extends RefreshableState { subtitle: Text(L10().usedInDetails), leading: Icon(TablerIcons.stack_2, color: COLOR_ACTION), trailing: Text(usedInCount.toString()), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => BillOfMaterialsWidget(part, isParentComponent: false) - ) - ); - } - ) + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + BillOfMaterialsWidget(part, isParentComponent: false), + ), + ); + }, + ), ); } } @@ -545,29 +516,28 @@ class _PartDisplayState extends RefreshableState { // Keywords? if (part.keywords.isNotEmpty) { tiles.add( - ListTile( - title: Text("${part.keywords}"), - leading: Icon(TablerIcons.tags), - ) + ListTile( + title: Text("${part.keywords}"), + leading: Icon(TablerIcons.tags), + ), ); } // External link? if (part.link.isNotEmpty) { tiles.add( - ListTile( - title: Text("${part.link}"), - leading: Icon(TablerIcons.link, color: COLOR_ACTION), - onTap: () { - part.openLink(); - }, - ) + ListTile( + title: Text("${part.link}"), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () { + part.openLink(); + }, + ), ); } // Tiles for "component" part if (part.isComponent && part.usedInCount > 0) { - tiles.add( ListTile( title: Text(L10().usedIn), @@ -577,44 +547,44 @@ class _PartDisplayState extends RefreshableState { onTap: () { // TODO }, - ) + ), ); } if (part.isPurchaseable) { - if (part.supplierCount > 0) { tiles.add( - ListTile( - title: Text(L10().suppliers), - leading: Icon(TablerIcons.building_factory, color: COLOR_ACTION), - trailing: Text("${part.supplierCount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => SupplierPartList({ - "part": part.pk.toString() - })) - ); - }, - ) + ListTile( + title: Text(L10().suppliers), + leading: Icon(TablerIcons.building_factory, color: COLOR_ACTION), + trailing: Text("${part.supplierCount}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + SupplierPartList({"part": part.pk.toString()}), + ), + ); + }, + ), ); } } // Notes field tiles.add( - ListTile( - title: Text(L10().notes), - leading: Icon(TablerIcons.note, color: COLOR_ACTION), - trailing: Text(""), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => NotesWidget(part)) - ); - }, - ) + ListTile( + title: Text(L10().notes), + leading: Icon(TablerIcons.note, color: COLOR_ACTION), + trailing: Text(""), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NotesWidget(part)), + ); + }, + ), ); tiles.add( @@ -627,19 +597,18 @@ class _PartDisplayState extends RefreshableState { context, MaterialPageRoute( builder: (context) => AttachmentWidget( - InvenTreePartAttachment(), - part.pk, - L10().part, - part.canEdit - ) - ) + InvenTreePartAttachment(), + part.pk, + L10().part, + part.canEdit, + ), + ), ); }, - ) + ), ); return tiles; - } // Return tiles for each stock item @@ -654,9 +623,13 @@ class _PartDisplayState extends RefreshableState { L10().stockItems, style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: part.stockItems.isEmpty ? Text(L10().stockItemsNotAvailable) : null, - trailing: part.stockItems.isNotEmpty ? Text("${part.stockItems.length}") : null, - ) + subtitle: part.stockItems.isEmpty + ? Text(L10().stockItemsNotAvailable) + : null, + trailing: part.stockItems.isNotEmpty + ? Text("${part.stockItems.length}") + : null, + ), ); return tiles; @@ -666,7 +639,6 @@ class _PartDisplayState extends RefreshableState { * Launch a form to create a new StockItem for this part */ Future _newStockItem(BuildContext context) async { - var fields = InvenTreeStockItem().formFields(); // Serial number cannot be directly edited here @@ -677,9 +649,7 @@ class _PartDisplayState extends RefreshableState { int? default_location = part.defaultLocation; - Map data = { - "part": part.pk.toString() - }; + Map data = {"part": part.pk.toString()}; if (default_location != null) { data["location"] = default_location; @@ -688,15 +658,22 @@ class _PartDisplayState extends RefreshableState { if (part.isTrackable) { // read the next available serial number showLoadingOverlay(); - var response = await api.get("/api/part/${part.pk}/serial-numbers/", expectedStatusCode: null); + var response = await api.get( + "/api/part/${part.pk}/serial-numbers/", + expectedStatusCode: null, + ); hideLoadingOverlay(); if (response.isValid() && response.statusCode == 200) { - data["serial_numbers"] = response.data["next"] ?? response.data["latest"]; + data["serial_numbers"] = + response.data["next"] ?? response.data["latest"]; } - print("response: " + response.statusCode.toString() + response.data.toString()); - + print( + "response: " + + response.statusCode.toString() + + response.data.toString(), + ); } else { // Cannot set serial numbers for non-trackable parts fields.remove("serial_numbers"); @@ -705,28 +682,24 @@ class _PartDisplayState extends RefreshableState { print("data: ${data.toString()}"); InvenTreeStockItem().createForm( - context, - L10().stockItemCreate, - fields: fields, - data: data, - onSuccess: (result) async { + context, + L10().stockItemCreate, + fields: fields, + data: data, + onSuccess: (result) async { + Map data = result as Map; - Map data = result as Map; - - if (data.containsKey("pk")) { - var item = InvenTreeStockItem.fromJson(data); - item.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var item = InvenTreeStockItem.fromJson(data); + item.goToDetailPage(context); } + }, ); } @override List getTabIcons(BuildContext context) { - List icons = [ - Tab(text: L10().details), - Tab(text: L10().stock) - ]; + List icons = [Tab(text: L10().details), Tab(text: L10().stock)]; if (showParameters) { icons.add(Tab(text: L10().parameters)); @@ -740,11 +713,9 @@ class _PartDisplayState extends RefreshableState { List tabs = [ SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), - child: Column( - children: partTiles(), - ) + child: Column(children: partTiles()), ), - PaginatedStockItemList({"part": part.pk.toString()}) + PaginatedStockItemList({"part": part.pk.toString()}), ]; if (showParameters) { @@ -753,5 +724,4 @@ class _PartDisplayState extends RefreshableState { return tabs; } - } diff --git a/lib/widget/part/part_image_widget.dart b/lib/widget/part/part_image_widget.dart index 41da371..885f7bf 100644 --- a/lib/widget/part/part_image_widget.dart +++ b/lib/widget/part/part_image_widget.dart @@ -11,19 +11,15 @@ import "package:inventree/widget/snacks.dart"; import "package:inventree/l10.dart"; class PartImageWidget extends StatefulWidget { - const PartImageWidget(this.part, {Key? key}) : super(key: key); final InvenTreePart part; @override _PartImageState createState() => _PartImageState(part); - } - class _PartImageState extends RefreshableState { - _PartImageState(this.part); final InvenTreePart part; @@ -38,17 +34,14 @@ class _PartImageState extends RefreshableState { @override List appBarActions(BuildContext context) { - List actions = []; if (part.canEdit) { - // File upload actions.add( IconButton( icon: Icon(TablerIcons.file_upload), onPressed: () async { - FilePickerDialog.pickFile( onPicked: (File file) async { final result = await part.uploadImage(file); @@ -58,11 +51,10 @@ class _PartImageState extends RefreshableState { } refresh(context); - } + }, ); - }, - ) + ), ); } @@ -73,5 +65,4 @@ class _PartImageState extends RefreshableState { Widget getBody(BuildContext context) { return InvenTreeAPI().getImage(part.image); } - -} \ No newline at end of file +} diff --git a/lib/widget/part/part_list.dart b/lib/widget/part/part_list.dart index 8433e0b..e454522 100644 --- a/lib/widget/part/part_list.dart +++ b/lib/widget/part/part_list.dart @@ -9,9 +9,7 @@ import "package:inventree/inventree/part.dart"; import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; - class PartList extends StatefulWidget { - const PartList(this.filters, {this.title = ""}); final String title; @@ -22,9 +20,7 @@ class PartList extends StatefulWidget { _PartListState createState() => _PartListState(filters, title); } - class _PartListState extends RefreshableState { - _PartListState(this.filters, this.title); final String title; @@ -40,13 +36,11 @@ class _PartListState extends RefreshableState { Widget getBody(BuildContext context) { return PaginatedPartList(filters); } - } - class PaginatedPartList extends PaginatedSearchWidget { - - const PaginatedPartList(Map filters) : super(filters: filters); + const PaginatedPartList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().parts; @@ -55,9 +49,7 @@ class PaginatedPartList extends PaginatedSearchWidget { _PaginatedPartListState createState() => _PaginatedPartListState(); } - class _PaginatedPartListState extends PaginatedSearchState { - _PaginatedPartListState() : super(); @override @@ -84,7 +76,7 @@ class _PaginatedPartListState extends PaginatedSearchState { }, "assembly": { "label": L10().filterAssembly, - "help_text": L10().filterAssemblyDetail + "help_text": L10().filterAssemblyDetail, }, "component": { "label": L10().filterComponent, @@ -92,7 +84,7 @@ class _PaginatedPartListState extends PaginatedSearchState { }, "is_template": { "label": L10().filterTemplate, - "help_text": L10().filterTemplateDetail + "help_text": L10().filterTemplateDetail, }, "trackable": { "label": L10().filterTrackable, @@ -105,18 +97,25 @@ class _PaginatedPartListState extends PaginatedSearchState { "has_stock": { "label": L10().filterInStock, "help_text": L10().filterInStockDetail, - } + }, }; @override - Future requestPage(int limit, int offset, Map params) async { - final page = await InvenTreePart().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreePart().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePart part = model as InvenTreePart; return ListTile( @@ -124,10 +123,7 @@ class _PaginatedPartListState extends PaginatedSearchState { subtitle: Text(part.description), trailing: Text( part.stockString(), - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold - ) + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), leading: InvenTreeAPI().getThumbnail(part.thumbnail), onTap: () { @@ -135,4 +131,4 @@ class _PaginatedPartListState extends PaginatedSearchState { }, ); } -} \ No newline at end of file +} diff --git a/lib/widget/part/part_parameter_widget.dart b/lib/widget/part/part_parameter_widget.dart index 53e772d..c4df189 100644 --- a/lib/widget/part/part_parameter_widget.dart +++ b/lib/widget/part/part_parameter_widget.dart @@ -11,7 +11,6 @@ import "package:inventree/widget/refreshable_state.dart"; * Widget for displaying a list of parameters associated with a given Part instance */ class PartParameterWidget extends StatefulWidget { - const PartParameterWidget(this.part); final InvenTreePart part; @@ -20,7 +19,6 @@ class PartParameterWidget extends StatefulWidget { _ParameterWidgetState createState() => _ParameterWidgetState(); } - class _ParameterWidgetState extends RefreshableState { _ParameterWidgetState(); @@ -36,28 +34,18 @@ class _ParameterWidgetState extends RefreshableState { @override Widget getBody(BuildContext context) { + Map filters = {"part": widget.part.pk.toString()}; - Map filters = { - "part": widget.part.pk.toString() - }; - - return Column( - children: [ - Expanded( - child: PaginatedParameterList(filters) - ) - ], - ); + return Column(children: [Expanded(child: PaginatedParameterList(filters))]); } } - /* * Widget for displaying a paginated list of Part parameters */ class PaginatedParameterList extends PaginatedSearchWidget { - - const PaginatedParameterList(Map filters) : super(filters: filters); + const PaginatedParameterList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().parameters; @@ -66,18 +54,15 @@ class PaginatedParameterList extends PaginatedSearchWidget { _PaginatedParameterState createState() => _PaginatedParameterState(); } - -class _PaginatedParameterState extends PaginatedSearchState { - +class _PaginatedParameterState + extends PaginatedSearchState { _PaginatedParameterState() : super(); @override String get prefix => "parameters_"; @override - Map get orderingOptions => { - - }; + Map get orderingOptions => {}; @override Map> get filterOptions => { @@ -85,32 +70,37 @@ class _PaginatedParameterState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreePartParameter().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreePartParameter().listPaginated( + limit, + offset, + filters: params, + ); return page; } Future editParameter(InvenTreePartParameter parameter) async { - // Checkbox values are handled separately if (parameter.is_checkbox) { return; } else { parameter.editForm( - context, - L10().editParameter, - onSuccess: (data) async { - updateSearchTerm(); - } + context, + L10().editParameter, + onSuccess: (data) async { + updateSearchTerm(); + }, ); } } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreePartParameter parameter = model as InvenTreePartParameter; String title = parameter.name; @@ -123,27 +113,28 @@ class _PaginatedParameterState extends PaginatedSearchState { - @override String getAppBarTitle() { return L10().partPricing; @@ -25,14 +27,13 @@ class _PartPricingWidgetState extends RefreshableState { @override List getTiles(BuildContext context) { - List tiles = [ Card( child: ListTile( title: Text(widget.part.fullname), subtitle: Text(widget.part.description), - leading: api.getThumbnail(widget.part.thumbnail) - ) + leading: api.getThumbnail(widget.part.thumbnail), + ), ), ]; @@ -41,7 +42,7 @@ class _PartPricingWidgetState extends RefreshableState { ListTile( title: Text(L10().noPricingAvailable), subtitle: Text(L10().noPricingDataFound), - ) + ), ); return tiles; @@ -50,10 +51,7 @@ class _PartPricingWidgetState extends RefreshableState { final pricing = widget.partPricing!; tiles.add( - ListTile( - title: Text(L10().currency), - trailing: Text(pricing.currency), - ) + ListTile(title: Text(L10().currency), trailing: Text(pricing.currency)), ); tiles.add( @@ -63,10 +61,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.overallMin, pricing.overallMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); if (pricing.overallMin != null) { @@ -74,9 +72,9 @@ class _PartPricingWidgetState extends RefreshableState { ListTile( title: Text(L10().priceOverrideMin), trailing: Text( - renderCurrency(pricing.overallMin, pricing.overrideMinCurrency) - ) - ) + renderCurrency(pricing.overallMin, pricing.overrideMinCurrency), + ), + ), ); } @@ -85,9 +83,9 @@ class _PartPricingWidgetState extends RefreshableState { ListTile( title: Text(L10().priceOverrideMax), trailing: Text( - renderCurrency(pricing.overallMax, pricing.overrideMaxCurrency) - ) - ) + renderCurrency(pricing.overallMax, pricing.overrideMaxCurrency), + ), + ), ); } @@ -98,10 +96,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.internalCostMin, pricing.internalCostMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); if (widget.part.isTemplate) { @@ -112,10 +110,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.variantCostMin, pricing.variantCostMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); } @@ -124,13 +122,13 @@ class _PartPricingWidgetState extends RefreshableState { ListTile( title: Text(L10().bomCost), trailing: Text( - formatPriceRange( + formatPriceRange( pricing.bomCostMin, pricing.bomCostMax, - currency: pricing.currency - ) - ) - ) + currency: pricing.currency, + ), + ), + ), ); } @@ -142,10 +140,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.purchaseCostMin, pricing.purchaseCostMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); tiles.add( @@ -155,10 +153,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.supplierPriceMin, pricing.supplierPriceMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); } @@ -172,10 +170,10 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.salePriceMin, pricing.salePriceMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); tiles.add( @@ -185,14 +183,13 @@ class _PartPricingWidgetState extends RefreshableState { formatPriceRange( pricing.saleHistoryMin, pricing.saleHistoryMax, - currency: pricing.currency - ) + currency: pricing.currency, + ), ), - ) + ), ); } return tiles; } - } diff --git a/lib/widget/part/part_suppliers.dart b/lib/widget/part/part_suppliers.dart index 204ac6e..0fa79ae 100644 --- a/lib/widget/part/part_suppliers.dart +++ b/lib/widget/part/part_suppliers.dart @@ -10,19 +10,15 @@ import "package:inventree/inventree/company.dart"; import "package:inventree/widget/refreshable_state.dart"; class PartSupplierWidget extends StatefulWidget { - const PartSupplierWidget(this.part, {Key? key}) : super(key: key); final InvenTreePart part; @override _PartSupplierState createState() => _PartSupplierState(part); - } - class _PartSupplierState extends RefreshableState { - _PartSupplierState(this.part); final InvenTreePart part; @@ -46,7 +42,6 @@ class _PartSupplierState extends RefreshableState { } Widget _supplierPartTile(BuildContext context, int index) { - InvenTreeSupplierPart _part = _supplierParts[index]; return ListTile( @@ -73,5 +68,4 @@ class _PartSupplierState extends RefreshableState { itemBuilder: _supplierPartTile, ); } - -} \ No newline at end of file +} diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index 3deb938..a95ace9 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -1,5 +1,3 @@ - - import "dart:io"; import "package:flutter/material.dart"; @@ -7,17 +5,11 @@ import "package:flutter_overlay_loader/flutter_overlay_loader.dart"; import "package:inventree/app_colors.dart"; import "package:one_context/one_context.dart"; - /* * A simplified linear progress bar widget, * with standardized color depiction */ -Widget ProgressBar( - double value, -{ - double maximum = 1.0 -}) { - +Widget ProgressBar(double value, {double maximum = 1.0}) { double v = 0; if (value <= 0 || maximum <= 0) { @@ -33,20 +25,14 @@ Widget ProgressBar( ); } - /* * Construct a circular progress indicator */ Widget progressIndicator() { - - return Center( - child: CircularProgressIndicator() - ); + return Center(child: CircularProgressIndicator()); } - void showLoadingOverlay() { - // Do not show overlay if running unit tests if (Platform.environment.containsKey("FLUTTER_TEST")) { return; @@ -60,11 +46,12 @@ void showLoadingOverlay() { Loader.show( context, - themeData: Theme.of(context).copyWith(colorScheme: ColorScheme.fromSwatch()) + themeData: Theme.of( + context, + ).copyWith(colorScheme: ColorScheme.fromSwatch()), ); } - void hideLoadingOverlay() { if (Loader.isShown) { Loader.hide(); diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 59e70fa..9b09c97 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -10,12 +10,10 @@ import "package:inventree/widget/back.dart"; import "package:inventree/widget/drawer.dart"; import "package:inventree/widget/search.dart"; - /* * Simple mixin class which defines simple methods for defining widget properties */ mixin BaseWidgetProperties { - /* * Return a list of appBar actions * By default, no appBar actions are available @@ -23,7 +21,9 @@ mixin BaseWidgetProperties { List appBarActions(BuildContext context) => []; // Return a title for the appBar (placeholder) - String getAppBarTitle() { return "--- app bar ---"; } + String getAppBarTitle() { + return "--- app bar ---"; + } // Function to construct a drawer (override if needed) Widget getDrawer(BuildContext context) { @@ -38,7 +38,6 @@ mixin BaseWidgetProperties { // Function to construct a body Widget getBody(BuildContext context) { - // Default implementation is to return a ListView // Override getTiles to replace the internal context return ListView( @@ -51,7 +50,6 @@ mixin BaseWidgetProperties { * Construct the top AppBar for this view */ AppBar? buildAppBar(BuildContext context, GlobalKey key) { - List tabs = getTabIcons(context); return AppBar( @@ -70,8 +68,10 @@ mixin BaseWidgetProperties { * - Button to access global search * - Button to access barcode scan */ - BottomAppBar? buildBottomAppBar(BuildContext context, GlobalKey key) { - + BottomAppBar? buildBottomAppBar( + BuildContext context, + GlobalKey key, + ) { const double iconSize = 40; List icons = [ @@ -90,10 +90,8 @@ mixin BaseWidgetProperties { onPressed: () { if (InvenTreeAPI().checkConnection()) { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SearchWidget(true) - ) + context, + MaterialPageRoute(builder: (context) => SearchWidget(true)), ); } }, @@ -106,27 +104,27 @@ mixin BaseWidgetProperties { scanBarcode(context); } }, - ) + ), ]; return BottomAppBar( - shape: AutomaticNotchedShape( - RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), - RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(40)), - ), + shape: AutomaticNotchedShape( + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), ), - notchMargin: 10, - child: IconTheme( - data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: icons, - ) - ) + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(40)), + ), + ), + notchMargin: 10, + child: IconTheme( + data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: icons, + ), + ), ); } @@ -146,7 +144,6 @@ mixin BaseWidgetProperties { * Build out action buttons for a given widget */ Widget? buildSpeedDial(BuildContext context) { - final actions = actionButtons(context); final barcodeActions = barcodeButtons(context); @@ -165,44 +162,38 @@ mixin BaseWidgetProperties { spacing: 14, childPadding: const EdgeInsets.all(5), spaceBetweenChildren: 15, - ) + ), ); } if (actions.isNotEmpty) { children.add( - SpeedDial( - icon: Icons.more_horiz, - activeIcon: Icons.close, - children: actions, - spacing: 14, - childPadding: const EdgeInsets.all(5), - spaceBetweenChildren: 15, - ) + SpeedDial( + icon: Icons.more_horiz, + activeIcon: Icons.close, + children: actions, + spacing: 14, + childPadding: const EdgeInsets.all(5), + spaceBetweenChildren: 15, + ), ); } - return Wrap( - direction: Axis.horizontal, - children: children, - spacing: 15, - ); + return Wrap(direction: Axis.horizontal, children: children, spacing: 15); } // Return list of "tabs" for this widget List getTabIcons(BuildContext context) => []; - } - /* * Abstract base class which provides generic "refresh" functionality. * * - Drag down and release to 'refresh' the widget * - Define some method which runs to 'refresh' the widget state */ -abstract class RefreshableState extends State with BaseWidgetProperties { - +abstract class RefreshableState extends State + with BaseWidgetProperties { final scaffoldKey = GlobalKey(); final refreshKey = GlobalKey(); @@ -235,7 +226,6 @@ abstract class RefreshableState extends State with // Refresh the widget - handler for custom request() method Future refresh(BuildContext context) async { - // Escape if the widget is no longer loaded if (!mounted) { return; @@ -259,13 +249,14 @@ abstract class RefreshableState extends State with @override Widget build(BuildContext context) { - // Save the context for future use _context = context; List tabs = getTabIcons(context); - Widget body = tabs.isEmpty ? getBody(context) : TabBarView(children: getTabs(context)); + Widget body = tabs.isEmpty + ? getBody(context) + : TabBarView(children: getTabs(context)); Scaffold view = Scaffold( key: scaffoldKey, @@ -282,19 +273,16 @@ abstract class RefreshableState extends State with onRefresh: () async { refresh(context); }, - child: body + child: body, ), bottomNavigationBar: buildBottomAppBar(context, scaffoldKey), ); // Default implementation is *not* tabbed if (tabs.isNotEmpty) { - return DefaultTabController( - length: tabs.length, - child: view, - ); + return DefaultTabController(length: tabs.length, child: view); } else { return view; } } -} \ No newline at end of file +} diff --git a/lib/widget/search.dart b/lib/widget/search.dart index f9ab6e0..40c5a33 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -23,21 +23,17 @@ import "package:inventree/widget/order/sales_order_list.dart"; import "package:inventree/widget/company/company_list.dart"; import "package:inventree/widget/company/supplier_part_list.dart"; - // Widget for performing database-wide search class SearchWidget extends StatefulWidget { - const SearchWidget(this.hasAppbar); final bool hasAppbar; @override _SearchDisplayState createState() => _SearchDisplayState(hasAppbar); - } class _SearchDisplayState extends RefreshableState { - _SearchDisplayState(this.hasAppBar) : super(); final _formKey = GlobalKey(); @@ -80,7 +76,6 @@ class _SearchDisplayState extends RefreshableState { * Determine if the search is still running */ bool isSearching() { - if (searchController.text.isEmpty) { return false; } @@ -128,7 +123,6 @@ class _SearchDisplayState extends RefreshableState { // Callback when the text is being edited // Incorporates a debounce timer to restrict search frequency void onSearchTextChanged(String text, {bool immediate = false}) { - if (debounceTimer?.isActive ?? false) { debounceTimer!.cancel(); } @@ -151,8 +145,7 @@ class _SearchDisplayState extends RefreshableState { * } * } */ - int getSearchResultCount(Map results, String key) { - + int getSearchResultCount(Map results, String key) { dynamic result = results[key]; if (result == null || result is! Map) { @@ -170,43 +163,70 @@ class _SearchDisplayState extends RefreshableState { // Actually perform the search query Future _perform_search(Map body) async { - InvenTreeAPI().post( - "search/", - body: body, - expectedStatusCode: 200).then((APIResponse response) { + InvenTreeAPI().post("search/", body: body, expectedStatusCode: 200).then(( + APIResponse response, + ) { + String searchTerm = (body["search"] ?? "").toString(); - String searchTerm = (body["search"] ?? "").toString(); + // Only update if the results correspond to the current search term + if (searchTerm == searchController.text && mounted) { + decrementPendingSearches(); - // Only update if the results correspond to the current search term - if (searchTerm == searchController.text && mounted) { + Map results = {}; - decrementPendingSearches(); + if (response.isValid() && response.data is Map) { + results = response.data as Map; - Map results = {}; + setState(() { + nPartResults = getSearchResultCount( + results, + InvenTreePart.MODEL_TYPE, + ); + nCategoryResults = getSearchResultCount( + results, + InvenTreePartCategory.MODEL_TYPE, + ); + nStockResults = getSearchResultCount( + results, + InvenTreeStockItem.MODEL_TYPE, + ); + nLocationResults = getSearchResultCount( + results, + InvenTreeStockLocation.MODEL_TYPE, + ); + nPurchaseOrderResults = getSearchResultCount( + results, + InvenTreePurchaseOrder.MODEL_TYPE, + ); + nSalesOrderResults = getSearchResultCount( + results, + InvenTreeSalesOrder.MODEL_TYPE, + ); + nSupplierPartResults = getSearchResultCount( + results, + InvenTreeSupplierPart.MODEL_TYPE, + ); + nManufacturerPartResults = getSearchResultCount( + results, + InvenTreeManufacturerPart.MODEL_TYPE, + ); + nCompanyResults = getSearchResultCount( + results, + InvenTreeCompany.MODEL_TYPE, + ); - if (response.isValid() && response.data is Map) { - results = response.data as Map; - - setState(() { - nPartResults = getSearchResultCount(results, InvenTreePart.MODEL_TYPE); - nCategoryResults = getSearchResultCount(results, InvenTreePartCategory.MODEL_TYPE); - nStockResults = getSearchResultCount(results, InvenTreeStockItem.MODEL_TYPE); - nLocationResults = getSearchResultCount(results, InvenTreeStockLocation.MODEL_TYPE); - nPurchaseOrderResults = getSearchResultCount(results, InvenTreePurchaseOrder.MODEL_TYPE); - nSalesOrderResults = getSearchResultCount(results, InvenTreeSalesOrder.MODEL_TYPE); - nSupplierPartResults = getSearchResultCount(results, InvenTreeSupplierPart.MODEL_TYPE); - nManufacturerPartResults = getSearchResultCount(results, InvenTreeManufacturerPart.MODEL_TYPE); - nCompanyResults = getSearchResultCount(results, InvenTreeCompany.MODEL_TYPE); - - // Special case for company search results - nCustomerResults = getSearchResultCount(results, "customer"); - nManufacturerResults = getSearchResultCount(results, "manufacturer"); - nSupplierResults = getSearchResultCount(results, "supplier"); - }); - } else { - resetSearchResults(); - } + // Special case for company search results + nCustomerResults = getSearchResultCount(results, "customer"); + nManufacturerResults = getSearchResultCount( + results, + "manufacturer", + ); + nSupplierResults = getSearchResultCount(results, "supplier"); + }); + } else { + resetSearchResults(); } + } }); } @@ -237,7 +257,6 @@ class _SearchDisplayState extends RefreshableState { // Consolidated search allows us to perform *all* searches in a single query if (api.supportsConsolidatedSearch) { - Map body = { "limit": 1, "search": term, @@ -262,17 +281,13 @@ class _SearchDisplayState extends RefreshableState { } if (body.isNotEmpty) { - if (mounted) { setState(() { nPendingSearches = 1; }); - _search_query = CancelableOperation.fromFuture( - _perform_search(body), - ); + _search_query = CancelableOperation.fromFuture(_perform_search(body)); } - } } else { legacySearch(term); @@ -283,7 +298,6 @@ class _SearchDisplayState extends RefreshableState { * Perform "legacy" search (without consolidated search API endpoint */ Future legacySearch(String term) async { - // Search parts if (InvenTreePart().canView) { nPendingSearches++; @@ -302,7 +316,7 @@ class _SearchDisplayState extends RefreshableState { // Search part categories if (InvenTreePartCategory().canView) { nPendingSearches++; - InvenTreePartCategory().count(searchQuery: term,).then((int n) { + InvenTreePartCategory().count(searchQuery: term).then((int n) { if (term == searchController.text) { if (mounted) { decrementPendingSearches(); @@ -346,37 +360,31 @@ class _SearchDisplayState extends RefreshableState { // Search purchase orders if (InvenTreePurchaseOrder().canView) { - nPendingSearches++; - InvenTreePurchaseOrder().count( - searchQuery: term, - filters: { - "outstanding": "true" - } - ).then((int n) { - if (term == searchController.text) { - if (mounted) { - decrementPendingSearches(); - setState(() { - nPurchaseOrderResults = n; - }); - } - } - }); + nPendingSearches++; + InvenTreePurchaseOrder() + .count(searchQuery: term, filters: {"outstanding": "true"}) + .then((int n) { + if (term == searchController.text) { + if (mounted) { + decrementPendingSearches(); + setState(() { + nPurchaseOrderResults = n; + }); + } + } + }); } } @override List getTiles(BuildContext context) { - List tiles = []; // Search input tiles.add( ListTile( title: TextFormField( - decoration: InputDecoration( - hintText: L10().queryEmpty, - ), + decoration: InputDecoration(hintText: L10().queryEmpty), key: _formKey, readOnly: false, autofocus: true, @@ -385,12 +393,13 @@ class _SearchDisplayState extends RefreshableState { onChanged: (String text) { onSearchTextChanged(text); }, - onFieldSubmitted: (String text) { - }, + onFieldSubmitted: (String text) {}, ), trailing: GestureDetector( child: Icon( - searchController.text.isEmpty ? TablerIcons.search : TablerIcons.backspace, + searchController.text.isEmpty + ? TablerIcons.search + : TablerIcons.backspace, color: searchController.text.isEmpty ? COLOR_ACTION : COLOR_DANGER, ), onTap: () { @@ -398,8 +407,7 @@ class _SearchDisplayState extends RefreshableState { onSearchTextChanged("", immediate: true); }, ), - ) - + ), ); String query = searchController.text; @@ -415,17 +423,13 @@ class _SearchDisplayState extends RefreshableState { trailing: Text("${nPartResults}"), onTap: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartList( - { - "original_search": query - } - ) - ) + context, + MaterialPageRoute( + builder: (context) => PartList({"original_search": query}), + ), ); - } - ) + }, + ), ); } @@ -440,15 +444,12 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => PartCategoryList( - { - "original_search": query - } - ) - ) + builder: (context) => + PartCategoryList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -463,15 +464,11 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => StockItemList( - { - "original_search": query, - } - ) - ) + builder: (context) => StockItemList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -486,15 +483,12 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => StockLocationList( - { - "original_search": query - } - ) - ) + builder: (context) => + StockLocationList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -510,14 +504,12 @@ class _SearchDisplayState extends RefreshableState { context, MaterialPageRoute( builder: (context) => PurchaseOrderListWidget( - filters: { - "original_search": query - } - ) - ) + filters: {"original_search": query}, + ), + ), ); }, - ) + ), ); } @@ -532,15 +524,12 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => SalesOrderListWidget( - filters: { - "original_search": query - } - ) - ) + builder: (context) => + SalesOrderListWidget(filters: {"original_search": query}), + ), ); }, - ) + ), ); } @@ -555,16 +544,13 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().companies, - { - "original_search": query - } - ) - ) + builder: (context) => CompanyListWidget(L10().companies, { + "original_search": query, + }), + ), ); }, - ) + ), ); } @@ -579,17 +565,14 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().customers, - { - "original_search": query, - "is_customer": "true" - } - ) - ) + builder: (context) => CompanyListWidget(L10().customers, { + "original_search": query, + "is_customer": "true", + }), + ), ); }, - ) + ), ); } @@ -604,17 +587,14 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().manufacturers, - { - "original_search": query, - "is_manufacturer": "true" - } - ) - ) + builder: (context) => CompanyListWidget(L10().manufacturers, { + "original_search": query, + "is_manufacturer": "true", + }), + ), ); }, - ) + ), ); } @@ -629,17 +609,14 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().suppliers, - { - "original_search": query, - "is_supplier": "true" - } - ) - ) + builder: (context) => CompanyListWidget(L10().suppliers, { + "original_search": query, + "is_supplier": "true", + }), + ), ); }, - ) + ), ); } @@ -654,15 +631,12 @@ class _SearchDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => SupplierPartList( - { - "original_search": query - } - ) - ) + builder: (context) => + SupplierPartList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -672,7 +646,7 @@ class _SearchDisplayState extends RefreshableState { title: Text(L10().searching), leading: Icon(TablerIcons.search), trailing: CircularProgressIndicator(), - ) + ), ); } @@ -684,7 +658,7 @@ class _SearchDisplayState extends RefreshableState { style: TextStyle(fontStyle: FontStyle.italic), ), leading: Icon(TablerIcons.zoom_cancel), - ) + ), ); } else { for (Widget result in results) { @@ -694,5 +668,4 @@ class _SearchDisplayState extends RefreshableState { return tiles; } - } diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index 398a484..580955f 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -8,8 +8,13 @@ import "package:inventree/l10.dart"; /* * Display a configurable 'snackbar' at the bottom of the screen */ -void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? success, String? actionText}) { - +void showSnackIcon( + String text, { + IconData? icon, + Function()? onAction, + bool? success, + String? actionText, +}) { debug("showSnackIcon: '${text}'"); // Escape quickly if we do not have context @@ -34,7 +39,6 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc if (icon == null && onAction == null) { icon = TablerIcons.circle_check; } - } else if (success != null && success == false) { backgroundColor = Colors.deepOrange; @@ -45,35 +49,32 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc String _action = actionText ?? L10().details; - List childs = [ - Text(text), - Spacer(), - ]; + List childs = [Text(text), Spacer()]; if (icon != null) { childs.add(Icon(icon)); } - OneContext().showSnackBar(builder: (context) => SnackBar( - content: GestureDetector( - child: Row( - children: childs + OneContext().showSnackBar( + builder: (context) => SnackBar( + content: GestureDetector( + child: Row(children: childs), + onTap: () { + ScaffoldMessenger.of(context!).hideCurrentSnackBar(); + }, ), - onTap: () { - ScaffoldMessenger.of(context!).hideCurrentSnackBar(); - }, + backgroundColor: backgroundColor, + action: onAction == null + ? null + : SnackBarAction( + label: _action, + onPressed: () { + // Immediately dismiss the notification + ScaffoldMessenger.of(context!).hideCurrentSnackBar(); + onAction(); + }, + ), + duration: Duration(seconds: onAction == null ? 5 : 10), ), - backgroundColor: backgroundColor, - action: onAction == null ? null : SnackBarAction( - label: _action, - onPressed: () { - // Immediately dismiss the notification - ScaffoldMessenger.of(context!).hideCurrentSnackBar(); - onAction(); - } - ), - duration: Duration(seconds: onAction == null ? 5 : 10), - ) ); - -} \ No newline at end of file +} diff --git a/lib/widget/spinner.dart b/lib/widget/spinner.dart index 3ac68c5..e06e25b 100644 --- a/lib/widget/spinner.dart +++ b/lib/widget/spinner.dart @@ -2,7 +2,6 @@ import "package:flutter/material.dart"; import "package:inventree/app_colors.dart"; class Spinner extends StatefulWidget { - const Spinner({ this.color = COLOR_GRAY_LIGHT, Key? key, @@ -27,12 +26,8 @@ class _SpinnerState extends State with SingleTickerProviderStateMixin { _controller = AnimationController( vsync: this, duration: Duration(milliseconds: 2000), - ) - ..repeat(); - _child = Icon( - widget.icon, - color: widget.color - ); + )..repeat(); + _child = Icon(widget.icon, color: widget.color); super.initState(); } @@ -45,9 +40,6 @@ class _SpinnerState extends State with SingleTickerProviderStateMixin { @override Widget build(BuildContext context) { - return RotationTransition( - turns: _controller!, - child: _child, - ); + return RotationTransition(turns: _controller!, child: _child); } -} \ No newline at end of file +} diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart index b12f834..8c1a681 100644 --- a/lib/widget/stock/location_display.dart +++ b/lib/widget/stock/location_display.dart @@ -18,12 +18,10 @@ import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock/stock_list.dart"; import "package:inventree/labels.dart"; - /* * Widget for displaying detail view for a single StockLocation instance */ class LocationDisplayWidget extends StatefulWidget { - LocationDisplayWidget(this.location, {Key? key}) : super(key: key); final InvenTreeStockLocation? location; @@ -35,7 +33,6 @@ class LocationDisplayWidget extends StatefulWidget { } class _LocationDisplayState extends RefreshableState { - _LocationDisplayState(this.location); final InvenTreeStockLocation? location; @@ -54,30 +51,29 @@ class _LocationDisplayState extends RefreshableState { // Add "locate" button if (location != null && api.supportsMixin("locate")) { actions.add( - IconButton( - icon: Icon(Icons.travel_explore), - tooltip: L10().locateLocation, - onPressed: () async { - api.locateItemOrLocation(context, location: location!.pk); - } - ) + IconButton( + icon: Icon(Icons.travel_explore), + tooltip: L10().locateLocation, + onPressed: () async { + api.locateItemOrLocation(context, location: location!.pk); + }, + ), ); } // Add "edit" button if (location != null && InvenTreeStockLocation().canEdit) { actions.add( - IconButton( - icon: Icon(TablerIcons.edit), - tooltip: L10().editLocation, - onPressed: () { - _editLocationDialog(context); - } - ) + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editLocation, + onPressed: () { + _editLocationDialog(context); + }, + ), ); } - return actions; } @@ -89,18 +85,18 @@ class _LocationDisplayState extends RefreshableState { // Scan items into this location if (InvenTreeStockItem().canEdit) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.qrcode), - label: L10().barcodeScanItem, - onTap: () { - scanBarcode( - context, - handler: StockLocationScanInItemsHandler(location!), - ).then((value) { - refresh(context); - }); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.qrcode), + label: L10().barcodeScanItem, + onTap: () { + scanBarcode( + context, + handler: StockLocationScanInItemsHandler(location!), + ).then((value) { + refresh(context); + }); + }, + ), ); } @@ -109,41 +105,43 @@ class _LocationDisplayState extends RefreshableState { SpeedDialChild( child: Icon(Icons.barcode_reader), label: L10().scanReceivedParts, - onTap:() async { + onTap: () async { scanBarcode( context, handler: POReceiveBarcodeHandler(location: location), ); }, - ) + ), ); } // Scan this location into another one if (InvenTreeStockLocation().canEdit) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.qrcode), - label: L10().transferStockLocation, - onTap: () { - scanBarcode( - context, - handler: ScanParentLocationHandler(location!), - ).then((value) { - refresh(context); - }); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.qrcode), + label: L10().transferStockLocation, + onTap: () { + scanBarcode( + context, + handler: ScanParentLocationHandler(location!), + ).then((value) { + refresh(context); + }); + }, + ), ); } // Assign or un-assign barcodes actions.add( - customBarcodeAction( - context, this, - location!.customBarcode, "stocklocation", - location!.pk - ) + customBarcodeAction( + context, + this, + location!.customBarcode, + "stocklocation", + location!.pk, + ), ); } @@ -157,44 +155,44 @@ class _LocationDisplayState extends RefreshableState { // Create new location if (InvenTreeStockLocation().canCreate) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.sitemap), - label: L10().locationCreate, - onTap: () async { - _newLocation(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.sitemap), + label: L10().locationCreate, + onTap: () async { + _newLocation(context); + }, + ), ); } // Create new item if (InvenTreeStockItem().canCreate) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.packages), - label: L10().stockItemCreate, - onTap: () async { - _newStockItem(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.packages), + label: L10().stockItemCreate, + onTap: () async { + _newStockItem(context); + }, + ), ); } if (widget.location != null && labels.isNotEmpty) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.printer), - label: L10().printLabel, - onTap: () async { - selectAndPrintLabel( - context, - labels, - widget.location!.pk, - "location", - "location=${widget.location!.pk}" - ); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.printer), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel( + context, + labels, + widget.location!.pk, + "location", + "location=${widget.location!.pk}", + ); + }, + ), ); } @@ -212,12 +210,12 @@ class _LocationDisplayState extends RefreshableState { } _loc.editForm( - context, - L10().editLocation, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().locationUpdated, success: true); - } + context, + L10().editLocation, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().locationUpdated, success: true); + }, ); } @@ -238,22 +236,24 @@ class _LocationDisplayState extends RefreshableState { } List> _labels = []; - bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + bool allowLabelPrinting = await InvenTreeSettingsManager().getBool( + INV_ENABLE_LABEL_PRINTING, + true, + ); allowLabelPrinting &= api.supportsMixin("labels"); if (allowLabelPrinting) { - if (widget.location != null) { + String model_type = api.supportsModernLabelPrinting + ? InvenTreeStockLocation.MODEL_TYPE + : "location"; + String item_key = api.supportsModernLabelPrinting + ? "items" + : "location"; - String model_type = api.supportsModernLabelPrinting ? InvenTreeStockLocation.MODEL_TYPE : "location"; - String item_key = api.supportsModernLabelPrinting ? "items" : "location"; - - _labels = await getLabelTemplates( - model_type, - { - item_key: widget.location!.pk.toString() - } - ); + _labels = await getLabelTemplates(model_type, { + item_key: widget.location!.pk.toString(), + }); } } @@ -268,19 +268,17 @@ class _LocationDisplayState extends RefreshableState { int pk = location?.pk ?? -1; InvenTreeStockLocation().createForm( - context, - L10().locationCreate, - data: { - "parent": (pk > 0) ? pk : null, - }, - onSuccess: (result) async { - Map data = result as Map; + context, + L10().locationCreate, + data: {"parent": (pk > 0) ? pk : null}, + onSuccess: (result) async { + Map data = result as Map; - if (data.containsKey("pk")) { - var loc = InvenTreeStockLocation.fromJson(data); - loc.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var loc = InvenTreeStockLocation.fromJson(data); + loc.goToDetailPage(context); } + }, ); } @@ -288,7 +286,6 @@ class _LocationDisplayState extends RefreshableState { * Launch a dialog form to create a new stock item */ Future _newStockItem(BuildContext context) async { - var fields = InvenTreeStockItem().formFields(); // Serial number field is not required here @@ -301,94 +298,89 @@ class _LocationDisplayState extends RefreshableState { } InvenTreeStockItem().createForm( - context, - L10().stockItemCreate, - data: data, - fields: fields, - onSuccess: (result) async { - Map data = result as Map; + context, + L10().stockItemCreate, + data: data, + fields: fields, + onSuccess: (result) async { + Map data = result as Map; - if (data.containsKey("pk")) { - var item = InvenTreeStockItem.fromJson(data); - item.goToDetailPage(context); - } + if (data.containsKey("pk")) { + var item = InvenTreeStockItem.fromJson(data); + item.goToDetailPage(context); } + }, ); } Widget locationDescriptionCard({bool includeActions = true}) { if (location == null) { return Card( - child: ListTile( - title: Text( - L10().stockTopLevel, - style: TextStyle(fontStyle: FontStyle.italic) - ), - leading: Icon(TablerIcons.packages), - ) + child: ListTile( + title: Text( + L10().stockTopLevel, + style: TextStyle(fontStyle: FontStyle.italic), + ), + leading: Icon(TablerIcons.packages), + ), ); } else { List children = [ ListTile( title: Text("${location!.name}"), subtitle: Text("${location!.description}"), - leading: location!.customIcon == null ? Icon(TablerIcons.packages) : Icon(location!.customIcon) + leading: location!.customIcon == null + ? Icon(TablerIcons.packages) + : Icon(location!.customIcon), ), ]; if (includeActions) { children.add( - ListTile( - title: Text(L10().parentLocation), - subtitle: Text("${location!.parentPathString}"), - leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), - onTap: () async { - int parentId = location?.parentId ?? -1; + ListTile( + title: Text(L10().parentLocation), + subtitle: Text("${location!.parentPathString}"), + leading: Icon(TablerIcons.arrow_move_up, color: COLOR_ACTION), + onTap: () async { + int parentId = location?.parentId ?? -1; - if (parentId < 0) { - Navigator.push(context, MaterialPageRoute( - builder: (context) => LocationDisplayWidget(null))); - } else { - showLoadingOverlay(); - var loc = await InvenTreeStockLocation().get(parentId); - hideLoadingOverlay(); + if (parentId < 0) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationDisplayWidget(null), + ), + ); + } else { + showLoadingOverlay(); + var loc = await InvenTreeStockLocation().get(parentId); + hideLoadingOverlay(); - if (loc is InvenTreeStockLocation) { - loc.goToDetailPage(context); - } + if (loc is InvenTreeStockLocation) { + loc.goToDetailPage(context); } - }, - ) + } + }, + ), ); } - return Card( - child: Column( - children: children, - ) - ); + return Card(child: Column(children: children)); } } @override List getTabIcons(BuildContext context) { - return [ - Tab(text: L10().details), - Tab(text: L10().stockItems), - ]; + return [Tab(text: L10().details), Tab(text: L10().stockItems)]; } @override List getTabs(BuildContext context) { - return [ - Column(children: detailTiles()), - Column(children: stockTiles()), - ]; + return [Column(children: detailTiles()), Column(children: stockTiles())]; } // Construct the "details" panel List detailTiles() { - Map filters = {}; int? parent = location?.pk; @@ -402,12 +394,9 @@ class _LocationDisplayState extends RefreshableState { List tiles = [ locationDescriptionCard(), Expanded( - child: PaginatedStockLocationList( - filters, - title: L10().sublocations, - ), + child: PaginatedStockLocationList(filters, title: L10().sublocations), flex: 10, - ) + ), ]; return tiles; @@ -419,11 +408,6 @@ class _LocationDisplayState extends RefreshableState { "location": location?.pk.toString() ?? "null", }; - return [ - Expanded( - child: PaginatedStockItemList(filters), - flex: 10, - ) - ]; + return [Expanded(child: PaginatedStockItemList(filters), flex: 10)]; } } diff --git a/lib/widget/stock/location_list.dart b/lib/widget/stock/location_list.dart index 05cb204..1fc8032 100644 --- a/lib/widget/stock/location_list.dart +++ b/lib/widget/stock/location_list.dart @@ -7,9 +7,7 @@ import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; - class StockLocationList extends StatefulWidget { - const StockLocationList(this.filters); final Map filters; @@ -18,9 +16,7 @@ class StockLocationList extends StatefulWidget { _StockLocationListState createState() => _StockLocationListState(filters); } - class _StockLocationListState extends RefreshableState { - _StockLocationListState(this.filters); final Map filters; @@ -34,21 +30,22 @@ class _StockLocationListState extends RefreshableState { } } - class PaginatedStockLocationList extends PaginatedSearchWidget { - - const PaginatedStockLocationList(Map filters, {String title = ""}) : super(filters: filters, title: title); + const PaginatedStockLocationList( + Map filters, { + String title = "", + }) : super(filters: filters, title: title); @override String get searchTitle => title.isNotEmpty ? title : L10().stockLocations; @override - _PaginatedStockLocationListState createState() => _PaginatedStockLocationListState(); + _PaginatedStockLocationListState createState() => + _PaginatedStockLocationListState(); } - -class _PaginatedStockLocationListState extends PaginatedSearchState { - +class _PaginatedStockLocationListState + extends PaginatedSearchState { _PaginatedStockLocationListState() : super(); @override @@ -64,20 +61,26 @@ class _PaginatedStockLocationListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - - final page = await InvenTreeStockLocation().listPaginated(limit, offset, filters: params); + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeStockLocation().listPaginated( + limit, + offset, + filters: params, + ); return page; } @override Widget buildItem(BuildContext context, InvenTreeModel model) { - InvenTreeStockLocation location = model as InvenTreeStockLocation; return ListTile( @@ -90,4 +93,4 @@ class _PaginatedStockLocationListState extends PaginatedSearchState _StockItemDisplayState(); } - class _StockItemDisplayState extends RefreshableState { - _StockItemDisplayState(); @override @@ -62,25 +58,25 @@ class _StockItemDisplayState extends RefreshableState { if (api.supportsMixin("locate")) { actions.add( - IconButton( - icon: Icon(Icons.travel_explore), - tooltip: L10().locateItem, - onPressed: () async { - api.locateItemOrLocation(context, item: widget.item.pk); - } - ) + IconButton( + icon: Icon(Icons.travel_explore), + tooltip: L10().locateItem, + onPressed: () async { + api.locateItemOrLocation(context, item: widget.item.pk); + }, + ), ); } if (widget.item.canEdit) { actions.add( - IconButton( - icon: Icon(TablerIcons.edit), - tooltip: L10().editItem, - onPressed: () { - _editStockItem(context); - } - ) + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editItem, + onPressed: () { + _editStockItem(context); + }, + ), ); } @@ -89,20 +85,17 @@ class _StockItemDisplayState extends RefreshableState { @override List actionButtons(BuildContext context) { - List actions = []; if (widget.item.canEdit) { - // Stock adjustment actions available if item is *not* serialized if (!widget.item.isSerialized()) { - actions.add( SpeedDialChild( child: Icon(TablerIcons.circle_check, color: Colors.blue), label: L10().countStock, onTap: _countStockDialog, - ) + ), ); actions.add( @@ -110,7 +103,7 @@ class _StockItemDisplayState extends RefreshableState { child: Icon(TablerIcons.circle_minus, color: Colors.red), label: L10().removeStock, onTap: _removeStockDialog, - ) + ), ); actions.add( @@ -118,7 +111,7 @@ class _StockItemDisplayState extends RefreshableState { child: Icon(TablerIcons.circle_plus, color: Colors.green), label: L10().addStock, onTap: _addStockDialog, - ) + ), ); } @@ -129,8 +122,8 @@ class _StockItemDisplayState extends RefreshableState { label: L10().transferStock, onTap: () { _transferStockDialog(context); - } - ) + }, + ), ); } @@ -141,26 +134,26 @@ class _StockItemDisplayState extends RefreshableState { label: L10().printLabel, onTap: () async { selectAndPrintLabel( - context, - labels, - widget.item.pk, - "stock", - "item=${widget.item.pk}" + context, + labels, + widget.item.pk, + "stock", + "item=${widget.item.pk}", ); - } - ) + }, + ), ); } if (widget.item.canDelete) { actions.add( - SpeedDialChild( - child: Icon(TablerIcons.trash, color: Colors.red), - label: L10().stockItemDelete, - onTap: () { - _deleteItem(context); - } - ) + SpeedDialChild( + child: Icon(TablerIcons.trash, color: Colors.red), + label: L10().stockItemDelete, + onTap: () { + _deleteItem(context); + }, + ), ); } @@ -174,26 +167,28 @@ class _StockItemDisplayState extends RefreshableState { if (widget.item.canEdit) { // Scan item into location actions.add( - SpeedDialChild( - child: Icon(Icons.qr_code_scanner), - label: L10().scanIntoLocation, - onTap: () { - scanBarcode( - context, - handler: StockItemScanIntoLocationHandler(widget.item) - ).then((ctx) { - refresh(context); - }); - } - ) + SpeedDialChild( + child: Icon(Icons.qr_code_scanner), + label: L10().scanIntoLocation, + onTap: () { + scanBarcode( + context, + handler: StockItemScanIntoLocationHandler(widget.item), + ).then((ctx) { + refresh(context); + }); + }, + ), ); actions.add( - customBarcodeAction( - context, this, - widget.item.customBarcode, - "stockitem", widget.item.pk - ) + customBarcodeAction( + context, + this, + widget.item.customBarcode, + "stockitem", + widget.item.pk, + ), ); } @@ -217,8 +212,12 @@ class _StockItemDisplayState extends RefreshableState { @override Future request(BuildContext context) async { await api.StockStatus.load(); - stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; - stockShowTests = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) as bool; + stockShowHistory = + await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) + as bool; + stockShowTests = + await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_TESTS, true) + as bool; final bool result = widget.item.pk > 0 && await widget.item.reload(); @@ -238,7 +237,6 @@ class _StockItemDisplayState extends RefreshableState { // Request test results (async) if (stockShowTests) { widget.item.getTestResults().then((value) { - if (mounted) { setState(() { // Update @@ -248,7 +246,9 @@ class _StockItemDisplayState extends RefreshableState { } // Request the number of attachments - InvenTreeStockItemAttachment().countAttachments(widget.item.pk).then((int value) { + InvenTreeStockItemAttachment().countAttachments(widget.item.pk).then(( + int value, + ) { if (mounted) { setState(() { attachmentCount = value; @@ -258,13 +258,18 @@ class _StockItemDisplayState extends RefreshableState { // Request SalesOrder information if (widget.item.hasSalesOrder) { - InvenTreeSalesOrder().get(widget.item.salesOrderId).then((instance) => { - if (mounted) { - setState(() { - salesOrder = instance as InvenTreeSalesOrder?; - }) - } - }); + InvenTreeSalesOrder() + .get(widget.item.salesOrderId) + .then( + (instance) => { + if (mounted) + { + setState(() { + salesOrder = instance as InvenTreeSalesOrder?; + }), + }, + }, + ); } else { if (mounted) { setState(() { @@ -275,13 +280,18 @@ class _StockItemDisplayState extends RefreshableState { // Request Customer information if (widget.item.hasCustomer) { - InvenTreeCompany().get(widget.item.customerId).then((instance) => { - if (mounted) { - setState(() { - customer = instance as InvenTreeCompany?; - }) - } - }); + InvenTreeCompany() + .get(widget.item.customerId) + .then( + (instance) => { + if (mounted) + { + setState(() { + customer = instance as InvenTreeCompany?; + }), + }, + }, + ); } else { if (mounted) { setState(() { @@ -291,22 +301,23 @@ class _StockItemDisplayState extends RefreshableState { } List> _labels = []; - bool allowLabelPrinting = await InvenTreeSettingsManager().getBool(INV_ENABLE_LABEL_PRINTING, true); + bool allowLabelPrinting = await InvenTreeSettingsManager().getBool( + INV_ENABLE_LABEL_PRINTING, + true, + ); allowLabelPrinting &= api.supportsMixin("labels"); // Request information on labels available for this stock item if (allowLabelPrinting) { - - String model_type = api.supportsModernLabelPrinting ? InvenTreeStockItem.MODEL_TYPE : "stock"; + String model_type = api.supportsModernLabelPrinting + ? InvenTreeStockItem.MODEL_TYPE + : "stock"; String item_key = api.supportsModernLabelPrinting ? "items" : "item"; // Clear the existing labels list - _labels = await getLabelTemplates( - model_type, - { - item_key: widget.item.pk.toString() - } - ); + _labels = await getLabelTemplates(model_type, { + item_key: widget.item.pk.toString(), + }); } if (mounted) { @@ -318,7 +329,6 @@ class _StockItemDisplayState extends RefreshableState { /// Delete the stock item from the database Future _deleteItem(BuildContext context) async { - confirmationDialog( L10().stockItemDelete, L10().stockItemDeleteConfirm, @@ -327,7 +337,7 @@ class _StockItemDisplayState extends RefreshableState { acceptText: L10().delete, onAccept: () async { final bool result = await widget.item.delete(); - + if (result) { Navigator.of(context).pop(); showSnackIcon(L10().stockItemDeleteSuccess, success: true); @@ -336,11 +346,9 @@ class _StockItemDisplayState extends RefreshableState { } }, ); - } - Future _editStockItem(BuildContext context) async { - + Future _editStockItem(BuildContext context) async { var fields = InvenTreeStockItem().formFields(); // Some fields we don't want to edit! @@ -360,16 +368,14 @@ class _StockItemDisplayState extends RefreshableState { onSuccess: (data) async { refresh(context); showSnackIcon(L10().stockItemUpdated, success: true); - } + }, ); - } /* * Launch a dialog to 'add' quantity to this StockItem */ - Future _addStockDialog() async { - + Future _addStockDialog() async { Map fields = { "pk": { "parent": "items", @@ -377,11 +383,7 @@ class _StockItemDisplayState extends RefreshableState { "hidden": true, "value": widget.item.pk, }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, + "quantity": {"parent": "items", "nested": true, "value": 0}, "notes": {}, }; @@ -395,12 +397,11 @@ class _StockItemDisplayState extends RefreshableState { onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); - } + }, ); } void _stockUpdateMessage(bool result) { - if (result) { showSnackIcon(L10().stockItemUpdated, success: true); } @@ -410,7 +411,6 @@ class _StockItemDisplayState extends RefreshableState { * Launch a dialog to 'remove' quantity from this StockItem */ void _removeStockDialog() { - Map fields = { "pk": { "parent": "items", @@ -418,30 +418,25 @@ class _StockItemDisplayState extends RefreshableState { "hidden": true, "value": widget.item.pk, }, - "quantity": { - "parent": "items", - "nested": true, - "value": 0, - }, + "quantity": {"parent": "items", "nested": true, "value": 0}, "notes": {}, }; launchApiForm( - context, - L10().removeStock, - InvenTreeStockItem.removeStockUrl(), - fields, - method: "POST", - icon: TablerIcons.circle_minus, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } + context, + L10().removeStock, + InvenTreeStockItem.removeStockUrl(), + fields, + method: "POST", + icon: TablerIcons.circle_minus, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + }, ); } - Future _countStockDialog() async { - + Future _countStockDialog() async { Map fields = { "pk": { "parent": "items", @@ -458,58 +453,51 @@ class _StockItemDisplayState extends RefreshableState { }; launchApiForm( - context, - L10().countStock, - InvenTreeStockItem.countStockUrl(), - fields, - method: "POST", - icon: TablerIcons.clipboard_check, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } + context, + L10().countStock, + InvenTreeStockItem.countStockUrl(), + fields, + method: "POST", + icon: TablerIcons.clipboard_check, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + }, ); } /* * Launches an API Form to transfer this stock item to a new location */ - Future _transferStockDialog(BuildContext context) async { - + Future _transferStockDialog(BuildContext context) async { Map fields = widget.item.transferFields(); launchApiForm( - context, - L10().transferStock, - InvenTreeStockItem.transferStockUrl(), - fields, - method: "POST", - icon: TablerIcons.transfer, - onSuccess: (data) async { - _stockUpdateMessage(true); - refresh(context); - } + context, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: TablerIcons.transfer, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + }, ); } Widget headerTile() { - Widget? trailing; if (!widget.item.isInStock) { - trailing = Text( - L10().unavailable, - style: TextStyle( - color: COLOR_DANGER - ) - ); + trailing = Text(L10().unavailable, style: TextStyle(color: COLOR_DANGER)); } else if (!widget.item.isSerialized()) { trailing = Text( - widget.item.quantityString(), - style: TextStyle( - fontSize: 20, - color: api.StockStatus.color(widget.item.status), - ) + widget.item.quantityString(), + style: TextStyle( + fontSize: 20, + color: api.StockStatus.color(widget.item.status), + ), ); } @@ -521,7 +509,6 @@ class _StockItemDisplayState extends RefreshableState { trailing: trailing, onTap: () async { if (widget.item.partId > 0) { - showLoadingOverlay(); var part = await InvenTreePart().get(widget.item.partId); hideLoadingOverlay(); @@ -532,7 +519,7 @@ class _StockItemDisplayState extends RefreshableState { } }, //trailing: Text(item.serialOrQuantityDisplay()), - ) + ), ); } @@ -558,15 +545,13 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().stockLocation), subtitle: Text("${widget.item.locationPathString}"), - leading: Icon( - TablerIcons.location, - color: COLOR_ACTION, - ), + leading: Icon(TablerIcons.location, color: COLOR_ACTION), onTap: () async { if (widget.item.locationId > 0) { - showLoadingOverlay(); - var loc = await InvenTreeStockLocation().get(widget.item.locationId); + var loc = await InvenTreeStockLocation().get( + widget.item.locationId, + ); hideLoadingOverlay(); if (loc is InvenTreeStockLocation) { @@ -578,30 +563,32 @@ class _StockItemDisplayState extends RefreshableState { ); } else { tiles.add( - ListTile( - title: Text(L10().stockLocation), - leading: Icon(TablerIcons.location), - subtitle: Text(L10().locationNotSet), - ) + ListTile( + title: Text(L10().stockLocation), + leading: Icon(TablerIcons.location), + subtitle: Text(L10().locationNotSet), + ), ); } // Quantity information if (widget.item.isSerialized()) { tiles.add( - ListTile( - title: Text(L10().serialNumber), - leading: Icon(TablerIcons.hash), - subtitle: Text("${widget.item.serialNumber}"), - ) + ListTile( + title: Text(L10().serialNumber), + leading: Icon(TablerIcons.hash), + subtitle: Text("${widget.item.serialNumber}"), + ), ); } else if (widget.item.isInStock) { tiles.add( - ListTile( - title: widget.item.allocated > 0 ? Text(L10().quantityAvailable) : Text(L10().quantity), - leading: Icon(TablerIcons.packages), - trailing: Text("${widget.item.quantityString()}"), - ) + ListTile( + title: widget.item.allocated > 0 + ? Text(L10().quantityAvailable) + : Text(L10().quantity), + leading: Icon(TablerIcons.packages), + trailing: Text("${widget.item.quantityString()}"), + ), ); } @@ -611,18 +598,13 @@ class _StockItemDisplayState extends RefreshableState { leading: Icon(TablerIcons.box_off), title: Text( L10().unavailable, - style: TextStyle( - color: COLOR_DANGER, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: COLOR_DANGER, fontWeight: FontWeight.bold), ), subtitle: Text( L10().unavailableDetail, - style: TextStyle( - color: COLOR_DANGER - ) - ) - ) + style: TextStyle(color: COLOR_DANGER), + ), + ), ); } @@ -633,11 +615,9 @@ class _StockItemDisplayState extends RefreshableState { leading: Icon(TablerIcons.help_circle), trailing: Text( api.StockStatus.label(widget.item.status), - style: TextStyle( - color: api.StockStatus.color(widget.item.status), - ) - ) - ) + style: TextStyle(color: api.StockStatus.color(widget.item.status)), + ), + ), ); // Supplier part information (if available) @@ -647,20 +627,26 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().supplierPart), subtitle: Text(widget.item.supplierSKU), leading: Icon(TablerIcons.building, color: COLOR_ACTION), - trailing: InvenTreeAPI().getThumbnail(widget.item.supplierImage, hideIfNull: true), + trailing: InvenTreeAPI().getThumbnail( + widget.item.supplierImage, + hideIfNull: true, + ), onTap: () async { showLoadingOverlay(); var sp = await InvenTreeSupplierPart().get( - widget.item.supplierPartId); + widget.item.supplierPartId, + ); hideLoadingOverlay(); if (sp is InvenTreeSupplierPart) { Navigator.push( - context, MaterialPageRoute( - builder: (context) => SupplierPartDetailWidget(sp)) + context, + MaterialPageRoute( + builder: (context) => SupplierPartDetailWidget(sp), + ), ); } - } - ) + }, + ), ); } @@ -673,7 +659,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: () { // TODO: Click through to the "build order" }, - ) + ), ); } @@ -686,8 +672,8 @@ class _StockItemDisplayState extends RefreshableState { trailing: Text(salesOrder?.reference ?? ""), onTap: () { salesOrder?.goToDetailPage(context); - } - ) + }, + ), ); } @@ -701,7 +687,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: () { customer?.goToDetailPage(context); }, - ) + ), ); } @@ -711,7 +697,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().batchCode), subtitle: Text(widget.item.batch), leading: Icon(TablerIcons.clipboard_text), - ) + ), ); } @@ -721,18 +707,23 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().packaging), subtitle: Text(widget.item.packaging), leading: Icon(TablerIcons.package), - ) + ), ); } if (expiryEnabled && widget.item.expiryDate != null) { - Widget? _expiryIcon; if (widget.item.expired) { - _expiryIcon = Text(L10().expiryExpired, style: TextStyle(color: COLOR_DANGER)); + _expiryIcon = Text( + L10().expiryExpired, + style: TextStyle(color: COLOR_DANGER), + ); } else if (widget.item.stale) { - _expiryIcon = Text(L10().expiryStale, style: TextStyle(color: COLOR_WARNING)); + _expiryIcon = Text( + L10().expiryStale, + style: TextStyle(color: COLOR_WARNING), + ); } tiles.add( @@ -741,19 +732,18 @@ class _StockItemDisplayState extends RefreshableState { subtitle: Text(widget.item.expiryDateString), leading: Icon(TablerIcons.calendar_x), trailing: _expiryIcon, - ) + ), ); } // Last update? if (widget.item.updatedDateString.isNotEmpty) { - tiles.add( ListTile( title: Text(L10().lastUpdated), subtitle: Text(widget.item.updatedDateString), - leading: Icon(TablerIcons.calendar) - ) + leading: Icon(TablerIcons.calendar), + ), ); } @@ -763,8 +753,8 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastStocktake), subtitle: Text(widget.item.stocktakeDateString), - leading: Icon(TablerIcons.calendar) - ) + leading: Icon(TablerIcons.calendar), + ), ); } @@ -776,26 +766,27 @@ class _StockItemDisplayState extends RefreshableState { onTap: () { widget.item.openLink(); }, - ) + ), ); } if (stockShowTests || (widget.item.testResultCount > 0)) { tiles.add( - ListTile( - title: Text(L10().testResults), - leading: Icon(TablerIcons.list_check, color: COLOR_ACTION), - trailing: Text("${widget.item.testResultCount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockItemTestResultsWidget(widget.item)) - ).then((ctx) { - refresh(context); - }); - } - ) + ListTile( + title: Text(L10().testResults), + leading: Icon(TablerIcons.list_check, color: COLOR_ACTION), + trailing: Text("${widget.item.testResultCount}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockItemTestResultsWidget(widget.item), + ), + ).then((ctx) { + refresh(context); + }); + }, + ), ); } @@ -805,9 +796,12 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().purchasePrice), leading: Icon(TablerIcons.currency_dollar), trailing: Text( - renderCurrency(widget.item.purchasePrice, widget.item.purchasePriceCurrency) - ) - ) + renderCurrency( + widget.item.purchasePrice, + widget.item.purchasePriceCurrency, + ), + ), + ), ); } @@ -823,12 +817,13 @@ class _StockItemDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => StockItemHistoryWidget(widget.item)) - ).then((ctx) { - refresh(context); + builder: (context) => StockItemHistoryWidget(widget.item), + ), + ).then((ctx) { + refresh(context); }); }, - ) + ), ); } @@ -840,34 +835,33 @@ class _StockItemDisplayState extends RefreshableState { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => NotesWidget(widget.item)) + MaterialPageRoute(builder: (context) => NotesWidget(widget.item)), ); - } - ) + }, + ), ); tiles.add( - ListTile( - title: Text(L10().attachments), - leading: Icon(TablerIcons.file, color: COLOR_ACTION), - trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AttachmentWidget( - InvenTreeStockItemAttachment(), - widget.item.pk, - L10().stockItem, - widget.item.canEdit, - ) - ) - ); - }, - ) + ListTile( + title: Text(L10().attachments), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AttachmentWidget( + InvenTreeStockItemAttachment(), + widget.item.pk, + L10().stockItem, + widget.item.canEdit, + ), + ), + ); + }, + ), ); return tiles; } - -} \ No newline at end of file +} diff --git a/lib/widget/stock/stock_item_history.dart b/lib/widget/stock/stock_item_history.dart index b2829fd..7324156 100644 --- a/lib/widget/stock/stock_item_history.dart +++ b/lib/widget/stock/stock_item_history.dart @@ -14,10 +14,12 @@ class StockItemHistoryWidget extends StatefulWidget { final InvenTreeStockItem item; @override - _StockItemHistoryDisplayState createState() => _StockItemHistoryDisplayState(item); + _StockItemHistoryDisplayState createState() => + _StockItemHistoryDisplayState(item); } -class _StockItemHistoryDisplayState extends RefreshableState { +class _StockItemHistoryDisplayState + extends RefreshableState { _StockItemHistoryDisplayState(this.item); final InvenTreeStockItem item; @@ -30,20 +32,18 @@ class _StockItemHistoryDisplayState extends RefreshableState filters = { - "item": widget.item.pk.toString(), - }; + Map filters = {"item": widget.item.pk.toString()}; return PaginatedStockHistoryList(filters); } - } /* * Widget which displays a paginated stock history list */ class PaginatedStockHistoryList extends PaginatedSearchWidget { - const PaginatedStockHistoryList(Map filters) : super(filters: filters); + const PaginatedStockHistoryList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().stockItemHistory; @@ -67,15 +67,22 @@ class _PaginatedStockHistoryState @override Map> get filterOptions => { - // TODO: Add filter options - }; + // TODO: Add filter options + }; @override Future requestPage( - int limit, int offset, Map params) async { + int limit, + int offset, + Map params, + ) async { await InvenTreeAPI().StockHistoryStatus.load(); - final page = await InvenTreeStockItemHistory().listPaginated(limit, offset, filters: params); + final page = await InvenTreeStockItemHistory().listPaginated( + limit, + offset, + filters: params, + ); return page; } diff --git a/lib/widget/stock/stock_item_test_results.dart b/lib/widget/stock/stock_item_test_results.dart index d1671e5..9fb7d92 100644 --- a/lib/widget/stock/stock_item_test_results.dart +++ b/lib/widget/stock/stock_item_test_results.dart @@ -13,20 +13,18 @@ import "package:inventree/inventree/model.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; - class StockItemTestResultsWidget extends StatefulWidget { - const StockItemTestResultsWidget(this.item, {Key? key}) : super(key: key); final InvenTreeStockItem item; @override - _StockItemTestResultDisplayState createState() => _StockItemTestResultDisplayState(item); + _StockItemTestResultDisplayState createState() => + _StockItemTestResultDisplayState(item); } - -class _StockItemTestResultDisplayState extends RefreshableState { - +class _StockItemTestResultDisplayState + extends RefreshableState { _StockItemTestResultDisplayState(this.item); @override @@ -46,8 +44,8 @@ class _StockItemTestResultDisplayState extends RefreshableState addTestResult(BuildContext context, {int templateId = 0, String name = "", bool nameIsEditable = true, bool result = false, String value = "", bool valueRequired = false, bool attachmentRequired = false}) async { - - Map> fields = InvenTreeStockItemTestResult().formFields(); + Future addTestResult( + BuildContext context, { + int templateId = 0, + String name = "", + bool nameIsEditable = true, + bool result = false, + String value = "", + bool valueRequired = false, + bool attachmentRequired = false, + }) async { + Map> fields = InvenTreeStockItemTestResult() + .formFields(); // Add additional filters fields["template"]?["filters"]?["part"] = "${item.partId}"; @@ -102,7 +109,6 @@ class _StockItemTestResultDisplayState extends RefreshableState filters; @@ -18,9 +16,7 @@ class StockItemList extends StatefulWidget { _StockListState createState() => _StockListState(filters); } - class _StockListState extends RefreshableState { - _StockListState(this.filters); final Map filters; @@ -35,20 +31,18 @@ class _StockListState extends RefreshableState { } class PaginatedStockItemList extends PaginatedSearchWidget { - - const PaginatedStockItemList(Map filters) : super(filters: filters); + const PaginatedStockItemList(Map filters) + : super(filters: filters); @override String get searchTitle => L10().stockItems; @override _PaginatedStockItemListState createState() => _PaginatedStockItemListState(); - } - -class _PaginatedStockItemListState extends PaginatedSearchState { - +class _PaginatedStockItemListState + extends PaginatedSearchState { _PaginatedStockItemListState() : super(); @override @@ -100,7 +94,7 @@ class _PaginatedStockItemListState extends PaginatedSearchState requestPage(int limit, int offset, Map params) async { - + Future requestPage( + int limit, + int offset, + Map params, + ) async { // Ensure StockStatus codes are loaded await InvenTreeAPI().StockStatus.load(); final page = await InvenTreeStockItem().listPaginated( limit, offset, - filters: params + filters: params, ); return page; @@ -127,7 +124,6 @@ class _PaginatedStockItemListState extends PaginatedSearchState fetchProfileToken({ UserProfile? profile, String username = testUsername, - String password = testPassword + String password = testPassword, }) async { - profile ??= await UserProfileDBManager().getProfileByName(testServerName); assert(profile != null); - final response = await InvenTreeAPI().fetchToken(profile!, username, password); + final response = await InvenTreeAPI().fetchToken( + profile!, + username, + password, + ); return response.successful(); } - /* * Setup a valid profile, and return it */ -Future setupServerProfile({bool select = true, bool fetchToken = false}) async { +Future setupServerProfile({ + bool select = true, + bool fetchToken = false, +}) async { // Setup a valid server profile - UserProfile? profile = await UserProfileDBManager().getProfileByName(testServerName); + UserProfile? profile = await UserProfileDBManager().getProfileByName( + testServerName, + ); if (profile == null) { // Profile does not already exist - create it! bool result = await UserProfileDBManager().addProfile( - UserProfile( - server: testServerAddress, - name: testServerName - ) + UserProfile(server: testServerAddress, name: testServerName), ); assert(result); @@ -84,15 +88,13 @@ Future setupServerProfile({bool select = true, bool fetchToken = fa return profile!; } - /* * Complete all steps necessary to login to the server */ Future connectToTestServer() async { - // Setup profile, and fetch user token as necessary final profile = await setupServerProfile(fetchToken: true); // Connect to the server assert(await InvenTreeAPI().connectToServer(profile)); -} \ No newline at end of file +} diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 0921d76..e1b49cf 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -26,11 +26,13 @@ void main() { expect(profiles.length, equals(0)); // Now, create one! - bool result = await UserProfileDBManager().addProfile(UserProfile( - name: testServerName, - server: testServerAddress, - selected: true, - )); + bool result = await UserProfileDBManager().addProfile( + UserProfile( + name: testServerName, + server: testServerAddress, + selected: true, + ), + ); expect(result, equals(true)); @@ -56,20 +58,15 @@ void main() { // Run a set of tests for user profile functionality group("Profile Tests:", () { - test("Add Invalid Profiles", () async { // Add a profile with missing data - bool result = await UserProfileDBManager().addProfile( - UserProfile() - ); + bool result = await UserProfileDBManager().addProfile(UserProfile()); expect(result, equals(false)); // Add a profile with a new name result = await UserProfileDBManager().addProfile( - UserProfile( - name: "Another Test Profile", - ) + UserProfile(name: "Another Test Profile"), ); expect(result, equals(true)); @@ -81,7 +78,9 @@ void main() { }); test("Profile Name Check", () async { - bool result = await UserProfileDBManager().profileNameExists("doesnotexist"); + bool result = await UserProfileDBManager().profileNameExists( + "doesnotexist", + ); expect(result, equals(false)); result = await UserProfileDBManager().profileNameExists("Test Server"); @@ -100,7 +99,10 @@ void main() { expect(p.name, equals(testServerName)); expect(p.server, equals(testServerAddress)); - expect(p.toString(), equals("<${p.key}> Test Server : http://localhost:8000/")); + expect( + p.toString(), + equals("<${p.key}> Test Server : http://localhost:8000/"), + ); // Test that we can update the profile p.name = "different name"; @@ -110,5 +112,4 @@ void main() { } }); }); - -} \ No newline at end of file +} diff --git a/test/wedge_scanner_test.dart b/test/wedge_scanner_test.dart index 8cdca59..bd98872 100644 --- a/test/wedge_scanner_test.dart +++ b/test/wedge_scanner_test.dart @@ -1,5 +1,3 @@ - - import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_test/flutter_test.dart"; @@ -7,14 +5,10 @@ import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/wedge_controller.dart"; import "package:inventree/helpers.dart"; - void main() { testWidgets("Wedge Scanner Test", (tester) async { - await tester.pumpWidget( - MaterialApp( - home: WedgeBarcodeController(BarcodeScanHandler()) - ) + MaterialApp(home: WedgeBarcodeController(BarcodeScanHandler())), ); // Generate some keyboard data @@ -27,6 +21,5 @@ void main() { debugContains("scanned: abc"); debugContains("No match for barcode"); debugContains("Server Error"); - }); -} \ No newline at end of file +} From 2568a299fc7952ebaa379299cfebbe234f8d6cae Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 24 Jun 2025 11:15:42 +0200 Subject: [PATCH 678/746] Fix image url in BUILDING.md (#663) --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index c05e8e7..b04b60b 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -72,7 +72,7 @@ Set Flutter SDK path in Android Studio: 2. Go to `File` -> `Settings` -> `Languages & Frameworks` -> `Flutter` 3. Set `Flutter SDK path` to `.fvm/flutter_sdk`: -![Setting Flutter SDK path in Android Studio](android_studio_fvm.png) +![Setting Flutter SDK path in Android Studio](docs/android_studio_fvm.png) ## Getting Started From 2619adc87b60632fe9257d25ef8e9c16ce756936 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 24 Jun 2025 11:27:49 +0200 Subject: [PATCH 679/746] feat: theme update (#645) --- lib/app_colors.dart | 6 +- lib/main.dart | 2 +- lib/widget/drawer.dart | 108 ++++++++++++++++++++++++++++-- lib/widget/home.dart | 39 ++++++++--- lib/widget/refreshable_state.dart | 2 +- 5 files changed, 136 insertions(+), 21 deletions(-) diff --git a/lib/app_colors.dart b/lib/app_colors.dart index aeda838..a22dfbc 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -26,10 +26,8 @@ Color get COLOR_ACTION { } } -// Return an "app bar" color based on the current theme -Color get COLOR_APP_BAR { - return Color.fromRGBO(55, 150, 175, 1); -} +// Set to null to use the system default +Color? COLOR_APP_BAR; const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); const Color COLOR_DANGER = Color.fromRGBO(200, 50, 75, 1); diff --git a/lib/main.dart b/lib/main.dart index 22dd25b..5db07ee 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -166,7 +166,7 @@ class InvenTreeAppState extends State { colorSchemeSeed: Colors.blue, useMaterial3: true, ), - initial: savedThemeMode ?? AdaptiveThemeMode.light, + initial: savedThemeMode ?? AdaptiveThemeMode.system, builder: (light, dark) => MaterialApp( theme: light, darkTheme: dark, diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 90bae32..9f30446 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -19,6 +19,81 @@ import "package:inventree/widget/stock/location_display.dart"; /* * Custom "drawer" widget for the InvenTree app. */ +// Dialog for theme selection +class ThemeSelectionDialog extends StatelessWidget { + const ThemeSelectionDialog({Key? key, required this.onThemeSelected}) + : super(key: key); + + final VoidCallback onThemeSelected; + + @override + Widget build(BuildContext context) { + final currentThemeMode = AdaptiveTheme.of(context).mode; + + return AlertDialog( + title: Text(L10().colorScheme), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.device_desktop), + SizedBox(width: 10), + Text("System"), + ], + ), + value: AdaptiveThemeMode.system, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.system); + onThemeSelected(); + }, + ), + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.sun), + SizedBox(width: 10), + Text("Light"), + ], + ), + value: AdaptiveThemeMode.light, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.light); + onThemeSelected(); + }, + ), + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.moon), + SizedBox(width: 10), + Text("Dark"), + ], + ), + value: AdaptiveThemeMode.dark, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.dark); + onThemeSelected(); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("Cancel"), + ), + ], + ); + } +} + class InvenTreeDrawer extends StatelessWidget { const InvenTreeDrawer(this.context); @@ -118,6 +193,18 @@ class InvenTreeDrawer extends StatelessWidget { ); } + // Return an icon representing the current theme mode + Widget _getThemeModeIcon(AdaptiveThemeMode mode) { + switch (mode) { + case AdaptiveThemeMode.dark: + return Icon(TablerIcons.moon); + case AdaptiveThemeMode.light: + return Icon(TablerIcons.sun); + case AdaptiveThemeMode.system: + return Icon(TablerIcons.device_desktop); + } + } + // Construct list of tiles to display in the "drawer" menu List drawerTiles(BuildContext context) { List tiles = []; @@ -125,7 +212,7 @@ class InvenTreeDrawer extends StatelessWidget { // "Home" access tiles.add( ListTile( - leading: Icon(TablerIcons.home, color: COLOR_ACTION), + leading: Image.asset("assets/image/logo_transparent.png", height: 24), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -195,18 +282,25 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add(Divider()); - bool darkMode = AdaptiveTheme.of(context).mode.isDark; - tiles.add( ListTile( onTap: () { - AdaptiveTheme.of(context).toggleThemeMode(); - _closeDrawer(); + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return ThemeSelectionDialog( + onThemeSelected: () { + Navigator.of(dialogContext).pop(); + _closeDrawer(); + }, + ); + }, + ); }, title: Text(L10().colorScheme), subtitle: Text(L10().colorSchemeDetail), - leading: Icon(TablerIcons.sun_moon, color: COLOR_ACTION), - trailing: Icon(darkMode ? TablerIcons.moon : TablerIcons.sun), + leading: Icon(TablerIcons.palette, color: COLOR_ACTION), + trailing: _getThemeModeIcon(AdaptiveTheme.of(context).mode), ), ); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 2a2b615..3b29d86 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -225,10 +225,9 @@ class _InvenTreeHomePageState extends State child: ListTile( leading: Icon( icon, - size: 32, color: connected && allowed ? COLOR_ACTION : Colors.grey, ), - title: Text(label, style: TextStyle(fontSize: 20)), + title: Text(label), trailing: trailing, ), alignment: Alignment.center, @@ -457,15 +456,39 @@ class _InvenTreeHomePageState extends State return Scaffold( key: homeKey, appBar: AppBar( - title: Text(L10().appTitle), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset("assets/image/logo_transparent.png", height: 24), + SizedBox(width: 8), + Text(L10().appTitle), + ], + ), backgroundColor: COLOR_APP_BAR, actions: [ IconButton( - icon: Icon( - TablerIcons.server, - color: connected - ? COLOR_SUCCESS - : (connecting ? COLOR_PROGRESS : COLOR_DANGER), + icon: Stack( + children: [ + Icon(TablerIcons.server), + Positioned( + right: 0, + bottom: 0, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: connected + ? COLOR_SUCCESS + : (connecting ? COLOR_PROGRESS : COLOR_DANGER), + shape: BoxShape.circle, + border: Border.all( + color: Theme.of(context).scaffoldBackgroundColor, + width: 1.5, + ), + ), + ), + ), + ], ), onPressed: _selectProfile, ), diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 9b09c97..cd53b82 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -72,7 +72,7 @@ mixin BaseWidgetProperties { BuildContext context, GlobalKey key, ) { - const double iconSize = 40; + const double iconSize = 32; List icons = [ IconButton( From 29ccd4ebfa3242a6b5c653d64a883dadbed74a3b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 24 Jun 2025 19:47:28 +1000 Subject: [PATCH 680/746] Contributors update (#664) * Update credits * Tweak release notes --- assets/credits.md | 1 + assets/release_notes.md | 1 + 2 files changed, 2 insertions(+) diff --git a/assets/credits.md b/assets/credits.md index 16f2801..abf8611 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -3,6 +3,7 @@ Thanks to the following contributors, for their work building this app! - [SchrodingersGat](https://github.com/SchrodingersGat) (*Lead Developer*) +- [cbenhagen](https://github.com/cbenhagen) - [Guusggg](https://github.com/Guusggg) - [GoryMoon](https://github.com/GoryMoon) - [simonkuehling](https://github.com/simonkuehling) diff --git a/assets/release_notes.md b/assets/release_notes.md index c69b658..e80308a 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -2,6 +2,7 @@ --- - Replace barcode scanning library for better performance - Display part pricing information +- Updated theme support - Fix broken documentation link - Reduce frequency of notification checks - Updated translations From eb30bbb2fa72d03eb8974abc59f2eae8e1bcf07a Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 24 Jun 2025 15:17:36 +0200 Subject: [PATCH 681/746] feat: add image cropping functionality with custom aspect ratios (#638) * feat: add image cropping functionality with custom aspect ratios * Update release notes --- assets/release_notes.md | 1 + lib/l10n/app_en.arb | 51 +++++++- lib/widget/part/image_cropper.dart | 169 +++++++++++++++++++++++++ lib/widget/part/part_image_widget.dart | 134 +++++++++++++++++--- pubspec.lock | 16 +++ pubspec.yaml | 1 + 6 files changed, 350 insertions(+), 22 deletions(-) create mode 100644 lib/widget/part/image_cropper.dart diff --git a/assets/release_notes.md b/assets/release_notes.md index e80308a..0d68aa0 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Fix broken documentation link - Reduce frequency of notification checks - Updated translations +- Add image cropping functionality ### 0.18.1 - April 2025 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 11a61b7..ff6fa80 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -50,6 +50,18 @@ "allocated": "Allocated", "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", "@allocateStock": {}, @@ -259,7 +271,7 @@ "@confirmScan": {}, "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", - "@confirmScan": {}, + "@confirmScanDetail": {}, "connectionRefused": "Connection Refused", "@connectionRefused": {}, @@ -277,6 +289,12 @@ "credits": "Credits", "@credits": {}, + "crop": "Crop", + "@crop": {}, + + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", "@customer": {}, @@ -333,12 +351,15 @@ "documentation": "Documentation", "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", "@downloading": {}, - "downloadError": "Download Error", - "@downloadError": {}, - "edit": "Edit", "@edit": { "description": "edit" @@ -504,7 +525,7 @@ }, "home": "Home", - "@homeScreen": {}, + "@home": {}, "homeScreen": "Home Screen", "@homeScreen": {}, @@ -759,6 +780,9 @@ "noResults": "No Results", "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, + "noSubcategories": "No Subcategories", "@noSubcategories": {}, @@ -1040,6 +1064,9 @@ "refresh": "Refresh", "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "Refreshing", "@refreshing": {}, @@ -1565,6 +1592,9 @@ "uploadSuccess": "File uploaded", "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "Used In", "@usedIn": {}, @@ -1646,5 +1676,14 @@ "@noPricingAvailable": {}, "noPricingDataFound": "No pricing data found for this part", - "@noPricingDataFound": {} + "@noPricingDataFound": {}, + + "deleteImageConfirmation": "Are you sure you want to delete this image?", + "@deleteImageConfirmation": {}, + + "deleteImageTooltip": "Delete Image", + "@deleteImageTooltip": {}, + + "deleteImage": "Delete Image", + "@deleteImage": {} } diff --git a/lib/widget/part/image_cropper.dart b/lib/widget/part/image_cropper.dart new file mode 100644 index 0000000..a3236d2 --- /dev/null +++ b/lib/widget/part/image_cropper.dart @@ -0,0 +1,169 @@ +import "dart:typed_data"; +import "package:custom_image_crop/custom_image_crop.dart"; +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/l10.dart"; + +/// Widget for displaying the image cropper UI +class ImageCropperWidget extends StatefulWidget { + const ImageCropperWidget({Key? key, required this.imageBytes}) + : super(key: key); + + final Uint8List imageBytes; + + @override + State createState() => _ImageCropperWidgetState(); +} + +class _ImageCropperWidgetState extends State { + final cropController = CustomImageCropController(); + + // Define fixed ratio objects so they are the same instances for comparison + static final _ratioSquare = Ratio(width: 1, height: 1); + static final _ratio4x3 = Ratio(width: 4, height: 3); + static final _ratio16x9 = Ratio(width: 16, height: 9); + static final _ratio3x2 = Ratio(width: 3, height: 2); + + var _aspectRatio = _ratioSquare; + var _isCropping = false; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + DropdownButton( + value: _aspectRatio, + items: [ + DropdownMenuItem( + value: _ratioSquare, + child: Text(L10().aspectRatioSquare), + ), + DropdownMenuItem( + value: _ratio4x3, + child: Text(L10().aspectRatio4x3), + ), + DropdownMenuItem( + value: _ratio16x9, + child: Text(L10().aspectRatio16x9), + ), + DropdownMenuItem( + value: _ratio3x2, + child: Text(L10().aspectRatio3x2), + ), + ], + onChanged: (value) { + if (value != null) { + setState(() { + _aspectRatio = value; + }); + } + }, + ), + + // Reset button - returns the image to its default state + IconButton( + icon: Icon(TablerIcons.refresh), + onPressed: () => cropController.reset(), + tooltip: "Reset", + ), + + // Zoom out button - scales to 75% of current size + IconButton( + icon: Icon(TablerIcons.zoom_out), + onPressed: () => + cropController.addTransition(CropImageData(scale: 0.75)), + tooltip: "Zoom Out", + ), + + // Zoom in button - scales to 133% of current size + IconButton( + icon: Icon(TablerIcons.zoom_in), + onPressed: () => + cropController.addTransition(CropImageData(scale: 1.33)), + tooltip: "Zoom In", + ), + + // Rotate button + IconButton( + icon: Icon(TablerIcons.rotate), + onPressed: () => + cropController.addTransition(CropImageData(angle: 90)), + tooltip: L10().rotateClockwise, + ), + ], + ), + ), + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: CustomImageCrop( + cropController: cropController, + image: MemoryImage(widget.imageBytes), + shape: CustomCropShape.Ratio, + ratio: _aspectRatio, + forceInsideCropArea: true, + overlayColor: Colors.black.withAlpha(128), + backgroundColor: Colors.black.withAlpha(64), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(L10().cancel), + ), + ElevatedButton( + onPressed: _isCropping + ? null + : () async { + setState(() { + _isCropping = true; + }); + + try { + // Crop the image + final image = await cropController.onCropImage(); + if (!mounted) return; + if (image != null) { + Navigator.of(context).pop(image.bytes); + } else { + setState(() { + _isCropping = false; + }); + } + } catch (e) { + if (!mounted) return; + setState(() { + _isCropping = false; + }); + } + }, + child: _isCropping + ? SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2.0, + color: Colors.white, + ), + ) + : Text(L10().crop), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/widget/part/part_image_widget.dart b/lib/widget/part/part_image_widget.dart index 885f7bf..b40353c 100644 --- a/lib/widget/part/part_image_widget.dart +++ b/lib/widget/part/part_image_widget.dart @@ -1,14 +1,16 @@ import "dart:io"; +import "dart:typed_data"; import "package:flutter/material.dart"; +import "package:path_provider/path_provider.dart" as path_provider; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; - import "package:inventree/api.dart"; import "package:inventree/inventree/part.dart"; +import "package:inventree/l10.dart"; import "package:inventree/widget/fields.dart"; +import "package:inventree/widget/part/image_cropper.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import "package:inventree/l10.dart"; class PartImageWidget extends StatefulWidget { const PartImageWidget(this.part, {Key? key}) : super(key: key); @@ -32,37 +34,137 @@ class _PartImageState extends RefreshableState { @override String getAppBarTitle() => part.fullname; + Future _processImageWithCropping(File imageFile) async { + try { + Uint8List imageBytes = await imageFile.readAsBytes(); + + // Show the cropping dialog + final Uint8List? croppedBytes = await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Dialog( + insetPadding: const EdgeInsets.all(16), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + L10().cropImage, + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(height: 8), + Expanded(child: ImageCropperWidget(imageBytes: imageBytes)), + ], + ), + ), + ), + ); + + if (croppedBytes != null) { + imageBytes = croppedBytes; + } + + // Save cropped bytes to a proper temporary file for upload + final tempDir = await path_provider.getTemporaryDirectory(); + final timestamp = DateTime.now().millisecondsSinceEpoch; + final tempFile = File("${tempDir.path}/cropped_image_$timestamp.jpg"); + await tempFile.writeAsBytes(imageBytes); + + // Upload the cropped file + final result = await part.uploadImage(tempFile); + + // Delete temporary file + if (await tempFile.exists()) { + await tempFile.delete().catchError((_) => tempFile); + } + + if (!result) { + showSnackIcon(L10().uploadFailed, success: false); + } else { + showSnackIcon(L10().uploadSuccess, success: true); + } + + refresh(context); + } catch (e) { + showSnackIcon("${L10().error}: $e", success: false); + } + } + + // Delete the current part image + Future _deleteImage() async { + // Confirm deletion with user + final bool confirm = + await showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(L10().deleteImage), + content: Text(L10().deleteImageConfirmation), + actions: [ + TextButton( + child: Text(L10().cancel), + onPressed: () => Navigator.of(context).pop(false), + ), + TextButton( + child: Text(L10().delete), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ), + ) ?? + false; + + if (confirm) { + final APIResponse response = await InvenTreeAPI().patch( + part.url, + body: {"image": null}, + ); + + if (response.successful()) { + showSnackIcon(L10().deleteSuccess, success: true); + } else { + showSnackIcon( + "${L10().deleteFailed}: ${response.error}", + success: false, + ); + } + + refresh(context); + } + } + @override List appBarActions(BuildContext context) { - List actions = []; + List actions = [ + if (part.canEdit) ...[ + // Delete image button + if (part.jsondata["image"] != null) + IconButton( + icon: Icon(TablerIcons.trash), + tooltip: L10().deleteImageTooltip, + onPressed: _deleteImage, + ), - if (part.canEdit) { - // File upload - actions.add( + // File upload with cropping IconButton( icon: Icon(TablerIcons.file_upload), + tooltip: L10().uploadImage, onPressed: () async { FilePickerDialog.pickFile( onPicked: (File file) async { - final result = await part.uploadImage(file); - - if (!result) { - showSnackIcon(L10().uploadFailed, success: false); - } - - refresh(context); + await _processImageWithCropping(file); }, ); }, ), - ); - } + ], + ]; return actions; } @override Widget getBody(BuildContext context) { - return InvenTreeAPI().getImage(part.image); + return Center(child: InvenTreeAPI().getImage(part.image)); } } diff --git a/pubspec.lock b/pubspec.lock index 9520e7e..ed42dec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -281,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + custom_image_crop: + dependency: "direct main" + description: + name: custom_image_crop + sha256: d352ebe734677c391d77a1234dcc64a4e1a0ec5a35f8248d7274655f723edda4 + url: "https://pub.dev" + source: hosted + version: "0.1.1" datetime_picker_formfield: dependency: "direct main" description: @@ -493,6 +501,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + gesture_x_detector: + dependency: transitive + description: + name: gesture_x_detector + sha256: "777855ee4e1fa4d677c40d6a44b9106696ef6745879027c8871e334cee8cde1e" + url: "https://pub.dev" + source: hosted + version: "1.1.1" glob: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5f1db57..91f5b16 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: camera: ^0.11.1 # Camera cupertino_icons: ^1.0.8 currency_formatter: ^2.2.1 # Currency formatting + custom_image_crop: ^0.1.1 # Crop selected images datetime_picker_formfield: ^2.0.1 # Date / time picker device_info_plus: ^11.4.0 # Information about the device dropdown_search: ^5.0.6 # Dropdown autocomplete form fields From 55d14e745747dd19c394781399cd505abf480c93 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 24 Jun 2025 16:26:42 +0200 Subject: [PATCH 682/746] Add screenshot to README.md (#665) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c422c6c..a2fdfe3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ The InvenTree mobile / tablet application is a companion app for the [InvenTree Written in the [Flutter](https://flutter.dev/) environment, the app provides native support for Android and iOS devices. +

<&k9o{Z1Np?5BYG?| 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