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/release.yml b/.github/release.yml new file mode 100644 index 0000000..57cda2a --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,32 @@ +# .github/release.yml + +changelog: + exclude: + labels: + - wontfix + - translation + categories: + - title: Breaking Changes + labels: + - Semver-Major + - breaking + - title: Security Patches + labels: + - security + - title: New Features + labels: + - Semver-Minor + - enhancement + - title: Bug Fixes + labels: + - Semver-Patch + - bug + - title: Devops / Setup Changes + labels: + - docker + - setup + - demo + - CI + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 32aed76..3147927 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -3,10 +3,10 @@ name: Android on: - push: + pull_request: branches: - master - pull_request: + push: branches: - master @@ -17,23 +17,43 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 - with: - submodules: recursive + uses: actions/checkout@v3 + - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: - java-version: '12.x' - - name: Setup Flutter - uses: subosito/flutter-action@v1 + distribution: 'temurin' + java-version: '17' + + - name: Setup FVM + id: fvm-config-action + uses: kuhnroyal/flutter-fvm-config-action@v2 + + - uses: subosito/flutter-action@v2 with: - flutter-version: '2.10.3' + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} + 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:" + pub-cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" + + - run: flutter --version + - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v2.4.2 with: - gradle-version: 6.1.1 + gradle-version: 8.7 + + - name: Collect Translation Files + run: | + cd lib/l10n + python3 collect_translations.py + - name: Build for Android run: | - flutter pub get - cp lib/dummy_dsn.dart lib/dsn.dart - 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/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..c317876 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,93 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +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 + INVENTREE_STATIC_ROOT: ../test_inventree_static + INVENTREE_BACKUP_DIR: ../test_inventree_backup + INVENTREE_ADMIN_USER: testuser + INVENTREE_ADMIN_PASSWORD: testpassword + INVENTREE_ADMIN_EMAIL: test@test.com +jobs: + + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '11' + + - name: Setup Flutter and FVM + id: fvm-config-action + uses: kuhnroyal/flutter-fvm-config-action@v2 + + - uses: subosito/flutter-action@v2 + with: + 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 + python collect_translations.py + + - name: Static Analysis Tests + working-directory: . + run: | + 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: 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 dev.import-fixtures + invoke dev.server -a 127.0.0.1:8000 & + invoke wait + sleep 30 + + - name: Unit Tests + run: | + fvm 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 202c684..cdd51ed 100644 --- a/.github/workflows/ios.yaml +++ b/.github/workflows/ios.yaml @@ -3,10 +3,10 @@ name: iOS on: - push: + pull_request: branches: - master - pull_request: + push: branches: - master @@ -17,23 +17,44 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive + - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: - java-version: '12.x' + 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@v1 + uses: subosito/flutter-action@v2 with: - flutter-version: '2.10.3' + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} + 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:" + 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 + dart pub global activate fvm + fvm install + fvm flutter pub get + fvm flutter precache --ios cd ios pod repo update pod install cd .. - cp lib/dummy_dsn.dart lib/dsn.dart - flutter build ios --release --no-codesign + fvm flutter build ios --release --no-codesign --no-tree-shake-icons diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml deleted file mode 100644 index a9d3fe7..0000000 --- a/.github/workflows/lint.yaml +++ /dev/null @@ -1,37 +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' - - 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..8effbf9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,9 @@ coverage/* -# Sentry API key -lib/dsn.dart +# This file is auto-generated as part of the CI process +test/coverage_helper_test.dart +InvenTreeSettings.db # App signing key android/key.properties @@ -81,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/.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/.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 diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..b04b60b --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,132 @@ +## 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 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 + +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 +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](docs/android_studio_fvm.png) + + +## 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: +``` +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: + +### Android + +Build Android release: + +``` +invoke android +``` + +### iOS + +Build iOS release: + +``` +invoke ios +``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..859ab60 --- /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 `invoke 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/README.md b/README.md index 844a040..a2fdfe3 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,36 @@ [![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). 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/). + +## Developer Documentation + +Refer to the [build instructions](BUILDING.md) for information on how to build the app from source. diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 7f16021..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 update_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 -``` - -### Validate and Distribute - -- Open `./build/ios/archive/Runner.xcarchive` in Xcode -- Run "Validate App" -- Run "Distribute App" \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index 29c06eb..eed06a4 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 @@ -74,4 +74,12 @@ linter: avoid_dynamic_calls: false - avoid_classes_with_only_static_members: false \ No newline at end of file + avoid_classes_with_only_static_members: false + + no_leading_underscores_for_local_identifiers: false + + 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/android/app/build.gradle b/android/app/build.gradle index 6b6b83a..d133d64 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()) { @@ -32,7 +29,18 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 31 + namespace "inventree.inventree_app" + compileSdkVersion 35 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + // If using Kotlin + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17 + } sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -48,8 +56,8 @@ android { defaultConfig { applicationId "inventree.inventree_app" - minSdkVersion 25 - targetSdkVersion 31 + minSdkVersion 21 + targetSdkVersion 35 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -83,7 +91,6 @@ dependencies { androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support:multidex:2.0.1' - implementation "androidx.core:core:1.5.0-rc01" - implementation 'androidx.appcompat:appcompat:1.0.0' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "androidx.core:core:1.9.0" + implementation 'androidx.appcompat:appcompat:1.6.0' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 41a7000..3bf7ae2 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,6 @@ - - - - + + + + \ No newline at end of file diff --git a/android/app/src/main/res/values-v31/styles.xml b/android/app/src/main/res/values-v31/styles.xml new file mode 100644 index 0000000..fb61beb --- /dev/null +++ b/android/app/src/main/res/values-v31/styles.xml @@ -0,0 +1,9 @@ + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index ca5f4fc..dabc4dc 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/android/build.gradle b/android/build.gradle index af27b36..346e552 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,22 +1,8 @@ -buildscript { - - ext.kotlin_version = '1.5.10' - - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} allprojects { repositories { google() - jcenter() + mavenCentral() } } @@ -29,6 +15,6 @@ subprojects { } } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle.properties b/android/gradle.properties index 5f17537..f2b745e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,8 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.configureondemand=true +org.gradle.caching=true +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 9b9d49f..3bfe7cf 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-8.7-all.zip +networkTimeout=30000 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/android/settings.gradle b/android/settings.gradle index 5a2f14f..eb1096e 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 "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/credits.md b/assets/credits.md index 525dc8d..31eb4f0 100644 --- a/assets/credits.md +++ b/assets/credits.md @@ -1,6 +1,23 @@ -## InvenTree App Credits ---- +## Contributors -### Sound Files +Thanks to the following contributors, for their work building this app! -- Some sound files have been sourced from [https://www.zapsplat.com](https://www.zapsplat.com) +- [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) +- [Bobbe](https://github.com/30350n) +- [awnz](https://github.com/awnz) +- [joaomnuno](https://github.com/joaomnuno) +- [Alex9779](https://github.com/Alex9779) +-------- + +## Assets + +The InvenTree App makes use of the following third party assets + +- 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/image/logo_transparent.png b/assets/image/logo_transparent.png new file mode 100644 index 0000000..f5045cf Binary files /dev/null and b/assets/image/logo_transparent.png differ diff --git a/assets/release_notes.md b/assets/release_notes.md index 77b02c4..72324c1 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,468 @@ -## InvenTree App Release Notes +### x.xx.x - Month Year --- +- Support display of custom status codes +- Fix default values for list sorting + + +### 0.21.2 - January 2026 +--- + +- Fixes bug which launched camera twice when uploading an attachment +- Fixed bug related to list sorting and filtering + +### 0.21.1 - November 2025 +--- + +- Fixed app freeze bug after form submission + +### 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 + +### 0.20.2 - November 2025 +--- + +- Fixes URL for reporting issues on GitHub +- Fix for uploading files against server with self-signed certificates + +### 0.20.1 - October 2025 +--- + +- Bug fix for camera barcode scanner + +### 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" +- Updated translations + +### 0.19.3 - September 2025 +--- + +- Fixes incorrect priority of barcode scanner results + +### 0.19.2 - August 2025 +--- + +- 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 + +### 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 +- Display part pricing information +- Updated theme support +- Fix broken documentation link +- Reduce frequency of notification checks +- Updated translations +- Add image cropping functionality + +### 0.18.1 - April 2025 +--- +- Fix bug associated with handling invalid URLs + +### 0.18.0 - April 2025 +--- +- Adds ability to create new companies from the app +- Allow creation of line items against pending sales orders +- Support "extra line items" for purchase orders +- Support "extra line items" for sales orders +- Display start date for purchase orders +- Display start date for sales orders +- Fix scrolling behaviour for some widgets +- Updated search functionality +- Updated translations + +### 0.17.4 - January 2025 +--- +- Display responsible owner for orders +- Display completion date for orders +- Updated translations + +### 0.17.3 - January 2025 +--- + +- Fixes bug which prevent dialog boxes from being dismissed correctly +- Enable editing of attachment comments +- Updated translations + +### 0.17.2 - December 2024 +--- + +- 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 +--- + +- 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 +- 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 +--- + +- 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 +- 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 +--- + +- Allow blank values to be entered into numerical fields +- Updated translations + +### 0.16.4 - September 2024 +--- + +- Fixes bug related to printing stock item labels + +### 0.16.3 - August 2024 +--- + +- Fixes bug relating to viewing attachment files +- Fixes bug relating to uploading attachment files + + +### 0.16.2 - August 2024 +--- + +- 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 +--- + +- Update base packages for Android + +### 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 +--- + +- Support modern label printing API +- Improved display of stock item serial numbers +- Updated translations + +### 0.14.3 - April 2024 +--- + +- Support "active" field for Company model +- Support "active" field for SupplierPart model +- Adjustments to barcode scanning workflow +- Updated translations + +### 0.14.2 - February 2024 +--- + +- Updated error reporting +- Support for updated server API endpoints +- Updated translations + +### 0.14.1 - January 2024 +--- + +- Squashing bugs + +### 0.14.0 - December 2023 +--- + +- 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 +- 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 +- Allocate stock items against existing sales orders + +### 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 +- Improve scroll-to-refresh behaviour across multiple widgets + + +### 0.12.8 - September 2023 +--- + +- Added extra options for transferring stock items +- Fixes bug where API data was not fetched with correct locale + +### 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 +--- + +- Enable label printing for stock locations +- Enable label printing for parts +- Updated translation support +- Bug fixes + +### 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 +--- + +- 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 +--- + +- Adds options for configuring screen orientation +- Improvements to barcode scanning +- Translation updates +- Bug fix for scrolling long lists + +### 0.12.1 - May 2023 +--- + +- Fixes bug in purchase order form + +### 0.12.0 - April 2023 +--- + +- 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 + +### 0.11.5 - April 2023 +--- + +- 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 +--- + +- Bug fix for stock history widget +- Improved display of stock history widget +- Theme improvements for dark mode + +### 0.11.3 - April 2023 +--- + +- Fixes text color in dark mode + +### 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 +--- + +- 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 +--- + +- 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 +- Support barcode scanning for purchase orders + +### 0.10.2 - March 2023 +--- + +- 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 +--- + +- Add support for attachments on Companies +- Fix duplicate scanning of barcodes +- Updated translations + +### 0.10.0 - February 2023 +--- + +- Add support for Supplier Parts +- Updated translations + +### 0.9.3 - February 2023 +--- + +- Updates to match latest server API +- Bug fix for empty HttpResponse from server + +### 0.9.2 - December 2022 +--- + +- Support custom icons for part category +- Support custom icons for stock location +- Adjustments to notification messages +- Assorted bug fixes +- Updated translations + +### 0.9.1 - December 2022 +--- + +- Bug fixes for custom barcode actions +- Updated translations + +### 0.9.0 - December 2022 +--- + +- Added support for custom barcodes for Parts +- Added support for custom barcode for Stock Locations +- Support Part parameters +- Add support for structural part categories +- Add support for structural stock locations +- Allow deletion of attachments via app +- Adds option for controlling BOM display +- Updated translations + + +### 0.8.3 - September 2022 +--- + +- Display list of assemblies which components are used in +- Fixes search input bug + +### 0.8.2 - August 2022 +--- + +- Allow serial numbers to be specified when creating new stock items +- Allow serial numbers to be edited for existing stock items +- Allow app locale to be changed manually +- Improved handling of certain errors + +### 0.8.1 - August 2022 +--- + +- Added extra filtering options for PartCategory list +- Added extra filtering options for StockLocation list +- Fixed bug related to null widget context +- Improved error handling and reporting + +### 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 +- Allow stock location to be "scanned" into another location using barcode +- Improves server connection status indicator on home screen +- Display loading indicator during long-running operations +- Improved error handling and reporting + +### 0.7.3 - June 2022 +--- + +- Adds ability to display link URLs in attachments view +- Updated translations + +### 0.7.2 - June 2022 +--- + +- Add "quarantined" status flag for stock items +- Extends attachment support to stock items +- Extends attachment support to purchase orders + +### 0.7.1 - May 2022 +--- + +- 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 +--- + +- Refactor home screen display +- 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 +--- + +- Fixes issues related to locale support (for specific locales) + ### 0.6.1 - April 2022 --- diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..d354ec1 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: /lib/l10n/app_en.arb + translation: /lib/l10n/%locale_with_underscore%/app_%locale_with_underscore%.arb diff --git a/docs/android_studio_fvm.png b/docs/android_studio_fvm.png new file mode 100644 index 0000000..4d497b9 Binary files /dev/null and b/docs/android_studio_fvm.png differ diff --git a/find_dart_files.py b/find_dart_files.py new file mode 100644 index 0000000..80fba3a --- /dev/null +++ b/find_dart_files.py @@ -0,0 +1,50 @@ +""" +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") + + 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") + + 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/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/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..7c56964 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 12.0 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/ios/Podfile b/ios/Podfile index 11c9435..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, '9.0' +platform :ios, '15.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'] = '12.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 e68a9d4..81f65ca 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,13 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* 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 */; }; + 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 */; }; @@ -57,6 +57,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, D95D9CD46BE28F7F69DBC0F6 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -93,6 +94,7 @@ 3B8B22940C363C2F0DDB698A /* Frameworks */, ); sourceTree = ""; + tabWidth = 5; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; @@ -157,6 +159,9 @@ dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -167,26 +172,28 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; 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, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -203,7 +210,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 */, ); @@ -236,10 +242,12 @@ }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -250,6 +258,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -271,47 +280,45 @@ "${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}/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}/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/path_provider.framework", - "${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework", + "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", - "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", - "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.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}/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}/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}/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.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.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.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.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; @@ -357,6 +364,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++"; @@ -366,14 +374,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; @@ -384,6 +395,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; @@ -392,7 +404,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -404,6 +417,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; @@ -415,8 +429,12 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -432,6 +450,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++"; @@ -441,14 +460,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; @@ -459,6 +481,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; @@ -473,7 +496,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -485,6 +509,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++"; @@ -494,14 +519,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; @@ -512,6 +540,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; @@ -520,7 +549,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -532,6 +562,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; @@ -543,8 +574,12 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -560,6 +595,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; @@ -571,8 +607,12 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + INFOPLIST_KEY_CFBundleDisplayName = InvenTree; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -608,6 +648,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/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/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/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 444bcdb..5db441f 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,10 +1,28 @@ + + + + + + + + + + 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/ios/Runner/Info.plist b/ios/Runner/Info.plist index 3d514f8..5cd05c6 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -12,23 +12,35 @@ 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 + fi-FI + 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 + sl_SI + sv-SE + th-TH + tr-TR + vi-VN zh-CN + zh-TW CFBundleName InvenTree @@ -67,5 +79,16 @@ UIViewControllerBasedStatusBarAppearance + LSApplicationQueriesSchemes + + http + https + mailto + tel + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + 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/api.dart b/lib/api.dart index 71af9cb..61a6379 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -4,31 +4,42 @@ 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/app_colors.dart"; -import "package:inventree/app_settings.dart"; - -import "package:open_file/open_file.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"; 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:inventree/widget/dialogs.dart"; -import "package:inventree/l10.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"; /* * 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; @@ -77,8 +88,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 []; + } + } +} /* * Custom FileService for caching network images @@ -86,13 +115,11 @@ class APIResponse { * so we can accept "dodgy" (e.g. self-signed) certificates */ class InvenTreeFileService extends FileService { - InvenTreeFileService({HttpClient? client, bool strictHttps = false}) { _client = client ?? HttpClient(); if (_client != null) { _client!.badCertificateCallback = (cert, host, port) { - print("BAD CERTIFICATE CALLBACK FOR IMAGE REQUEST"); return !strictHttps; }; } @@ -101,8 +128,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); @@ -114,12 +143,17 @@ 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, + httpResponse.timeout(Duration(seconds: 60)), + httpResponse.statusCode, + contentLength: httpResponse.contentLength < 0 + ? 0 + : httpResponse.contentLength, reasonPhrase: httpResponse.reasonPhrase, isRedirect: httpResponse.isRedirect, ); + return HttpGetResponse(_response); } } @@ -131,31 +165,46 @@ 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; } 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 = []; + + // Register a callback function to be notified when the connection status changes + void registerCallback(Function() func) => _statusCallbacks.add(func); + + void _connectionStatusChanged() { + for (Function() func in _statusCallbacks) { + // Call the function + func(); + } + } + // Minimum required API version for server - static const _minApiVersion = 7; + // 2023-03-04 + static const _minApiVersion = 100; 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 += "/"; @@ -165,7 +214,6 @@ class InvenTreeAPI { } String _makeUrl(String url) { - // Strip leading slash if (url.startsWith("/")) { url = url.substring(1, url.length); @@ -193,23 +241,32 @@ class InvenTreeAPI { UserProfile? profile; + // Available user roles are loaded when connecting to the server Map roles = {}; - // Authentication token (initially empty, must be requested) - String _token = ""; + // Available user permissions are loaded when connecting to the server + Map permissions = {}; + + // Profile authentication token + String get token => profile?.token ?? ""; + + bool get hasToken => token.isNotEmpty; + + String? get serverAddress { + return profile?.server; + } /* * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. */ - bool checkConnection(BuildContext context) { - // Firstly, is the server connected? + bool checkConnection() { + // Is the server connected? if (!isConnected()) { - showSnackIcon( L10().notConnected, success: false, - icon: FontAwesomeIcons.server + icon: TablerIcons.server, ); return false; @@ -219,23 +276,86 @@ 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; + int get userId => (userInfo["pk"] ?? -1) as int; - int get apiVersion => _apiVersion; + // Map of server information + Map serverInfo = {}; - // Are plugins enabled on the server? - bool _pluginsEnabled = false; + String get serverInstance => (serverInfo["instance"] ?? "") as String; + String get serverVersion => (serverInfo["version"] ?? "") as String; + int get apiVersion => (serverInfo["apiVersion"] ?? 1) as int; - // 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; + // Consolidated search request API v102 or newer + bool get supportsConsolidatedSearch => apiVersion >= 102; + + // ReturnOrder supports API v104 or newer + bool get supportsReturnOrders => apiVersion >= 104; + + // "Contact" model exposed to API + bool get supportsContactModel => apiVersion >= 104; + + // Status label endpoints API v105 or newer + bool get supportsStatusLabelEndpoints => apiVersion >= 105; + + // Regex search API v106 or newer + bool get supportsRegexSearch => apiVersion >= 106; + + // Order barcodes API v107 or newer + bool get supportsOrderBarcodes => apiVersion >= 107; + + // Project codes require v109 or newer + bool get supportsProjectCodes => apiVersion >= 109; + + // Does the server support extra fields on stock adjustment actions? + bool get supportsStockAdjustExtraFields => apiVersion >= 133; + + // Does the server support receiving items against a PO using barcodes? + bool get supportsBarcodePOReceiveEndpoint => apiVersion >= 139; + + // Does the server support adding line items to a PO using barcodes? + bool get supportsBarcodePOAddLineEndpoint => apiVersion >= 153; + + // Does the server support allocating stock to sales order using barcodes? + bool get supportsBarcodeSOAllocateEndpoint => apiVersion >= 160; + + // Does the server support the "modern" test results API + // Ref: https://github.com/inventree/InvenTree/pull/6430/ + bool get supportsModernTestResults => apiVersion >= 169; + + // Does the server support "null" top-level filtering for PartCategory and StockLocation endpoints? + bool get supportsNullTopLevelFiltering => apiVersion < 174; + + // Does the server support "active" status on Company and SupplierPart API endpoints? + bool get supportsCompanyActiveStatus => apiVersion >= 189; + + // Does the server support the "modern" (consolidated) label printing API? + bool get supportsModernLabelPrinting => apiVersion >= 201; + + // Does the server support the "modern" (consolidated) attachment API? + // Ref: https://github.com/inventree/InvenTree/pull/7420 + bool get supportsModernAttachments => apiVersion >= 207; + + bool get supportsUserPermissions => apiVersion >= 207; + + // Does the server support the "destination" field on the PurchaseOrder model? + // Ref: https://github.com/inventree/InvenTree/pull/8403 + bool get supportsPurchaseOrderDestination => apiVersion >= 276; + + // Does the server support the "start_date" field for orders? + // Ref: https://github.com/inventree/InvenTree/pull/8966 + bool get supportsStartDate => apiVersion >= 306; + + // 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 = []; @@ -263,62 +383,81 @@ 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; bool _connecting = false; bool isConnected() { - return profile != null && _connected && baseUrl.isNotEmpty && _token.isNotEmpty; + return profile != null && _connected && baseUrl.isNotEmpty && hasToken; } bool isConnecting() { return !isConnected() && _connecting; } - // Ensure we only ever create a single instance of the API class - static final InvenTreeAPI _api = InvenTreeAPI._internal(); + /* + * 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; + } - // API endpoint for receiving purchase order line items was introduced in v12 - bool supportPoReceive() { - return apiVersion >= 12; - } + if (!hasToken) { + return false; + } - // "Modern" API transactions were implemented in API v14 - bool supportModernStockTransactions() { - return apiVersion >= 14; + 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; } /* - * Connect to the remote InvenTree server: - * - * - Check that the InvenTree server exists - * - Request user token from the server - * - Request user roles from the server + * Check that the remote server is available. + * Ping the api/ endpoint, which does not require user authentication */ - Future _connect() async { - - if (profile == null) return false; - + 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.exclamationCircle, - success: false + icon: TablerIcons.exclamation_circle, + success: false, ); return false; } @@ -326,51 +465,38 @@ 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; + // 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}"); - print("Connecting to ${apiUrl} -> username=${username}"); - - APIResponse response; - - response = await get("", expectedStatusCode: 200); + APIResponse response = await get("", expectedStatusCode: 200); if (!response.successful()) { - showStatusCodeError(response.statusCode); - return false; - } - - var data = response.asMap(); - - // We expect certain response from the server - if (!data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) { - - showServerError( - L10().missingData, - L10().serverMissingData, + debug("Server returned invalid response: ${response.statusCode}"); + showStatusCodeError( + apiUrl, + response.statusCode, + details: response.data.toString(), ); + return false; + } + + Map _data = response.asMap(); + + serverInfo = {..._data}; + + if (serverVersion.isEmpty) { + showServerError(apiUrl, L10().missingData, L10().serverMissingData); return false; } - // Record server information - _version = (data["version"] ?? "") as String; - instance = (data["instance"] ?? "") as String; - - // 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}"; + if (apiVersion < _minApiVersion) { + String message = L10().serverApiVersion + ": ${apiVersion}"; message += "\n"; message += L10().serverApiRequired + ": ${_minApiVersion}"; @@ -379,147 +505,241 @@ class InvenTreeAPI { message += "Ensure your InvenTree server version is up to date!"; - showServerError( - L10().serverOld, - message, - ); + showServerError(apiUrl, L10().serverOld, message); 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}"); - // Invalid response - if (!response.successful()) { + userInfo.clear(); - switch (response.statusCode) { - case 401: - case 403: - showServerError( - L10().serverAuthenticationError, - L10().invalidUsernamePassword, - ); - break; - default: - showStatusCodeError(response.statusCode); - break; + 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; } + } - data = response.asMap(); + /* + * 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: + showServerError( + apiUrl, + L10().serverAuthenticationError, + L10().invalidUsernamePassword, + ); + default: + showStatusCodeError(apiUrl, response.statusCode); + } + + debug("Token request failed: STATUS ${response.statusCode}"); + + if (response.data != null) { + debug("Response data: ${response.data.toString()}"); + } + } + + final data = response.asMap(); if (!data.containsKey("token")) { showServerError( - L10().tokenMissing, - L10().tokenMissingFromResponse, + apiUrl, + L10().tokenMissing, + L10().tokenMissingFromResponse, ); - - return false; } - // Return the received token - _token = (data["token"] ?? "") as String; - print("Received token - $_token"); + // Save the token to the user profile + userProfile.token = (data["token"] ?? "") as String; - // Request user role information (async) - getUserRoles(); + debug("Received token from server: ${userProfile.token}"); - // Request plugin information (async) - getPluginInformation(); - - // Ok, probably pretty good... - return true; + await UserProfileDBManager().updateProfile(userProfile); + return response; } void disconnectFromServer() { - print("InvenTreeAPI().disconnectFromServer()"); + debug("API : disconnectFromServer()"); _connected = false; _connecting = false; - _token = ""; profile = null; + + // Clear received settings + _globalSettings.clear(); + _userSettings.clear(); + + roles.clear(); + _plugins.clear(); + serverInfo.clear(); + _connectionStatusChanged(); } - 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( - L10().profileSelect, - success: false, - icon: FontAwesomeIcons.exclamationCircle + L10().profileSelect, + success: false, + icon: TablerIcons.exclamation_circle, ); return false; } + // Cancel notification timer + _notification_timer?.cancel(); + _connecting = true; + _connectionStatusChanged(); - _connected = await _connect(); - + // Perform the actual connection routine + _connected = await _connectToServer(); _connecting = false; if (_connected) { showSnackIcon( L10().serverConnected, - icon: FontAwesomeIcons.server, + icon: TablerIcons.server, success: true, ); + + if (_notification_timer == null) { + debug("starting notification timer"); + _notification_timer = Timer.periodic(Duration(seconds: 60), (timer) { + _refreshNotifications(); + }); + } } + _connectionStatusChanged(); + + fetchStatusCodeData(); + return _connected; } - - Future getUserRoles() async { - + /* + * Request the user roles (permissions) from the InvenTree server + */ + Future _fetchRoles() async { 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. - // 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; + return false; } var data = response.asMap(); - if (data.containsKey("roles")) { - // Save a local copy of the user roles - roles = (response.data["roles"] ?? {}) as Map; + if (!data.containsKey("roles")) { + roles = {}; + permissions = {}; + + showServerError(apiUrl, L10().serverError, L10().errorUserRoles); + return false; } + + roles = (data["roles"] ?? {}) as Map; + + if (supportsUserPermissions && data.containsKey("permissions")) { + permissions = (data["permissions"] ?? {}) as Map; + } else { + permissions = {}; + } + + return true; } // Request plugin information from the server - Future getPluginInformation() async { + Future _fetchPlugins() async { + _plugins.clear(); - // The server does not support plugins, or they are not enabled - if (!pluginsEnabled()) { - _plugins.clear(); - return; - } - - print("Requesting plugin information"); + debug("API: getPluginInformation()"); // Request a list of plugins from the server final List results = await InvenTreePlugin().list(); @@ -532,26 +752,33 @@ class InvenTreeAPI { } } } + + return true; } - bool checkPermission(String role, String permission) { - /* - * Check if the user has the given role.permission assigned - *e - * e.g. "part", "change" - */ + /* + * Check if the user has the given role.permission assigned + * e.g. "sales_order", "change" + */ + bool checkRole(String role, String permission) { + if (!_connected) { + return false; + } // If we do not have enough information, assume permission is allowed if (roles.isEmpty) { + debug("checkRole - no roles defined!"); return true; } if (!roles.containsKey(role)) { + debug("checkRole - role '$role' not found!"); return true; } if (roles[role] == null) { - return true; + debug("checkRole - role '$role' is null!"); + return false; } try { @@ -562,7 +789,16 @@ class InvenTreeAPI { // Ignore TypeError } else { // Unknown error - report it! - sentryReportError(error, stackTrace); + sentryReportError( + "api.checkRole", + error, + stackTrace, + context: { + "role": role, + "permission": permission, + "error": error.toString(), + }, + ); } // Unable to determine permission - assume true? @@ -570,10 +806,61 @@ class InvenTreeAPI { } } + /* + * Check if the user has the particular model permission assigned + * e.g. "company", "add" + */ + bool checkPermission(String model, String permission) { + if (!_connected) { + return false; + } + + if (permissions.isEmpty) { + // Not enough information available - default to True + return true; + } + + if (!permissions.containsKey(model)) { + debug("checkPermission - model '$model' not found!"); + return false; + } + + if (permissions[model] == null) { + debug("checkPermission - model '$model' is null!"); + return false; + } + + try { + List perms = List.from(permissions[model] as List); + return perms.contains(permission); + } catch (error, stackTrace) { + if (error is TypeError) { + // Ignore TypeError + } else { + // Unknown error - report it! + sentryReportError( + "api.checkPermission", + error, + stackTrace, + context: { + "model": model, + "permission": permission, + "error": error.toString(), + }, + ); + } + + // Unable to determine permission - assume true? + return true; + } + } // 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"); @@ -583,14 +870,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, ); } @@ -598,14 +885,12 @@ 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; + } - showSnackIcon( - L10().downloading, - icon: FontAwesomeIcons.download, - success: true - ); - - // Find the local downlods directory + // Find the local downloads directory final Directory dir = await getTemporaryDirectory(); String filename = url.split("/").last; @@ -615,48 +900,52 @@ 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; } 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(strictHttps: strictHttps); + var client = createClient(url, strictHttps: strictHttps); + + showLoadingOverlay(); // 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 - _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) { - print("SocketException at ${url}: ${error.toString()}"); - showServerError(L10().connectionRefused, error.toString()); + debug("SocketException at ${url}: ${error.toString()}"); + showServerError(url, L10().connectionRefused, error.toString()); return; } on TimeoutException { - print("TimeoutException at ${url}"); - showTimeoutError(); + debug("TimeoutException at ${url}"); + showTimeoutError(url); return; } on HandshakeException catch (error) { - print("HandshakeException at ${url}:"); - print(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + debug("HandshakeException at ${url}:"); + debug(error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); return; } catch (error, stackTrace) { - print("Server error at ${url}: ${error.toString()}"); - showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + debug("Server error at ${url}: ${error.toString()}"); + showServerError(url, L10().serverError, error.toString()); + sentryReportError("api.downloadFile : client.openUrl", error, stackTrace); return; } @@ -671,36 +960,59 @@ class InvenTreeAPI { await localFile.writeAsBytes(bytes); if (openOnDownload) { - OpenFile.open(local_path); + hideLoadingOverlay(); + OpenFilex.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(); - } catch (error) { - print("Error downloading image:"); - print(error.toString()); - showServerError(L10().downloadError, error.toString()); + showTimeoutError(url); + } catch (error, stackTrace) { + debug("Error downloading image:"); + debug(error.toString()); + showServerError(url, L10().downloadError, error.toString()); + sentryReportError( + "api.downloadFile : client.closeRequest", + error, + stackTrace, + ); } + + hideLoadingOverlay(); } /* * Upload a file to the given URL */ - Future uploadFile(String url, File f, - {String name = "attachment", String method="POST", Map? fields}) async { - var _url = makeApiUrl(url); + Future uploadFile( + String url, + File f, { + String name = "attachment", + String method = "POST", + Map? fields, + }) async { + 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) { request.fields[key] = ""; } else { @@ -709,65 +1021,67 @@ class InvenTreeAPI { }); } + // Add file to upload var _file = await http.MultipartFile.fromPath(name, f.path); - request.files.add(_file); - APIResponse response = APIResponse( - url: url, - method: method, - ); + // 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); // Report a server-side error - if (response.statusCode >= 500) { + 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) { - 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}" + L10().formatExceptionJson + ":\n${jsondata}", ); sentryReportMessage( - "Error decoding JSON response from server", - context: { - "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(); + showTimeoutError(url); response.error = "TimeoutException"; } catch (error, stackTrace) { - showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + showServerError(url, L10().serverError, error.toString()); + sentryReportError("api.uploadFile", error, stackTrace); response.error = "UnknownError"; response.errorDetail = error.toString(); } @@ -781,16 +1095,19 @@ 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 - return APIResponse( - url: url, - method: "OPTIONS" - ); + return APIResponse(url: url, method: "OPTIONS"); } return completeRequest(request); @@ -800,42 +1117,80 @@ 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, ); } - HttpClient createClient({bool strictHttps = false}) { + /* + * Perform a request to link a custom barcode to a particular item + */ + Future linkBarcode(Map body) async { + HttpClientRequest? request = await apiRequest("/barcode/link/", "POST"); + if (request == null) { + return false; + } + + 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) { + return false; + } + + final response = await completeRequest( + 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( - 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); @@ -850,10 +1205,19 @@ 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); + if (_url.isEmpty) { + showServerError(url, L10().invalidHost, L10().invalidHostDetails); + return null; + } + // Add any required query parameters to the URL using ?key=value notation if (urlParams.isNotEmpty) { String query = "?"; @@ -870,140 +1234,171 @@ class InvenTreeAPI { Uri? _uri = Uri.tryParse(_url); - if (_uri == null) { - showServerError(L10().invalidHost, L10().invalidHostDetails); - return null; - } - - if (_uri.host.isEmpty) { - showServerError(L10().invalidHost, L10().invalidHostDetails); + if (_uri == null || _uri.host.isEmpty) { + 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(strictHttps: strictHttps); + 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)); - // 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()); + // 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) { - print("SocketException at ${url}: ${error.toString()}"); - showServerError(L10().connectionRefused, error.toString()); + debug("SocketException at ${url}: ${error.toString()}"); + showServerError(url, L10().connectionRefused, error.toString()); return null; } on TimeoutException { - print("TimeoutException at ${url}"); - showTimeoutError(); + 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) { - print("CertificateException at ${url}:"); - print(error.toString()); - showServerError(L10().serverCertificateError, error.toString()); + debug("CertificateException at ${url}:"); + debug(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()); + debug("HandshakeException at ${url}:"); + debug(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()); - sentryReportError(error, stackTrace); + debug("Server error at ${url}: ${error.toString()}"); + showServerError(url, L10().serverError, error.toString()); + sentryReportError( + "api.apiRequest : openUrl", + 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; // 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", - 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 { - - if (ignoreResponse) { - response.data = {}; - } else { - response.data = await responseToJson(_response) ?? {}; + // 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 + 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(), + }, + ); } + } else { + response.data = ignoreResponse + ? {} + : await responseToJson(url, _response) ?? {}; - if (statusCode != null) { - - // Expected status code not returned - if (statusCode != _response.statusCode) { - showStatusCodeError(_response.statusCode); - } + // 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(), + ); } } - + } on HttpException catch (error) { + showServerError(url, L10().serverError, error.toString()); + response.error = "HTTPException"; + response.errorDetail = error.toString(); } 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) { + debug("CertificateException at ${request.uri.toString()}:"); + debug(error.toString()); + showServerError(url, L10().serverCertificateError, error.toString()); } on TimeoutException { - showTimeoutError(); + showTimeoutError(url); response.error = "TimeoutException"; } catch (error, stackTrace) { - showServerError(L10().serverError, error.toString()); - sentryReportError(error, stackTrace); + showServerError(url, L10().serverError, error.toString()); + sentryReportError("api.completeRequest", error, stackTrace); response.error = "UnknownError"; response.errorDetail = error.toString(); } return response; - } /* * 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(); try { @@ -1011,37 +1406,56 @@ class InvenTreeAPI { return data ?? {}; } on FormatException { - - sentryReportMessage( - "Error decoding JSON response from server", - context: { - "headers": response.headers.toString(), - "statusCode": response.statusCode.toString(), - "data": body.toString(), - } - ); + switch (response.statusCode) { + case 400: + case 401: + case 403: + 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", + 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 {}, 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, ); if (request == null) { @@ -1060,11 +1474,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 @@ -1075,29 +1485,47 @@ 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; + + if (locale != null) { + return locale.languageCode; //.toString(); + } + } + } + + // Fallback value + return Intl.getCurrentLocale(); } // Return a list of request headers 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] = Intl.getCurrentLocale(); + headers[HttpHeaders.acceptLanguageHeader] = currentLocale; 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 ""; } @@ -1107,11 +1535,34 @@ class InvenTreeAPI { static String get staticThumb => "/static/img/blank_image.thumbnail.png"; + CachedNetworkImage? getThumbnail( + String imageUrl, { + double size = 40, + bool hideIfNull = false, + }) { + if (hideIfNull) { + if (imageUrl.isEmpty) { + return null; + } + } + + try { + return getImage(imageUrl, width: size, height: size); + } catch (error, stackTrace) { + sentryReportError("_getThumbnail", error, stackTrace); + return null; + } + } + /* * 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; } @@ -1121,22 +1572,208 @@ 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) => FaIcon(FontAwesomeIcons.timesCircle, 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, cacheManager: manager, ); } + + // Keep a record of which settings we have received from the server + Map _globalSettings = {}; + Map _userSettings = {}; + + Future getGlobalSetting(String key) async { + 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 ""; + } + } + + // Return a boolean global setting value + Future getGlobalBooleanSetting( + String key, { + bool backup = false, + }) async { + String value = await getGlobalSetting(key); + + if (value.isEmpty) { + return backup; + } + + return value.toLowerCase().trim() == "true"; + } + + Future getUserSetting(String key) async { + InvenTreeUserSetting? setting = _userSettings[key]; + + if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { + return setting.value; + } + + final response = await InvenTreeUserSetting().getModel(key); + + if (response is InvenTreeUserSetting) { + response.lastReload = DateTime.now(); + _userSettings[key] = response; + return response.value; + } else { + return ""; + } + } + + // Return a boolean user setting value + Future getUserBooleanSetting(String key) async { + String value = await getUserSetting(key); + return value.toLowerCase().trim() == "true"; + } + + /* + * 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"); + + 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: TablerIcons.location_search, + 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); + } + }); + } + + // 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/"); + 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; + + Timer? _notification_timer; + + /* + * Update notification counter (called periodically) + */ + Future _refreshNotifications() async { + if (!isConnected()) { + return; + } + + InvenTreeNotification().count(filters: {"read": "false"}).then((int n) { + notification_counter = n; + }); + } } diff --git a/lib/api_form.dart b/lib/api_form.dart index ff82759..9df134c 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -1,44 +1,77 @@ - 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"; 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/helpers.dart"; -import "package:inventree/inventree/part.dart"; -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/inventree/stock.dart"; -import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/fields.dart"; import "package:inventree/l10.dart"; -import "package:flutter/material.dart"; +import "package:inventree/inventree/company.dart"; +import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/project_code.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"; 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 = {}; @@ -46,7 +79,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; @@ -85,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; @@ -126,19 +160,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 } @@ -146,7 +177,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; @@ -156,7 +186,6 @@ class APIFormField { } catch (error) { // pass } - } // Finally, augment or override with any filters provided by the calling function @@ -173,14 +202,12 @@ class APIFormField { } return _filters; - } bool hasErrors() => errorMessages().isNotEmpty; // Extract error messages from the server response void extractErrorMessages(APIResponse response) { - dynamic errors; if (isSimple) { @@ -206,7 +233,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 @@ -239,7 +265,6 @@ class APIFormField { List get choices => (getParameter("choices") ?? []) as List; Future loadInitialData() async { - // Only for "related fields" if (type != "related field") { return; @@ -250,21 +275,13 @@ class APIFormField { return; } - int? pk = int.tryParse(value.toString()); + String url = api_url + "/" + value.toString() + "/"; - if (pk == null) { - return; - } - - 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; + formHandler?.onValueChanged(name, value); } } @@ -278,6 +295,7 @@ class APIFormField { return _constructBoolean(); case "related field": return _constructRelatedField(); + case "integer": case "float": case "decimal": return _constructFloatField(); @@ -293,18 +311,15 @@ class APIFormField { default: return ListTile( title: Text( - "Unsupported field type: '${type}'", - style: TextStyle( - color: COLOR_DANGER, - fontStyle: FontStyle.italic), - ) + "Unsupported field type: '${type}' for field '${name}'", + style: TextStyle(color: COLOR_DANGER, fontStyle: FontStyle.italic), + ), ); } } // Field for capturing a barcode Widget _constructBarcodeField(BuildContext context) { - TextEditingController controller = TextEditingController(); String barcode = (value ?? "").toString(); @@ -324,41 +339,26 @@ class APIFormField { hintText: placeholderText, ), child: ListTile( - title: TextField( - readOnly: true, - controller: controller, - ), + title: TextField(readOnly: true, controller: controller), trailing: IconButton( - icon: Icon(Icons.qr_code), + icon: Icon(TablerIcons.qrcode), onPressed: () async { var handler = UniqueBarcodeHandler((String hash) { controller.text = hash; - data["value"] = hash; - - successTone(); - - showSnackIcon( - L10().barcodeAssigned, - success: true - ); + setFieldValue(hash); + barcodeSuccess(L10().barcodeAssigned); }); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(handler) - ) - ); + 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( @@ -373,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 { @@ -388,18 +388,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( @@ -407,12 +406,9 @@ 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: FaIcon(FontAwesomeIcons.plusCircle), + icon: Icon(TablerIcons.circle_plus), onPressed: () async { FilePickerDialog.pickFile( message: L10().attachmentSelect, @@ -422,52 +418,64 @@ class APIFormField { // Save the file attachedfile = file; - } + }, ); }, - ) - ) + ), + ), ); } // 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; }, onSaved: (item) { if (item == null) { - data["value"] = null; + setFieldValue(null); } else { - data["value"] = item["value"]; + setFieldValue(item["value"]); } - } + }, ); } // Construct a floating point numerical input field Widget _constructFloatField() { + // 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( @@ -477,9 +485,18 @@ class APIFormField { helperStyle: _helperStyle(), hintText: placeholderText, ), - initialValue: simpleNumberString(double.tryParse(value.toString()) ?? 0), - keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), + 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()); @@ -490,26 +507,29 @@ class APIFormField { return null; }, onSaved: (val) { - data["value"] = val; + setFieldValue(val); }, ); - } // 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(name, item, isSelected, true); + }, + emptyBuilder: (context, item) { + return _renderEmptyResult(); + }, + searchFieldProps: TextFieldProps(autofocus: true), + ), selectedItem: initial_data, - onFind: (String filter) async { - - Map _filters = {}; - - filters.forEach((key, value) { - _filters[key] = value; - }); + asyncItems: (String filter) async { + Map _filters = {..._relatedFieldFilters(), ...filters}; _filters["search"] = filter; _filters["offset"] = "0"; @@ -517,60 +537,59 @@ class APIFormField { final APIResponse response = await InvenTreeAPI().get( api_url, - params: _filters + params: _filters, ); if (response.isValid()) { - - List results = []; - - for (var result in response.data["results"] ?? []) { - results.add(result); - } - - return results; + return response.resultsList(); } else { return []; } }, - label: label, - hint: helpText, - onChanged: null, - showClearButton: !required, + clearButtonProps: ClearButtonProps(isVisible: !required), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: label, + hintText: helpText, + ), + ), + 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; 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}'"; } }, - dropdownBuilder: (context, item, itemAsString) { - return _renderRelatedField(item, true, false); + dropdownBuilder: (context, item) { + return _renderRelatedField(name, 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"]; - } else { - data["value"] = null; - } - }, - isFilteredOnline: true, - showSearchBox: true, - autoFocusSearchBox: true, compareFn: (dynamic item, dynamic selectedItem) { // Comparison is based on the PK value @@ -578,77 +597,225 @@ class APIFormField { return false; } - return item["pk"] == selectedItem["pk"]; - } + bool result = false; + + try { + result = + item[pk_field].toString() == selectedItem[pk_field].toString(); + } catch (error) { + // Catch any conversion errors + result = false; + } + + return result; + }, ); } - Widget _renderRelatedField(dynamic item, bool selected, bool extended) { - // Render a "related field" based on the "model" type + // Construct a set of custom filters for the dropdown search + Map _relatedFieldFilters() { + switch (model) { + case InvenTreeSupplierPart.MODEL_TYPE: + return InvenTreeSupplierPart().defaultListFilters(); + case InvenTreeStockItem.MODEL_TYPE: + return InvenTreeStockItem().defaultListFilters(); + case InvenTreeSalesOrder.MODEL_TYPE: + return InvenTreeSalesOrder().defaultListFilters(); + default: + break; + } + return {}; + } + + // Render a "related field" based on the "model" type + Widget _renderRelatedField( + String fieldName, + dynamic item, + bool selected, + bool extended, + ) { // Convert to JSON - var data = Map.from((item ?? {}) as Map); + Map data = {}; + + try { + if (item is Map) { + data = Map.from(item); + } else { + data = {}; + } + } 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": - + case InvenTreePart.MODEL_TYPE: var part = InvenTreePart.fromJson(data); return ListTile( title: Text( part.fullname, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + 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().getImage(part.thumbnail, width: 40, height: 40) : 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); - case "partcategory": + 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, + ); + case InvenTreePartCategory.MODEL_TYPE: var cat = InvenTreePartCategory.fromJson(data); return ListTile( title: Text( cat.pathstring, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + 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 "stocklocation": + case InvenTreeStockItem.MODEL_TYPE: + var item = InvenTreeStockItem.fromJson(data); + return ListTile( + title: Text(item.partName), + subtitle: Text(item.locationPathString), + leading: InvenTreeAPI().getThumbnail(item.partThumbnail), + trailing: Text(item.quantityString()), + ); + case InvenTreeStockLocation.MODEL_TYPE: var loc = InvenTreeStockLocation.fromJson(data); return ListTile( title: Text( loc.pathstring, - style: TextStyle(fontWeight: selected && extended ? FontWeight.bold : FontWeight.normal) + 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); + + return ListTile( + title: Text(shipment.reference), + subtitle: Text(shipment.tracking_number), + trailing: shipment.isShipped ? Text(shipment.shipment_date!) : null, ); case "owner": String name = (data["name"] ?? "") as String; 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; + String role = (data["role"] ?? "") as String; + 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), + ); + 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), + ); + 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 ?? "", + ), + ); + 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( "Unsupported model", - style: TextStyle( - fontWeight: FontWeight.bold, - color: COLOR_DANGER - ) + style: TextStyle(fontWeight: FontWeight.bold, color: COLOR_DANGER), ), subtitle: Text("Model '${model}' rendering not supported"), ); @@ -658,7 +825,7 @@ class APIFormField { // Construct a widget to instruct the user that no results were found Widget _renderEmptyResult() { return ListTile( - leading: FaIcon(FontAwesomeIcons.search), + leading: Icon(TablerIcons.search), title: Text(L10().noResults), subtitle: Text( L10().queryNoResults, @@ -667,9 +834,15 @@ 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( @@ -683,8 +856,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)) { @@ -698,15 +874,24 @@ 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; + setFieldValue(val); }, ); } @@ -716,7 +901,7 @@ class APIFormField { fontWeight: FontWeight.bold, fontSize: 18, fontFamily: "arial", - color: hasErrors() ? COLOR_DANGER : COLOR_GRAY, + color: hasErrors() ? COLOR_DANGER : null, fontStyle: FontStyle.normal, ); } @@ -724,33 +909,9 @@ class APIFormField { TextStyle _helperStyle() { return TextStyle( fontStyle: FontStyle.italic, - color: hasErrors() ? COLOR_DANGER : COLOR_GRAY, + color: hasErrors() ? COLOR_DANGER : null, ); } - -} - - -/* - * 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; } /* @@ -763,8 +924,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 @@ -772,7 +935,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)) { @@ -788,7 +950,12 @@ 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 {}; } } @@ -798,7 +965,6 @@ Map extractFieldDefinition(Map data, String lo if (!_data.containsKey(el)) { return {}; } else { - try { Map definition = _data[el] as Map; @@ -808,15 +974,18 @@ 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 {}; } - } } - /* * Launch an API-driven form, * which uses the OPTIONS metadata (at the provided URL) @@ -830,21 +999,26 @@ 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, - Function? onCancel, - IconData icon = FontAwesomeIcons.save, - }) 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, + APIFormWidgetState? formHandler, + IconData icon = TablerIcons.device_floppy, +}) async { // 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()) { @@ -855,11 +1029,7 @@ Future launchApiForm( if (serverFields.isEmpty) { // User does not have permission to perform this action - showSnackIcon( - L10().response403, - icon: FontAwesomeIcons.userTimes, - ); - + showSnackIcon(L10().response403, icon: TablerIcons.user_x); return; } } @@ -870,7 +1040,6 @@ Future launchApiForm( APIFormField field; for (String fieldName in fields.keys) { - dynamic data = fields[fieldName]; Map fieldData = {}; @@ -887,7 +1056,7 @@ Future launchApiForm( field.definition = extractFieldDefinition(serverFields, field.lookupPath); // Skip fields with empty definitions - if (field.definition.isEmpty) { + if (url.isNotEmpty && field.definition.isEmpty) { print("Warning: Empty field definition for field '${fieldName}'"); } @@ -898,47 +1067,53 @@ 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); } + showLoadingOverlay(); + // Grab existing data for each form field for (var field in formFields) { await field.loadInitialData(); } + hideLoadingOverlay(); + // Now, launch a new widget! Navigator.push( context, - MaterialPageRoute(builder: (context) => APIFormWidget( - title, - url, - formFields, - method, - onSuccess: onSuccess, - fileField: fileField, - icon: icon, - )) + MaterialPageRoute( + builder: (context) => APIFormWidget( + title, + url, + formFields, + method, + onSuccess: onSuccess, + validate: validate, + fileField: fileField, + state: formHandler, + icon: icon, + ), + ), ); } - class APIFormWidget extends StatefulWidget { - const APIFormWidget( - this.title, - this.url, - this.fields, - this.method, - { - Key? key, - this.onSuccess, - this.fileField = "", - this.icon = FontAwesomeIcons.save, - } - ) : super(key: key); + this.title, + this.url, + this.fields, + this.method, { + Key? key, + this.state, + this.onSuccess, + this.validate, + this.fileField = "", + this.icon = TablerIcons.device_floppy, + }) : super(key: key); //! Form title to display final String title; @@ -958,38 +1133,52 @@ class APIFormWidget extends StatefulWidget { final Function(Map)? onSuccess; - @override - _APIFormWidgetState createState() => _APIFormWidgetState(title, url, fields, method, onSuccess, fileField, icon); + final bool Function(Map)? validate; + final APIFormWidgetState? state; + + // Default form handler is constructed if none is provided + @override + APIFormWidgetState createState() => state ?? APIFormWidgetState(); } - -class _APIFormWidgetState extends State { - - _APIFormWidgetState(this.title, this.url, this.fields, this.method, this.onSuccess, this.fileField, this.icon) : super(); +class APIFormWidgetState extends State { + APIFormWidgetState() : super(); final _formKey = GlobalKey(); - final String title; - - final String url; - - final String method; - - final String fileField; - - final IconData icon; - List nonFieldErrors = []; - List fields; - - Function(Map)? onSuccess; - bool spacerRequired = false; - List _buildForm() { + // 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 { + Navigator.pop(context); + widget.onSuccess?.call(responseData); + } + + List _buildForm() { List widgets = []; // Display non-field errors first @@ -997,26 +1186,16 @@ class _APIFormWidgetState extends State { for (String error in nonFieldErrors) { widgets.add( ListTile( - title: Text( - error, - style: TextStyle( - color: COLOR_DANGER, - ), - ), - leading: FaIcon( - FontAwesomeIcons.exclamationCircle, - 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 fields) { - + for (var field in formFields) { if (field.hidden) { continue; } @@ -1027,7 +1206,6 @@ class _APIFormWidgetState extends State { case "related field": case "choice": widgets.add(Divider(height: 15)); - break; default: break; } @@ -1046,8 +1224,8 @@ class _APIFormWidgetState extends State { fontStyle: FontStyle.italic, fontSize: 16, ), - ) - ) + ), + ), ); } } @@ -1058,37 +1236,30 @@ class _APIFormWidgetState extends State { case "choice": widgets.add(Divider(height: 15)); spacerRequired = false; - break; default: spacerRequired = true; - break; } - } return widgets; } Future _submit(Map data) async { - // If a file upload is required, we have to handle the submission differently - if (fileField.isNotEmpty) { - + if (widget.fileField.isNotEmpty) { // Pop the "file" field - data.remove(fileField); - - for (var field in fields) { - if (field.name == fileField) { + data.remove(widget.fileField); + for (var field in formFields) { + if (field.name == widget.fileField) { File? file = field.attachedfile; if (file != null) { - // A valid file has been supplied final response = await InvenTreeAPI().uploadFile( - url, + widget.url, file, - name: fileField, + name: widget.fileField, fields: data, ); @@ -1098,38 +1269,36 @@ class _APIFormWidgetState extends State { } } - if (method == "POST") { - final response = await InvenTreeAPI().post( - url, + if (widget.method == "POST") { + showLoadingOverlay(); + final response = await InvenTreeAPI().post( + widget.url, body: data, - expectedStatusCode: null + expectedStatusCode: null, ); + hideLoadingOverlay(); return response; - } else { + showLoadingOverlay(); final response = await InvenTreeAPI().patch( - url, + widget.url, body: data, - expectedStatusCode: null + expectedStatusCode: null, ); + hideLoadingOverlay(); return response; } } 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)) { @@ -1148,17 +1317,80 @@ 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 formFields) { + // 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; + } + } + } + } + + 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 */ Future _save(BuildContext context) async { - // Package up the form data Map data = {}; // Iterate through and find "simple" top-level fields - for (var field in fields) { + for (var field in formFields) { + if (field.readOnly) { + continue; + } if (field.isSimple) { // Simple top-level field data @@ -1166,7 +1398,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] ?? {}; @@ -1189,27 +1420,24 @@ class _APIFormWidgetState extends State { } } - // Run custom onSuccess function - var successFunc = onSuccess; + final bool isValid = widget.validate?.call(data) ?? true; + + if (!isValid) { + return; + } // An "empty" URL means we don't want to submit the form anywhere // Perhaps we just want to process the data? - if (url.isEmpty) { + 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, data); return; } final response = await _submit(data); if (!response.isValid()) { - showServerError(L10().serverError, L10().responseInvalid); + showServerError(widget.url, L10().serverError, L10().responseInvalid); return; } @@ -1217,118 +1445,87 @@ 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(); - // TODO: Display a snackBar - - if (successFunc != null) { - - // 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]; - } - } - - 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 - ); + showSnackIcon(L10().formError, success: false); // Update field errors - for (var field in fields) { + for (var field in formFields) { field.extractErrorMessages(response); } extractNonFieldErrors(response); - - break; + checkInvalidErrors(response); case 401: - showSnackIcon( - "401: " + L10().response401, - success: false - ); - break; + showSnackIcon("401: " + L10().response401, success: false); case 403: - showSnackIcon( - "403: " + L10().response403, - success: false, - ); - break; + showSnackIcon("403: " + L10().response403, success: false); case 404: - showSnackIcon( - "404: " + L10().response404, - success: false, - ); - break; + showSnackIcon("404: " + L10().response404, success: false); case 405: - showSnackIcon( - "405: " + L10().response405, - success: false, - ); - break; + showSnackIcon("405: " + L10().response405, success: false); case 500: - showSnackIcon( - "500: " + L10().response500, - success: false, - ); - break; + showSnackIcon("500: " + L10().response500, success: false); default: showSnackIcon( "${response.statusCode}: " + L10().responseInvalid, success: false, ); - break; } setState(() { // Refresh the form }); + } + // 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( appBar: AppBar( - title: Text(title), + title: Text(widget.title), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( - icon: FaIcon(icon), + icon: Icon(widget.icon), onPressed: () { - if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); _save(context); } }, - ) - ] - ), - 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), ); - } -} \ No newline at end of file +} diff --git a/lib/app_colors.dart b/lib/app_colors.dart index 99d8138..a22dfbc 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -1,19 +1,36 @@ +import "package:adaptive_theme/adaptive_theme.dart"; +import "package:flutter/material.dart"; +import "package:inventree/helpers.dart"; +import "package:one_context/one_context.dart"; +bool isDarkMode() { + if (!hasContext()) { + return false; + } -import "dart:ui"; + BuildContext? context = OneContext().context; -const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1); -const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 1); + if (context == null) { + return false; + } -const Color COLOR_CLICK = Color.fromRGBO(150, 120, 100, 0.9); + return AdaptiveTheme.of(context).brightness == Brightness.dark; +} -const Color COLOR_BLUE = Color.fromRGBO(0, 0, 250, 1); +// Return an "action" color based on the current theme +Color get COLOR_ACTION { + if (isDarkMode()) { + return Colors.lightBlueAccent; + } else { + return Colors.blue; + } +} -const Color COLOR_STAR = Color.fromRGBO(250, 250, 100, 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(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_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); +const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 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 deleted file mode 100644 index 4fd23f3..0000000 --- a/lib/barcode.dart +++ /dev/null @@ -1,579 +0,0 @@ -import "dart:io"; - -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/widget/dialogs.dart"; -import "package:inventree/widget/snacks.dart"; -import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:one_context/one_context.dart"; - -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/widget/location_display.dart"; -import "package:inventree/widget/part_detail.dart"; -import "package:inventree/widget/stock_detail.dart"; - - -class BarcodeHandler { - /* - * 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 - */ - - BarcodeHandler(); - - String getOverlayText(BuildContext context) => "Barcode Overlay"; - - QRViewController? _controller; - - Future onBarcodeMatched(BuildContext context, Map data) async { - // Called when the server "matches" a barcode - // Override this function - } - - Future onBarcodeUnknown(BuildContext context, Map data) async { - // Called when the server does not know about a barcode - // Override this function - - failureTone(); - - showSnackIcon( - L10().barcodeNoMatch, - success: false, - icon: Icons.qr_code, - ); - } - - Future onBarcodeUnhandled(BuildContext context, Map data) async { - - failureTone(); - - // Called when the server returns an unhandled response - showServerError(L10().responseUnknown, data.toString()); - - _controller?.resumeCamera(); - } - - Future processBarcode(BuildContext context, QRViewController? _controller, String barcode, {String url = "barcode/"}) async { - this._controller = _controller; - - print("Scanned barcode data: ${barcode}"); - - if (barcode.isEmpty) { - return; - } - - var response = await InvenTreeAPI().post( - url, - body: { - "barcode": barcode, - }, - expectedStatusCode: 200 - ); - - _controller?.resumeCamera(); - - Map data = response.asMap(); - - // Handle strange response from the server - if (!response.isValid() || !response.isMap()) { - onBarcodeUnknown(context, {}); - - // We want to know about this one! - await sentryReportMessage( - "BarcodeHandler.processBarcode returned strange 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, - } - ); - } else if (data.containsKey("error")) { - onBarcodeUnknown(context, data); - } else if (data.containsKey("success")) { - onBarcodeMatched(context, data); - } else { - onBarcodeUnhandled(context, data); - } - } -} - - -class BarcodeScanHandler extends BarcodeHandler { - /* - * Class for general barcode scanning. - * Scan *any* barcode without context, and then redirect app to correct view - */ - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanGeneral; - - @override - Future onBarcodeUnknown(BuildContext context, Map data) async { - - failureTone(); - - showSnackIcon( - L10().barcodeNoMatch, - icon: FontAwesomeIcons.exclamationCircle, - success: false, - ); - } - - @override - Future onBarcodeMatched(BuildContext context, Map data) async { - - int pk = -1; - - // A stocklocation has been passed? - if (data.containsKey("stocklocation")) { - - pk = (data["stocklocation"]?["pk"] ?? -1) as int; - - if (pk > 0) { - - successTone(); - - InvenTreeStockLocation().get(pk).then((var loc) { - if (loc is InvenTreeStockLocation) { - Navigator.of(context).pop(); - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); - } - }); - } else { - - failureTone(); - - showSnackIcon( - L10().invalidStockLocation, - success: false - ); - } - - } else if (data.containsKey("stockitem")) { - - pk = (data["stockitem"]?["pk"] ?? -1) as int; - - if (pk > 0) { - - successTone(); - - InvenTreeStockItem().get(pk).then((var item) { - - // Dispose of the barcode scanner - Navigator.of(context).pop(); - - if (item is InvenTreeStockItem) { - Navigator.push(context, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); - } - }); - } else { - - failureTone(); - - showSnackIcon( - L10().invalidStockItem, - success: false - ); - } - } else if (data.containsKey("part")) { - - pk = (data["part"]?["pk"] ?? -1) as int; - - if (pk > 0) { - - successTone(); - - InvenTreePart().get(pk).then((var part) { - - // Dismiss the barcode scanner - Navigator.of(context).pop(); - - if (part is InvenTreePart) { - Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); - } - }); - } else { - - failureTone(); - - showSnackIcon( - L10().invalidPart, - success: false - ); - } - } else { - - failureTone(); - - showSnackIcon( - L10().barcodeUnknown, - success: false, - onAction: () { - - OneContext().showDialog( - builder: (BuildContext context) => SimpleDialog( - title: Text(L10().unknownResponse), - children: [ - ListTile( - title: Text(L10().responseData), - subtitle: Text(data.toString()), - ) - ], - ) - ); - } - ); - } - } -} - -class StockItemScanIntoLocationHandler extends BarcodeHandler { - /* - * Barcode handler for scanning a provided StockItem into a scanned StockLocation - */ - - StockItemScanIntoLocationHandler(this.item); - - final InvenTreeStockItem item; - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanLocation; - - @override - Future onBarcodeMatched(BuildContext context, Map data) async { - // If the barcode points to a "stocklocation", great! - if (data.containsKey("stocklocation")) { - // Extract location information - int location = (data["stocklocation"]["pk"] ?? -1) as int; - - if (location == -1) { - showSnackIcon( - L10().invalidStockLocation, - success: false, - ); - - return; - } - - // Transfer stock to specified location - final result = await item.transferStock(context, location); - - if (result) { - - successTone(); - - Navigator.of(context).pop(); - - showSnackIcon( - L10().barcodeScanIntoLocationSuccess, - success: true, - ); - } else { - - failureTone(); - - showSnackIcon( - L10().barcodeScanIntoLocationFailure, - success: false - ); - } - } else { - - failureTone(); - - showSnackIcon( - L10().invalidStockLocation, - success: false, - ); - } - } -} - - -class StockLocationScanInItemsHandler extends BarcodeHandler { - /* - * Barcode handler for scanning stock item(s) into the specified StockLocation - */ - - StockLocationScanInItemsHandler(this.location); - - final InvenTreeStockLocation location; - - @override - String getOverlayText(BuildContext context) => L10().barcodeScanItem; - - @override - Future onBarcodeMatched(BuildContext context, Map data) async { - - // Returned barcode must match a stock item - if (data.containsKey("stockitem")) { - - int item_id = data["stockitem"]["pk"] as int; - - final InvenTreeStockItem? item = await InvenTreeStockItem().get(item_id) as InvenTreeStockItem?; - - if (item == null) { - - failureTone(); - - showSnackIcon( - L10().invalidStockItem, - success: false, - ); - } else if (item.locationId == location.pk) { - failureTone(); - - showSnackIcon( - L10().itemInLocation, - success: true - ); - } else { - final result = await item.transferStock(context, location.pk); - - if (result) { - - successTone(); - - showSnackIcon( - L10().barcodeScanIntoLocationSuccess, - success: true - ); - } else { - - failureTone(); - - showSnackIcon( - L10().barcodeScanIntoLocationFailure, - success: false - ); - } - } - } else { - - failureTone(); - - // Does not match a valid stock item! - showSnackIcon( - L10().invalidStockItem, - success: false, - ); - } - } -} - - -class UniqueBarcodeHandler extends BarcodeHandler { - /* - * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) - */ - - UniqueBarcodeHandler(this.callback, {this.overlayText = ""}); - - // Callback function when a "unique" barcode hash is found - final Function(String) callback; - - final String overlayText; - - @override - String getOverlayText(BuildContext context) { - if (overlayText.isEmpty) { - return L10().barcodeScanAssign; - } else { - return overlayText; - } - } - - @override - Future onBarcodeMatched(BuildContext context, Map data) async { - - failureTone(); - - // 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(BuildContext context, Map data) async { - // If the barcode is unknown, we *can* assign it to the stock item! - - if (!data.containsKey("hash")) { - showServerError( - L10().missingData, - L10().barcodeMissingHash, - ); - } else { - String hash = (data["hash"] ?? "") as String; - - if (hash.isEmpty) { - failureTone(); - - showSnackIcon( - L10().barcodeError, - success: false, - ); - } else { - - successTone(); - - // Close the barcode scanner - Navigator.of(context).pop(); - - callback(hash); - } - } - } -} - - -class InvenTreeQRView extends StatefulWidget { - - const InvenTreeQRView(this._handler, {Key? key}) : super(key: key); - - final BarcodeHandler _handler; - - @override - State createState() => _QRViewState(_handler); -} - - -class _QRViewState extends State { - - _QRViewState(this._handler) : super(); - - final GlobalKey qrKey = GlobalKey(debugLabel: "QR"); - - QRViewController? _controller; - - final BarcodeHandler _handler; - - bool flash_status = false; - - Future updateFlashStatus() async { - final bool? status = await _controller?.getFlashStatus(); - - flash_status = status != null && status; - - // Reload - 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 (Platform.isAndroid) { - _controller!.pauseCamera(); - } - - _controller!.resumeCamera(); - } - - void _onViewCreated(BuildContext context, QRViewController controller) { - _controller = controller; - controller.scannedDataStream.listen((barcode) { - _controller?.pauseCamera(); - - if (barcode.code != null) { - _handler.processBarcode(context, _controller, barcode.code ?? ""); - } - }); - } - - @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(_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()))); - - return; -} \ No newline at end of file diff --git a/lib/barcode/barcode.dart b/lib/barcode/barcode.dart new file mode 100644 index 0000000..8fe50ca --- /dev/null +++ b/lib/barcode/barcode.dart @@ -0,0 +1,439 @@ +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/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"; + +import "package:inventree/api.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"; + +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/dialogs.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/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); +} + +// Signal a barcode scan failure to the user +Future barcodeFailure(String msg, dynamic extra) async { + barcodeFailureTone(); + showSnackIcon( + 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()), + ), + ], + ), + ); + } + }, + ); +} + +/* + * 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 + */ +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; + + switch (barcodeControllerType) { + case BARCODE_CONTROLLER_WEDGE: + controller = WedgeBarcodeController(handler); + case BARCODE_CONTROLLER_CAMERA: + default: + // Already set as default option + break; + } + + return Navigator.of(context).push( + PageRouteBuilder(pageBuilder: (context, _, _) => controller, opaque: false), + ); +} + +/* + * Class for general barcode scanning. + * Scan *any* barcode without context, and then redirect app to correct view. + * + * Handles scanning of: + * + * - StockLocation + * - StockItem + * - Part + * - SupplierPart + * - 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, + ); + } + + /* + * 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)), + ); + } + } + + /* + * 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)), + ); + } + } + + /* + * 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)), + ); + } + } + + /* + * 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), + ), + ); + } + } + + /* + * 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 + */ + Future handlePurchaseOrder(int pk) async { + var order = await InvenTreePurchaseOrder().get(pk); + + if (order is InvenTreePurchaseOrder) { + OneContext().pop(); + OneContext().push( + MaterialPageRoute( + builder: (context) => PurchaseOrderDetailWidget(order), + ), + ); + } + } + + // 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 { + int pk = -1; + + String model = ""; + + // The following model types can be matched with barcodes + List validModels = [ + InvenTreeStockItem.MODEL_TYPE, + InvenTreeSupplierPart.MODEL_TYPE, + InvenTreeManufacturerPart.MODEL_TYPE, + InvenTreePart.MODEL_TYPE, + InvenTreeStockLocation.MODEL_TYPE, + InvenTreeCompany.MODEL_TYPE, + ]; + + if (InvenTreeAPI().supportsOrderBarcodes) { + validModels.add(InvenTreePurchaseOrder.MODEL_TYPE); + validModels.add(InvenTreeSalesOrder.MODEL_TYPE); + } + + for (var key in validModels) { + if (data.containsKey(key)) { + try { + pk = (data[key]?["pk"] ?? -1) as int; + + // Break on the first valid match found + if (pk > 0) { + model = key; + break; + } + } catch (error, stackTrace) { + sentryReportError("onBarcodeMatched", error, stackTrace); + } + } + } + + // A valid result has been found + if (pk > 0 && model.isNotEmpty) { + barcodeSuccessTone(); + + switch (model) { + case InvenTreeStockItem.MODEL_TYPE: + await handleStockItem(pk); + return; + case InvenTreePurchaseOrder.MODEL_TYPE: + await handlePurchaseOrder(pk); + return; + case InvenTreeSalesOrder.MODEL_TYPE: + await handleSalesOrder(pk); + return; + 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; + } + } + + // If we get here, we have not found a valid barcode result! + 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()), + ), + ], + ), + ); + } + }, + ); + } +} + +/* + * 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 + final Function(String) callback; + + final String overlayText; + + @override + String getOverlayText(BuildContext context) { + if (overlayText.isEmpty) { + return L10().barcodeScanAssign; + } else { + return overlayText; + } + } + + @override + Future onBarcodeMatched(Map data) async { + if (!data.containsKey("hash") && !data.containsKey("barcode_hash")) { + showServerError("barcode/", L10().missingData, L10().barcodeMissingHash); + } else { + String barcode; + + barcode = (data["barcode_data"] ?? "") as String; + + if (barcode.isEmpty) { + barcodeFailureTone(); + + showSnackIcon(L10().barcodeError, success: false); + } else { + barcodeSuccessTone(); + + // Close the barcode scanner + if (OneContext.hasContext) { + OneContext().pop(); + } + + callback(barcode); + } + } + } + + @override + Future onBarcodeUnknown(Map data) async { + await onBarcodeMatched(data); + } +} + +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, + ); + + 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, + ) { + showSnackIcon( + result ? L10().requestSuccessful : L10().requestFailed, + success: result, + ); + + state.refresh(context); + }); + }, + ); + } +} diff --git a/lib/barcode/camera_controller.dart b/lib/barcode/camera_controller.dart new file mode 100644 index 0000000..2baaca0 --- /dev/null +++ b/lib/barcode/camera_controller.dart @@ -0,0 +1,398 @@ +import "dart:math"; + +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: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(); + + bool flash_status = false; + + int scan_delay = 500; + bool single_scanning = false; + bool scanning_paused = false; + bool multiple_barcodes = false; + + String scanned_code = ""; + + double zoomFactor = 0.0; + + final MobileScannerController controller = MobileScannerController( + autoZoom: false, // Disable autoZoom as we implement a manual slider + ); + + @override + void initState() { + super.initState(); + _loadSettings(); + WakelockPlus.enable(); + } + + @override + void dispose() { + super.dispose(); + controller.dispose(); + WakelockPlus.disable(); + } + + /* + * 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; + }); + } + } + + @override + Future pauseScan() async { + if (mounted) { + setState(() { + scanning_paused = true; + }); + } + } + + @override + Future resumeScan() async { + controller.start(); + + if (mounted) { + setState(() { + scanning_paused = false; + }); + } + } + + /* + * Callback function when a barcode is scanned + */ + Future onScanSuccess(BarcodeCapture result) async { + if (!mounted || scanning_paused) { + return; + } + + // 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; + }); + } + + String 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 = ""; + multiple_barcodes = false; + }); + } + } + + 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!); + } + } + } + + Widget BarcodeOverlay(BuildContext context) { + 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; + + // 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), + ), + ), + ), + ], + ); + } + + /* + * 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; + + 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); + }, + ); + } + + Widget topCenterOverlay() { + return SafeArea( + child: Align( + alignment: Alignment.topCenter, + child: Padding( + 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, + ), + ), + ), + ), + ); + } + + Widget bottomCenterOverlay() { + 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.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, + ), + ), + ), + ), + ); + } + + Widget? buildActions(BuildContext context) { + 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); + } + + 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( + appBar: AppBar( + backgroundColor: COLOR_APP_BAR, + title: Text(L10().scanBarcode), + ), + floatingActionButton: buildActions(context), + body: GestureDetector( + onTap: () async { + if (mounted) { + setState(() { + // Toggle the 'scan paused' state + scanning_paused = !scanning_paused; + }); + } + }, + child: Stack( + children: [ + Column(children: [Expanded(child: BarcodeReader(context))]), + topCenterOverlay(), + bottomCenterOverlay(), + zoomSlider(), + ], + ), + ), + ); + } +} diff --git a/lib/barcode/controller.dart b/lib/barcode/controller.dart new file mode 100644 index 0000000..70a7986 --- /dev/null +++ b/lib/barcode/controller.dart @@ -0,0 +1,103 @@ +import "package:flutter/material.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; + }); + + showLoadingOverlay(); + 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(); + } +} diff --git a/lib/barcode/handler.dart b/lib/barcode/handler.dart new file mode 100644 index 0000000..3b9a72c --- /dev/null +++ b/lib/barcode/handler.dart @@ -0,0 +1,130 @@ +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.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( + (data["error"] ?? L10().barcodeNoMatch) as String, + 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/", + 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, + ); + + return; + } + + APIResponse? response; + + try { + response = await InvenTreeAPI().post( + url, + body: {"barcode": barcode, ...extra_data}, + 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()); + + Map data = response.asMap(); + + // Handle strange response from the server + if (!response.isValid() || !response.isMap()) { + await 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/purchase_order.dart b/lib/barcode/purchase_order.dart new file mode 100644 index 0000000..65f4913 --- /dev/null +++ b/lib/barcode/purchase_order.dart @@ -0,0 +1,194 @@ +import "package:flutter/material.dart"; +import "package:inventree/preferences.dart"; +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"; + +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, this.lineItem}); + + InvenTreePurchaseOrder? purchaseOrder; + InvenTreeStockLocation? location; + InvenTreePOLineItem? lineItem; + + @override + 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, + ); + + final po_extra_data = { + "purchase_order": purchaseOrder?.pk, + "location": location?.pk, + "line_item": lineItem?.pk, + "auto_allocate": !confirm, + ...extra_data, + }; + + return super.processBarcode(barcode, url: url, extra_data: po_extra_data); + } + + @override + Future onBarcodeMatched(Map data) async { + if (data.containsKey("lineitem") || data.containsKey("success")) { + barcodeSuccess(L10().receivedItem); + return; + } else { + return onBarcodeUnknown(data); + } + } + + @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); + } + + // 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); + }, + ); + } + + @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, + ); + } + + @override + Future onBarcodeUnhandled(Map data) async { + print("onBarcodeUnhandled:"); + print(data.toString()); + + super.onBarcodeUnhandled(data); + } +} diff --git a/lib/barcode/sales_order.dart b/lib/barcode/sales_order.dart new file mode 100644 index 0000000..75fbdc0 --- /dev/null +++ b/lib/barcode/sales_order.dart @@ -0,0 +1,163 @@ +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; +import "package:inventree/api_form.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/barcode.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); + } + } +} + +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); + } + + barcodeSuccess(L10().allocated); + } + + @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: 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, + ); + } +} diff --git a/lib/barcode/stock.dart b/lib/barcode/stock.dart new file mode 100644 index 0000000..09826f7 --- /dev/null +++ b/lib/barcode/stock.dart @@ -0,0 +1,270 @@ +import "package:flutter/cupertino.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"; + +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 && 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: TablerIcons.transfer, + 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: 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, + ); + } + } + } + + // 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/barcode/tones.dart b/lib/barcode/tones.dart new file mode 100644 index 0000000..0d8fddc --- /dev/null +++ b/lib/barcode/tones.dart @@ -0,0 +1,25 @@ +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"); + } +} diff --git a/lib/barcode/wedge_controller.dart b/lib/barcode/wedge_controller.dart new file mode 100644 index 0000000..5edf0f5 --- /dev/null +++ b/lib/barcode/wedge_controller.dart @@ -0,0 +1,146 @@ +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/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; + + final FocusNode _focusNode = FocusNode(); + + List _scannedCharacters = []; + + DateTime? _lastScanTime; + + @override + Future pauseScan() async { + if (mounted) { + setState(() { + canScan = false; + }); + } + } + + @override + Future resumeScan() async { + if (mounted) { + setState(() { + canScan = true; + }); + } + } + + // 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) { + return Scaffold( + appBar: AppBar( + backgroundColor: COLOR_APP_BAR, + title: Text(L10().scanBarcode), + ), + backgroundColor: Colors.black.withValues(alpha: 0.9), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(flex: 5), + Icon(TablerIcons.barcode, size: 64), + Spacer(flex: 5), + KeyboardListener( + autofocus: true, + focusNode: _focusNode, + child: SizedBox( + child: CircularProgressIndicator( + color: scanning ? COLOR_ACTION : COLOR_PROGRESS, + ), + width: 64, + height: 64, + ), + onKeyEvent: (event) { + handleKeyEvent(event); + }, + // 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), + ), + ], + ), + ), + ); + } +} diff --git a/lib/dsn.dart b/lib/dsn.dart new file mode 100644 index 0000000..87eb6eb --- /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"; 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/generated/i18n.dart b/lib/generated/i18n.dart deleted file mode 100644 index 09177b8..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 524cd92..5f74c00 100644 --- a/lib/helpers.dart +++ b/lib/helpers.dart @@ -7,31 +7,173 @@ * supressing trailing zeroes */ +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"; -import "package:inventree/app_settings.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/widget/snacks.dart"; + +List debug_messages = []; + +void clearDebugMessage() => debug_messages.clear(); + +int debugMessageCount() { + print("Debug Messages: ${debug_messages.length}"); + return debug_messages.length; +} + +// Check if the debug log contains a given message +bool debugContains(String msg, {bool raiseAssert = true}) { + bool result = false; + + for (String element in debug_messages) { + if (element.contains(msg)) { + result = true; + break; + } + } + + 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 + */ +void debug(dynamic msg) { + if (Platform.environment.containsKey("FLUTTER_TEST")) { + debug_messages.add(msg.toString()); + } + + 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) { - // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart - - return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1); -} - -Future successTone() 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 (number.toInt() == number) { + return number.toInt().toString(); + } else { + return number.toString(); } } -Future failureTone() 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 { + // Debug message for unit testing + debug("Playing audio file: '${path}'"); - final bool en = await InvenTreeSettingsManager().getValue(INV_SOUNDS_BARCODE, true) as bool; - - if (en) { - final player = AudioCache(); - player.play("sounds/barcode_error.mp3"); + if (!hasContext()) { + return; } -} \ No newline at end of file + + 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)); +} + +// 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 + */ +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; + + String value = CurrencyFormatter.format(amount, fmt); + + 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/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/bom.dart b/lib/inventree/bom.dart new file mode 100644 index 0000000..7c89376 --- /dev/null +++ b/lib/inventree/bom.dart @@ -0,0 +1,63 @@ +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) => + InvenTreeBomItem.fromJson(json); + + @override + String get URL => "bom/"; + + @override + Map defaultFilters() { + return { + "sub_part_detail": "true", + "part_detail": "true", + "show_pricing": "false", + }; + } + + // 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"); + + // Extract the ID of the related part + int get partId => getInt("part"); + + // 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 => getInt("sub_part"); +} diff --git a/lib/inventree/company.dart b/lib/inventree/company.dart index 2dec892..90ed77c 100644 --- a/lib/inventree/company.dart +++ b/lib/inventree/company.dart @@ -1,16 +1,17 @@ import "dart:async"; +import "package:flutter/material.dart"; 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 repreents the Company model in the InvenTree database. + * The InvenTreeCompany class represents the Company model in the InvenTree database. */ class InvenTreeCompany extends InvenTreeModel { - InvenTreeCompany() : super(); InvenTreeCompany.fromJson(Map json) : super.fromJson(json); @@ -18,9 +19,26 @@ class InvenTreeCompany extends InvenTreeModel { @override String get URL => "company/"; + static const String MODEL_TYPE = "company"; + @override - Map formFields() { - return { + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => CompanyDetailWidget(this)), + ); + } + + @override + List get rolesRequired => [ + "purchase_order", + "sales_order", + "return_order", + ]; + + @override + Map> formFields() { + Map> fields = { "name": {}, "description": {}, "website": {}, @@ -29,41 +47,52 @@ 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; + 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 => (jsondata["website"] ?? "") as String; + String get website => getString("website"); - String get phone => (jsondata["phone"] ?? "") as String; + String get phone => getString("phone"); - String get email => (jsondata["email"] ?? "") as String; + String get email => getString("email"); - bool get isSupplier => (jsondata["is_supplier"] ?? false) as bool; + bool get isSupplier => getBool("is_supplier"); - bool get isManufacturer => (jsondata["is_manufacturer"] ?? false) as bool; + bool get isManufacturer => getBool("is_manufacturer"); - bool get isCustomer => (jsondata["is_customer"] ?? false) as bool; + bool get isCustomer => getBool("is_customer"); - int get partSuppliedCount => (jsondata["parts_supplied"] ?? 0) as int; + bool get active => getBool("active", backup: true); - int get partManufacturedCount => (jsondata["parts_manufactured"] ?? 0) as int; + 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}" - }; + 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 = []; @@ -78,103 +107,189 @@ class InvenTreeCompany extends InvenTreeModel { } @override - InvenTreeModel createFromJson(Map json) { - var company = InvenTreeCompany.fromJson(json); - - return company; - } + InvenTreeModel createFromJson(Map json) => + InvenTreeCompany.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/"; - Map _filters() { + static const String MODEL_TYPE = "supplierpart"; + + @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 = { + "supplier": {}, + "SKU": {}, + "link": {}, + "note": {}, + "packaging": {}, + }; + + // At some point, pack_size was changed to pack_quantity + if (InvenTreeAPI().apiVersion < 117) { + fields["pack_size"] = {}; + } else { + fields["pack_quantity"] = {}; + } + + if (InvenTreeAPI().supportsCompanyActiveStatus) { + fields["active"] = {}; + } + + return fields; + } + + @override + Map defaultFilters() { return { "manufacturer_detail": "true", "supplier_detail": "true", - "manufacturer_part_detail": "true", + "part_detail": "true", }; } - @override - Map defaultListFilters() { - return _filters(); + 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 => 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 => getString("SKU"); + + bool get active => getBool("active", backup: true); + + 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; + + 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"); + + String get pack_quantity { + if (InvenTreeAPI().apiVersion < 117) { + return getString("pack_size"); + } else { + return getString("pack_quantity"); + } } @override - Map defaultGetFilters() { - return _filters(); - } - - int get manufacturerId => (jsondata["manufacturer"] ?? -1) as int; - - String get manufacturerName => (jsondata["manufacturer_detail"]["name"] ?? "") as String; - - 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; - - String get supplierImage => (jsondata["supplier_detail"]["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - - String get SKU => (jsondata["SKU"] ?? "") as String; - - String get MPN => (jsondata["MPN"] ?? "") as String; - - int get partId => (jsondata["part"] ?? -1) as int; - - String get partImage => (jsondata["part_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String; - - String get partName => (jsondata["part_detail"]["full_name"] ?? "") as String; - - @override - InvenTreeModel createFromJson(Map json) { - var part = InvenTreeSupplierPart.fromJson(json); - - return part; - } + 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/"; + String URL = "company/part/manufacturer/"; + + static const String MODEL_TYPE = "manufacturerpart"; @override - Map defaultListFilters() { - return { - "manufacturer_detail": "true", + List get rolesRequired => ["part"]; + + @override + Map> formFields() { + Map> fields = { + "manufacturer": {}, + "MPN": {}, + "link": {}, }; + + return fields; } - int get partId => (jsondata["part"] ?? -1) as int; - - int get manufacturerId => (jsondata["manufacturer"] ?? -1) as int; - - String get MPN => (jsondata["MPN"] ?? "") as String; - @override - InvenTreeModel createFromJson(Map json) { - var part = InvenTreeManufacturerPart.fromJson(json); - - return part; + 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 c39da8f..3a39e64 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -1,22 +1,22 @@ import "dart:async"; -import "dart:io"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/api.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter/material.dart"; -import "package:inventree/inventree/sentry.dart"; -import "package:inventree/widget/dialogs.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; -import "package:inventree/l10.dart"; +import "package:inventree/api.dart"; 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"; // Paginated response object class InvenTreePageResponse { - InvenTreePageResponse() { results = []; } @@ -27,7 +27,7 @@ class InvenTreePageResponse { // Total number of results in the dataset int count = 0; - + int get length => results.length; List results = []; @@ -38,12 +38,28 @@ class InvenTreePageResponse { * for interacting with InvenTree data. */ class InvenTreeModel { - InvenTreeModel(); // Construct an InvenTreeModel from a JSON data object InvenTreeModel.fromJson(this.jsondata); + // Navigate to a detail page for this item + Future goToDetailPage(BuildContext context) async { + // Default implementation does not do anything... + return null; + } + + // 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 => ""; @@ -51,8 +67,130 @@ class InvenTreeModel { // Note: If the WEB_URL is the same (except for /api/) as URL then just leave blank String get WEB_URL => ""; - String get webUrl { + // Return the "model type" of this model + static const String MODEL_TYPE = ""; + // 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 { + 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? getDoubleOrNull(String key, {double? backup, String subKey = ""}) { + dynamic value = getValue(key, backup: backup, subKey: subKey); + + if (value == null) { + return backup; + } + + 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); + + if (value == null) { + return backup; + } + + 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 { if (api.isConnected()) { String web = InvenTreeAPI().baseUrl; @@ -63,22 +201,84 @@ class InvenTreeModel { web = web.replaceAll("//", "/"); return web; - } 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().checkRole(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().checkRole(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().checkRole(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().checkRole(role, "view")) { + return true; + } + } + + // Fallback + return false; } // Fields for editing / creating this model // Override per-model - Map formFields() { - + 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(); } @@ -93,11 +293,17 @@ class InvenTreeModel { method: "POST", fileField: fileField, ); - } - Future editForm(BuildContext context, String title, {Map fields=const {}, Function(dynamic)? onSuccess}) async { - + /* + * 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 { if (fields.isEmpty) { fields = formFields(); } @@ -109,9 +315,8 @@ class InvenTreeModel { fields, modelData: jsondata, onSuccess: onSuccess, - method: "PATCH" + method: "PATCH", ); - } // JSON data which defines this object @@ -120,55 +325,124 @@ class InvenTreeModel { // Accessor for the API InvenTreeAPI get api => InvenTreeAPI(); - int get pk => (jsondata["pk"] ?? -1) as int; + int get pk => getInt("pk"); + + String get pkString => pk.toString(); // 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 => (jsondata["notes"] ?? "") as String; + int get logicalStatus => getInt("status"); - int get parentId => (jsondata["parent"] ?? -1) as int; + 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"); // Legacy API provided external link as "URL", while newer API uses "link" String get link => (jsondata["link"] ?? jsondata["URL"] ?? "") as String; - Future goToInvenTreePage() async { + bool get hasLink => link.isNotEmpty; - if (await canLaunch(webUrl)) { - await launch(webUrl); + /* + * Attempt to extract a custom icon for this model. + * If icon data is provided, attempt to convert to a TablerIcon icon + */ + IconData? get customIcon { + String icon = (jsondata["icon"] ?? "").toString().trim(); + + // Empty icon (default) + if (icon.isEmpty) { + return null; + } + + // Tabler icon is of the format "ti:: items = icon.split(":"); + + if (items.length < 2) { + 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. + * Note that old API used 'uid' (only for StockItem), + * but this was updated to use 'barcode_hash' + */ + String get customBarcode { + if (jsondata.containsKey("uid")) { + return jsondata["uid"] as String; + } else if (jsondata.containsKey("barcode_hash")) { + return jsondata["barcode_hash"] as String; + } else if (jsondata.containsKey("barcode")) { + return jsondata["barcode"] as String; + } + + // Empty string if no match + return ""; + } + + Future goToInvenTreePage() async { + var uri = Uri.tryParse(webUrl); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); } else { // TODO } } - Future openLink() async { - + 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); } } } - 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("//", "/"); // 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) { @@ -182,12 +456,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) { @@ -205,48 +480,84 @@ class InvenTreeModel { if (response.isValid()) { int n = int.tryParse(response.data["count"].toString()) ?? 0; - - print("${URL} -> ${n} results"); return n; } else { return 0; } -} + } + + Map defaultFilters() { + return {}; + } Map defaultListFilters() { - return {}; + return defaultFilters(); } // A map of "default" headers to use when performing a GET request Map defaultGetFilters() { - return {}; + return defaultFilters(); + } + + /* + * Report error information to sentry, when a model operation fails. + */ + 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 + if (response.errorDetail.isNotEmpty) { + return; + } + + // If the response status code indicates a server error, then this has already been reported + if (response.statusCode >= 500) { + return; + } + + 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 { + // Return if we do not have a valid pk + if (pk < 0) { + return false; + } + var response = await api.delete(url); - 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, - } - ); - } - - showServerError( - L10().serverError, - L10().errorDelete, + if (!response.isValid() || + response.data == null || + (response.data is! Map)) { + reportModelError( + "InvenTreeModel.delete() returned invalid response", + response, ); + showServerError(url, L10().serverError, L10().errorDelete); + return false; } @@ -258,65 +569,82 @@ 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, + ); - 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, - }, + // 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()}, ); + + showServerError(url, L10().serverError, L10().responseInvalid); + + return false; + } + } else { + switch (response.statusCode) { + case 404: // Object has been deleted + showSnackIcon(L10().itemDeleted, success: false); + default: + String detail = L10().errorFetch; + detail += "\n${L10().statusCode}: ${response.statusCode}"; + + showServerError(url, L10().serverError, detail); } - showServerError( - L10().serverError, - L10().errorFetch, - ); - return false; - } + lastReload = DateTime.now(); + jsondata = response.asMap(); return true; } // POST data to update the model - Future update({Map values = const {}}) 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); + } + if (!url.endsWith("/")) { url += "/"; } - var response = await api.patch( + final response = await api.patch( url, body: values, - expectedStatusCode: 200 + expectedStatusCode: expectedStatusCode, ); - if (!response.isValid()) { - return false; - } - - return true; + return response; } // 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()); if (!url.endsWith("/")) { @@ -333,35 +661,37 @@ class InvenTreeModel { var response = await api.get(url, params: params); 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, - } + if (response.statusCode != -1) { + // Report error + reportModelError( + "InvenTreeModel.getModel() returned invalid response", + response, + context: {"filters": filters.toString(), "pk": pk}, ); } - showServerError( - L10().serverError, - L10().errorFetch, - ); + showServerError(url, L10().serverError, L10().errorFetch); return null; - } + lastReload = DateTime.now(); + return createFromJson(response.asMap()); } - Future create(Map data) async { + Future get( + int pk, { + Map filters = const {}, + }) async { + if (pk < 0) { + return null; + } + return getModel(pk.toString(), filters: filters); + } + + Future create(Map data) async { if (data.containsKey("pk")) { data.remove("pk"); } @@ -374,26 +704,13 @@ 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, - } - ); - } - - showServerError( - L10().serverError, - L10().errorCreate, + reportModelError( + "InvenTreeModel.create() returned invalid response", + response, + context: {"pk": pk.toString()}, ); + showServerError(URL, L10().serverError, L10().errorCreate); return null; } @@ -401,7 +718,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) { @@ -417,7 +738,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"] ?? ""; @@ -435,27 +755,48 @@ 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 - page.results = []; + if (dataMap.isNotEmpty && + dataMap.containsKey("count") && + dataMap.containsKey("results")) { + page.count = (dataMap["count"] ?? 0) as int; - for (var result in response.data["results"]) { - page.addResult(createFromJson(result as Map)); - } + page.results = []; - return page; + List results = dataMap["results"] as List; - } else { - return null; + for (dynamic result in results) { + page.addResult(createFromJson(result as Map)); + } + + return page; } + + // 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 { - + Future> list({ + Map filters = const {}, + }) async { var params = defaultListFilters(); for (String key in filters.keys) { @@ -484,7 +825,6 @@ class InvenTreeModel { } for (var d in data) { - // Create a new object (of the current class type InvenTreeModel obj = createFromJson(d as Map); @@ -494,12 +834,6 @@ class InvenTreeModel { return results; } - - // Provide a listing of objects at the endpoint - // TODO - Static function which returns a list of objects (of this class) - - // TODO - Define a "save" / "update" function - // Override this function for each sub-class bool matchAgainstString(String filter) { // Default implementation matches name and description @@ -516,7 +850,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) { @@ -529,115 +862,89 @@ 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) { - return InvenTreePlugin.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => + InvenTreePlugin.fromJson(json); @override - String get URL => "plugin/"; + String get URL { + /* Note: The plugin API endpoint changed at API version 90, + * < 90 = 'plugin' + * >= 90 = 'plugins' + * Ref: https://github.com/inventree/InvenTree/pull/4186 + */ + if (api.isConnected() && api.apiVersion < 90) { + return "plugin/"; + } else { + return "plugins/"; + } + } - String get key => (jsondata["key"] ?? "") as String; + String get key => getString("key"); - bool get active => (jsondata["active"] ?? false) as bool; + 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: + * - GlobalSetting (applicable to all users) + * - UserSetting (applicable only to the current user) + */ +class InvenTreeGlobalSetting extends InvenTreeModel { + InvenTreeGlobalSetting() : super(); -class InvenTreeAttachment extends InvenTreeModel { - // Class representing an "attachment" file - InvenTreeAttachment() : super(); + InvenTreeGlobalSetting.fromJson(Map json) + : super.fromJson(json); - InvenTreeAttachment.fromJson(Map json) : super.fromJson(json); - - String get attachment => (jsondata["attachment"] ?? "") as String; - - // Return the filename of the attachment - String get filename { - return attachment.split("/").last; + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeGlobalSetting.fromJson(json); } - IconData get icon { - String fn = filename.toLowerCase(); + @override + String get URL => "settings/global/"; - if (fn.endsWith(".pdf")) { - return FontAwesomeIcons.filePdf; - } else if (fn.endsWith(".csv")) { - return FontAwesomeIcons.fileCsv; - } else if (fn.endsWith(".doc") || fn.endsWith(".docx")) { - return FontAwesomeIcons.fileWord; - } else if (fn.endsWith(".xls") || fn.endsWith(".xlsx")) { - return FontAwesomeIcons.fileExcel; - } + String get key => getString("key"); - // Image formats - final List img_formats = [ - ".png", - ".jpg", - ".gif", - ".bmp", - ".svg", - ]; - - for (String fmt in img_formats) { - if (fn.endsWith(fmt)) { - return FontAwesomeIcons.fileImage; - } - } - - return FontAwesomeIcons.fileAlt; - } - - String get comment => (jsondata["comment"] ?? "") as String; - - DateTime? get uploadDate { - if (jsondata.containsKey("upload_date")) { - return DateTime.tryParse((jsondata["upload_date"] ?? "") as String); - } else { - return null; - } - } - - Future uploadAttachment(File attachment, {String comment = "", Map fields = const {}}) async { - - final APIResponse response = await InvenTreeAPI().uploadFile( - URL, - attachment, - method: "POST", - name: "attachment", - fields: fields - ); - - return response.successful(); - } - - Future downloadAttachment() async { - - await InvenTreeAPI().downloadFile(attachment); - - } + String get value => getString("value"); + String get type => getString("type"); } +class InvenTreeUserSetting extends InvenTreeGlobalSetting { + InvenTreeUserSetting() : super(); + InvenTreeUserSetting.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeUserSetting.fromJson(json); + } + + @override + String get URL => "settings/user/"; +} diff --git a/lib/inventree/notification.dart b/lib/inventree/notification.dart new file mode 100644 index 0000000..eee2872 --- /dev/null +++ b/lib/inventree/notification.dart @@ -0,0 +1,48 @@ +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/"; + + @override + Map defaultListFilters() { + // By default, only return 'unread' notifications + return {"read": "false"}; + } + + String get message => getString("message"); + + DateTime? get creationDate { + if (jsondata.containsKey("creation")) { + return DateTime.tryParse((jsondata["creation"] ?? "") as String); + } else { + return null; + } + } + + /* + * 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"}); + } else { + await api.post("${url}read/"); + } + } +} diff --git a/lib/inventree/orders.dart b/lib/inventree/orders.dart new file mode 100644 index 0000000..124ded2 --- /dev/null +++ b/lib/inventree/orders.dart @@ -0,0 +1,161 @@ +/* + * 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 startDate => getString("start_date"); + + String get completionDate => getDateString("complete_date"); + + String get creationDate => getDateString("creation_date"); + + String get shipmentDate => getDateString("shipment_date"); + + String get targetDate => getDateString("target_date"); + + int get lineItemCount => getInt("line_items", backup: 0); + + 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"); + + String get reference => getString("reference"); + + int get responsibleId => getInt("responsible"); + + String get responsibleName => getString("name", 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"); + + bool get hasProjectCode => projectCode.isNotEmpty; + + 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 { + String img = getString("thumbnail", subKey: "part_detail"); + + if (img.isEmpty) { + img = getString("image", subKey: "part_detail"); + } + + return img; + } + + String get targetDate => getDateString("target_date"); +} + +/* + * Generic class representing an "ExtraLineItem" + */ +class InvenTreeExtraLineItem extends InvenTreeModel { + InvenTreeExtraLineItem() : super(); + + InvenTreeExtraLineItem.fromJson(Map json) + : super.fromJson(json); + + int get orderId => getInt("order"); + + double get quantity => getDouble("quantity"); + + String get reference => getString("reference"); + + double get price => getDouble("price"); + + String get priceCurrency => getString("price_currency"); + + @override + Map> formFields() { + return { + "order": { + // The order cannot be edited + "hidden": true, + }, + "reference": {}, + "description": {}, + "quantity": {}, + "price": {}, + "price_currency": {}, + "link": {}, + "notes": {}, + }; + } +} 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 723a7e8..033fae9 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -1,47 +1,61 @@ import "dart:io"; +import "dart:math"; + +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/inventree/sentry.dart"; import "package:inventree/l10.dart"; +import "package:inventree/inventree/stock.dart"; +import "package:inventree/inventree/company.dart"; 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/"; - @override - Map formFields() { + static const String MODEL_TYPE = "partcategory"; - return { + @override + List get rolesRequired => ["part"]; + + // Navigate to a detail page for this item + @override + Future goToDetailPage(BuildContext context) async { + // Default implementation does not do anything... + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(this)), + ); + } + + @override + Map> formFields() { + Map> fields = { "name": {}, "description": {}, - "parent": {} + "parent": {}, + "structural": {}, }; + + return fields; } - @override - Map defaultListFilters() { + String get pathstring => getString("pathstring"); - return { - "active": "true", - "cascade": "false" - }; - } - - String get pathstring => (jsondata["pathstring"] ?? "") as String; - - String get parentpathstring { - // TODO - Drive the refactor tractor through this + String get parentPathString { List psplit = pathstring.split("/"); if (psplit.isNotEmpty) { @@ -57,47 +71,45 @@ class InvenTreePartCategory extends InvenTreeModel { return p; } - int get partcount => (jsondata["parts"] ?? 0) as int; + // 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; @override - InvenTreeModel createFromJson(Map json) { - var cat = InvenTreePartCategory.fromJson(json); - - // TODO ? - - return cat; - } + 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/"; - String get key => (jsondata["key"] ?? "") as String; + static const String MODEL_TYPE = "parttesttemplate"; - String get testName => (jsondata["test_name"] ?? "") as String; + String get key => getString("key"); - bool get required => (jsondata["required"] ?? false) as bool; + String get testName => getString("test_name"); - bool get requiresValue => (jsondata["requires_value"] ?? false) as bool; + bool get required => getBool("required"); - bool get requiresAttachment => (jsondata["requires_attachment"] ?? false) as bool; + bool get requiresValue => getBool("requires_value"); + + 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() { - var result = latestResult(); if (result == null) { @@ -118,12 +130,12 @@ class InvenTreePartTestTemplate extends InvenTreeModel { return results.last; } - } - +/* + * Class representing the Part database model + */ class InvenTreePart extends InvenTreeModel { - InvenTreePart() : super(); InvenTreePart.fromJson(Map json) : super.fromJson(json); @@ -131,8 +143,23 @@ class InvenTreePart extends InvenTreeModel { @override String get URL => "part/"; + static const String MODEL_TYPE = "part"; + @override - Map formFields() { + List get rolesRequired => ["part"]; + + // Navigate to a detail page for this item + @override + Future goToDetailPage(BuildContext context) async { + // Default implementation does not do anything... + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => PartDetailWidget(this)), + ); + } + + @override + Map> formFields() { return { "name": {}, "description": {}, @@ -160,18 +187,8 @@ class InvenTreePart extends InvenTreeModel { } @override - Map defaultListFilters() { - return { - "cascade": "false", - "active": "true", - }; - } - - @override - Map defaultGetFilters() { - return { - "category_detail": "true", // Include category detail information - }; + Map defaultFilters() { + return {"category_detail": "true"}; } // Cached list of stock items @@ -180,34 +197,50 @@ 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); + } + } + }); } - int get supplierCount => (jsondata["suppliers"] ?? 0) as int; + // Request pricing data for this part + Future getPricing() async { + 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 Future> getSupplierParts() async { List _supplierParts = []; final parts = await InvenTreeSupplierPart().list( - filters: { - "part": "${pk}", - } + filters: {"part": "${pk}"}, ); for (var result in parts) { @@ -219,7 +252,6 @@ class InvenTreePart extends InvenTreeModel { return _supplierParts; } - // Cached list of test templates List testingTemplates = []; @@ -227,13 +259,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) { @@ -246,196 +274,214 @@ 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 { + 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")) { + unallocated = + double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; + } else { + unallocated = inStock; } - // Get the stock count for this Part - double get inStock => double.tryParse(jsondata["in_stock"].toString()) ?? 0; + return max(0, unallocated); + } - String get inStockString { + String get unallocatedStockString => simpleNumberString(unallocatedStock); - String q = simpleNumberString(inStock); + String stockString({bool includeUnits = true}) { + String q = unallocatedStockString; - if (units.isNotEmpty) { - q += " ${units}"; - } - - return q; + if (unallocatedStock != inStock) { + q += " / ${inStockString}"; } - // 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; - } + if (includeUnits && units.isNotEmpty) { + q += " ${units}"; } - String get unallocatedStockString { - String q = simpleNumberString(unallocatedStock); + return q; + } - if (units.isNotEmpty) { - q += " ${units}"; - } + String get units => getString("units"); - return q; - } + // Get the ID of the Part that this part is a variant of (or null) + int? get variantOf => jsondata["variant_of"] as int?; - String stockString({bool includeUnits = true}) { - String q = unallocatedStockString; + // Get the number of units being build for this Part + double get building => getDouble("building"); - if (unallocatedStock != inStock) { - q += " / ${inStockString}"; - } + // 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; - if (includeUnits && units.isNotEmpty) { - q += " ${units}"; - } + bool get isAssembly => getBool("assembly"); - return q; - } + bool get isComponent => getBool("component"); - String get units => (jsondata["units"] ?? "") as String; + bool get isPurchaseable => getBool("purchaseable"); - // Get the ID of the Part that this part is a variant of (or null) - int? get variantOf => jsondata["variant_of"] as int?; + bool get isSalable => getBool("salable"); - // Get the number of units being build for this Part - double get building => double.tryParse(jsondata["building"].toString()) ?? 0; + bool get isActive => getBool("active"); - // Get the number of BOM items in this Part (if it is an assembly) - int get bomItemCount => (jsondata["bom_items"] ?? 0) as int; + bool get isVirtual => getBool("virtual"); - // Get the number of BOMs this Part is used in (if it is a component) - int get usedInCount => (jsondata["used_in"] ?? 0) as int; + bool get isTemplate => getBool("is_template"); - bool get isAssembly => (jsondata["assembly"] ?? false) as bool; + bool get isTrackable => getBool("trackable"); - bool get isComponent => (jsondata["component"] ?? false) as bool; + bool get isTestable => getBool("testable"); - bool get isPurchaseable => (jsondata["purchaseable"] ?? false) as bool; + // Get the IPN (internal part number) for the Part instance + String get IPN => getString("IPN"); - bool get isSalable => (jsondata["salable"] ?? false) as bool; + // Get the revision string for the Part instance + String get revision => getString("revision"); - bool get isActive => (jsondata["active"] ?? false) as bool; + // Get the category ID for the Part instance (or "null" if does not exist) + int get categoryId => getInt("category"); - bool get isVirtual => (jsondata["virtual"] ?? false) as bool; + // Get the category name for the Part instance + String get categoryName { + // Inavlid category ID + if (categoryId <= 0) return ""; - bool get isTrackable => (jsondata["trackable"] ?? false) as bool; + if (!jsondata.containsKey("category_detail")) return ""; - // Get the IPN (internal part number) for the Part instance - String get IPN => (jsondata["IPN"] ?? "") as String; + return (jsondata["category_detail"]?["name"] ?? "") as String; + } - // Get the revision string for the Part instance - String get revision => (jsondata["revision"] ?? "") as String; + // Get the category description for the Part instance + String get categoryDescription { + // Invalid category ID + if (categoryId <= 0) return ""; - // Get the category ID for the Part instance (or "null" if does not exist) - int get categoryId => (jsondata["category"] ?? -1) as int; + if (!jsondata.containsKey("category_detail")) return ""; - // Get the category name for the Part instance - String get categoryName { - // Inavlid category ID - if (categoryId <= 0) return ""; + return (jsondata["category_detail"]?["description"] ?? "") as String; + } - if (!jsondata.containsKey("category_detail")) return ""; + // Get the image URL for the Part instance + String get _image => getString("image"); - return (jsondata["category_detail"]?["name"] ?? "") as String; - } + // Get the thumbnail URL for the Part instance + String get _thumbnail => getString("thumbnail"); - // Get the category description for the Part instance - String get categoryDescription { - // Invalid category ID - if (categoryId <= 0) return ""; + // Return the fully-qualified name for the Part instance + String get fullname { + String fn = getString("full_name"); - if (!jsondata.containsKey("category_detail")) return ""; + if (fn.isNotEmpty) return fn; - return (jsondata["category_detail"]?["description"] ?? "") as String; - } - // Get the image URL for the Part instance - String get _image => (jsondata["image"] ?? "") as String; + List elements = []; - // Get the thumbnail URL for the Part instance - String get _thumbnail => (jsondata["thumbnail"] ?? "") as String; + if (IPN.isNotEmpty) elements.add(IPN); - // Return the fully-qualified name for the Part instance - String get fullname { + elements.add(name); - String fn = (jsondata["full_name"] ?? "") as String; + if (revision.isNotEmpty) elements.add(revision); - if (fn.isNotEmpty) return fn; + return elements.join(" | "); + } - List elements = []; + // Return a path to the image for this Part + String get image { + // Use thumbnail as a backup + String img = _image.isNotEmpty ? _image : _thumbnail; - if (IPN.isNotEmpty) elements.add(IPN); + return img.isNotEmpty ? img : InvenTreeAPI.staticImage; + } - elements.add(name); + // Return a path to the thumbnail for this part + String get thumbnail { + // Use image as a backup + String img = _thumbnail.isNotEmpty ? _thumbnail : _image; - if (revision.isNotEmpty) elements.add(revision); + return img.isNotEmpty ? img : InvenTreeAPI.staticThumb; + } - return elements.join(" | "); - } + Future uploadImage(File image) async { + // Upload file against this part + final APIResponse response = await InvenTreeAPI().uploadFile( + url, + image, + method: "PATCH", + name: "image", + ); - // Return a path to the image for this Part - String get image { - // Use thumbnail as a backup - String img = _image.isNotEmpty ? _image : _thumbnail; + return response.successful(); + } - 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 => (jsondata["starred"] ?? false) as bool; + // Return the "starred" status of this part + bool get starred => getBool("starred"); @override - InvenTreeModel createFromJson(Map json) { - - var part = InvenTreePart.fromJson(json); - - return part; - } + InvenTreeModel createFromJson(Map json) => + InvenTreePart.fromJson(json); } +class InvenTreePartPricing extends InvenTreeModel { + InvenTreePartPricing() : super(); -class InvenTreePartAttachment extends InvenTreeAttachment { - - InvenTreePartAttachment() : super(); - - InvenTreePartAttachment.fromJson(Map json) : super.fromJson(json); + InvenTreePartPricing.fromJson(Map json) + : super.fromJson(json); @override - String get URL => "part/attachment/"; + List get rolesRequired => ["part"]; @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePartAttachment.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => + InvenTreePartPricing.fromJson(json); -} \ No newline at end of file + // 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"); +} diff --git a/lib/inventree/project_code.dart b/lib/inventree/project_code.dart new file mode 100644 index 0000000..3d8793b --- /dev/null +++ b/lib/inventree/project_code.dart @@ -0,0 +1,27 @@ +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/"; + + static const String MODEL_TYPE = "projectcode"; + + @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 6b8595c..65af361 100644 --- a/lib/inventree/purchase_order.dart +++ b/lib/inventree/purchase_order.dart @@ -1,73 +1,91 @@ +import "package:flutter/material.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"; -import "package:inventree/inventree/part.dart"; - import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/orders.dart"; +import "package:inventree/widget/order/extra_line_detail.dart"; +import "package:inventree/widget/order/purchase_order_detail.dart"; +import "package:inventree/widget/progress.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; -const int PO_STATUS_CANCELLED = 40; -const int PO_STATUS_LOST = 50; -const int PO_STATUS_RETURNED = 60; - -class InvenTreePurchaseOrder extends InvenTreeModel { +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); @override String get URL => "order/po/"; + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => PurchaseOrderDetailWidget(this)), + ); + } + + static const String MODEL_TYPE = "purchaseorder"; + + @override + List get rolesRequired => ["purchase_order"]; + String get receive_url => "${url}receive/"; @override - Map formFields() { - return { + Map> formFields() { + Map> fields = { "reference": {}, + "supplier": { + "filters": {"is_supplier": true}, + }, "supplier_reference": {}, "description": {}, + "project_code": {}, + "destination": {}, + "start_date": {}, "target_date": {}, "link": {}, "responsible": {}, + "contact": { + "filters": {"company": supplierId}, + }, }; + + if (!InvenTreeAPI().supportsProjectCodes) { + fields.remove("project_code"); + } + + if (!InvenTreeAPI().supportsPurchaseOrderDestination) { + fields.remove("destination"); + } + + if (!InvenTreeAPI().supportsStartDate) { + fields.remove("start_date"); + } + + return fields; } @override - Map defaultGetFilters() { - return { - "supplier_detail": "true", - }; + Map defaultFilters() { + return {"supplier_detail": "true"}; } - @override - Map defaultListFilters() { - return { - "supplier_detail": "true", - }; - } - - String get issueDate => (jsondata["issue_date"] ?? "") as String; - - String get completeDate => (jsondata["complete_date"] ?? "") as String; - - String get creationDate => (jsondata["creation_date"] ?? "") as String; - - String get targetDate => (jsondata["target_date"] ?? "") as String; - - int get lineItemCount => (jsondata["line_items"] ?? 0) as int; - - bool get overdue => (jsondata["overdue"] ?? false) as bool; - - String get reference => (jsondata["reference"] ?? "") as String; - - int get responsibleId => (jsondata["responsible"] ?? -1) as int; - - int get supplierId => (jsondata["supplier"] ?? -1) as int; + int get supplierId => getInt("supplier"); InvenTreeCompany? get supplier { - dynamic supplier_detail = jsondata["supplier_detail"]; if (supplier_detail == null) { @@ -77,24 +95,30 @@ 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 destinationId => getInt("destination"); - String get statusText => (jsondata["status_text"] ?? "") as String; + bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, [ + "PENDING", + "PLACED", + "ON_HOLD", + ]); - bool get isOpen => status == PO_STATUS_PENDING || status == PO_STATUS_PLACED; + bool get isPending => + api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]); - bool get isPlaced => status == PO_STATUS_PLACED; + bool get isPlaced => api.PurchaseOrderStatus.isNameIn(status, ["PLACED"]); - bool get isFailed => status == PO_STATUS_CANCELLED || status == PO_STATUS_LOST || status == PO_STATUS_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 = []; @@ -108,77 +132,92 @@ class InvenTreePurchaseOrder extends InvenTreeModel { return items; } - @override - 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; + } + + showLoadingOverlay(); + await api.post("${url}issue/", expectedStatusCode: 201); + hideLoadingOverlay(); + } + + /// Mark this order as "cancelled" + Future cancelOrder() async { + if (!isOpen) { + return; + } + + showLoadingOverlay(); + await api.post("${url}cancel/", expectedStatusCode: 201); + hideLoadingOverlay(); } } -class InvenTreePOLineItem extends InvenTreeModel { - +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); @override String get URL => "order/po-line/"; @override - Map formFields() { + 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": {}, }; } @override - Map defaultGetFilters() { - return { - "part_detail": "true", - }; + Map defaultFilters() { + return {"part_detail": "true", "order_detail": "true"}; } - @override - Map defaultListFilters() { - return { - "part_detail": "true", - }; - } + double get received => getDouble("received"); bool get isComplete => received >= quantity; - double get quantity => (jsondata["quantity"] ?? 0) as double; + double get progressRatio { + if (quantity <= 0 || received <= 0) { + return 0; + } - double get received => (jsondata["received"] ?? 0) as double; + return received / quantity; + } + + String get progressString => + simpleNumberString(received) + " / " + simpleNumberString(quantity); double get outstanding => quantity - received; - String get reference => (jsondata["reference"] ?? "") as String; - - int get orderId => (jsondata["order"] ?? -1) as int; - - int get supplierPartId => (jsondata["part"] ?? -1) as int; - - 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 supplierPartId => getInt("part"); InvenTreeSupplierPart? get supplierPart { - dynamic detail = jsondata["supplier_part_detail"]; if (detail == null) { @@ -188,18 +227,112 @@ class InvenTreePOLineItem extends InvenTreeModel { } } - double get purchasePrice => double.parse((jsondata["purchase_price"] ?? "") as String); + InvenTreePurchaseOrder? get purchaseOrder { + dynamic detail = jsondata["order_detail"]; - String get purchasePriceCurrency => (jsondata["purchase_price_currency"] ?? "") as String; + if (detail == null) { + return null; + } else { + return InvenTreePurchaseOrder.fromJson(detail as Map); + } + } - String get purchasePriceString => (jsondata["purchase_price_string"] ?? "") as String; + String get SKU => getString("SKU", subKey: "supplier_part_detail"); - int get destination => (jsondata["destination"] ?? -1) as int; + double get purchasePrice => getDouble("purchase_price"); - Map get destinationDetail => (jsondata["destination_detail"] ?? {}) as Map; + String get purchasePriceCurrency => getString("purchase_price_currency"); - @override - InvenTreeModel createFromJson(Map json) { - return InvenTreePOLineItem.fromJson(json); + int get destinationId => getInt("destination"); + + 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(); + } + }, + ); + } + } +} + +class InvenTreePOExtraLineItem extends InvenTreeExtraLineItem { + InvenTreePOExtraLineItem() : super(); + + InvenTreePOExtraLineItem.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => + InvenTreePOExtraLineItem.fromJson(json); + + @override + String get URL => "order/po-extra-line/"; + + @override + List get rolesRequired => ["purchase_order"]; + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => ExtraLineDetailWidget(this)), + ); } } diff --git a/lib/inventree/sales_order.dart b/lib/inventree/sales_order.dart new file mode 100644 index 0000000..82cc074 --- /dev/null +++ b/lib/inventree/sales_order.dart @@ -0,0 +1,430 @@ +import "package:flutter/material.dart"; +import "package:inventree/api.dart"; +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"; + +/* + * 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/"; + + static const String MODEL_TYPE = "salesorder"; + + @override + List get rolesRequired => ["sales_order"]; + + String get allocate_url => "${url}allocate/"; + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => SalesOrderDetailWidget(this)), + ); + } + + @override + Map> formFields() { + Map> fields = { + "reference": {}, + "customer": { + "filters": {"is_customer": true, "active": true}, + }, + "customer_reference": {}, + "description": {}, + "project_code": {}, + "start_date": {}, + "target_date": {}, + "link": {}, + "responsible": {}, + "contact": { + "filters": {"company": customerId}, + }, + }; + + if (!InvenTreeAPI().supportsProjectCodes) { + fields.remove("project_code"); + } + + if (!InvenTreeAPI().supportsContactModel) { + fields.remove("contact"); + } + + if (!InvenTreeAPI().supportsStartDate) { + fields.remove("start_date"); + } + + return fields; + } + + @override + Map defaultFilters() { + return {"customer_detail": "true"}; + } + + Future issueOrder() async { + if (!isPending) { + return; + } + + showLoadingOverlay(); + await api.post("${url}issue/", expectedStatusCode: 201); + hideLoadingOverlay(); + } + + /// Mark this order as "cancelled" + Future cancelOrder() async { + if (!isOpen) { + return; + } + + showLoadingOverlay(); + await api.post("${url}cancel/", expectedStatusCode: 201); + hideLoadingOverlay(); + } + + 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", + "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"]); +} + +/* + * 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": { + "filters": {"salable": true}, + }, + "quantity": {}, + "reference": {}, + "notes": {}, + "link": {}, + }; + } + + 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 defaultFilters() { + return {"part_detail": "true"}; + } + + double get allocated => getDouble("allocated"); + + 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; + } + + 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 InvenTreeSOExtraLineItem extends InvenTreeExtraLineItem { + InvenTreeSOExtraLineItem() : super(); + + InvenTreeSOExtraLineItem.fromJson(Map json) + : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) => + InvenTreeSOExtraLineItem.fromJson(json); + + @override + String get URL => "order/so-extra-line/"; + + @override + List get rolesRequired => ["sales_order"]; + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => ExtraLineDetailWidget(this)), + ); + } +} + +/* + * 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/"; + + 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 + Map> formFields() { + Map> fields = { + "order": {}, + "reference": {}, + "tracking_number": {}, + "invoice_number": {}, + "link": {}, + }; + + 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"); + + String get invoice_number => getString("invoice_number"); + + String? get shipment_date => getString("shipment_date"); + + 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 InvenTreeModel { + 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, + ); + } + } +} diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 79a8ea5..132974a 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,14 +1,16 @@ import "dart:io"; import "package:device_info_plus/device_info_plus.dart"; -import "package:inventree/app_settings.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"; import "package:inventree/api.dart"; +import "package:inventree/dsn.dart"; +import "package:inventree/preferences.dart"; Future> getDeviceInfo() async { - // Extract device information final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); @@ -28,7 +30,6 @@ Future> getDeviceInfo() async { "identifierForVendor": iosDeviceInfo.identifierForVendor, "isPhysicalDevice": iosDeviceInfo.isPhysicalDevice, }; - } else if (Platform.isAndroid) { final androidDeviceInfo = await deviceInfo.androidInfo; @@ -37,13 +38,13 @@ 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, "manufacturer": androidDeviceInfo.manufacturer, "product": androidDeviceInfo.product, - "version": androidDeviceInfo.version.release, + "systemVersion": androidDeviceInfo.version.release, "supported32BitAbis": androidDeviceInfo.supported32BitAbis, "supported64BitAbis": androidDeviceInfo.supported64BitAbis, "supportedAbis": androidDeviceInfo.supportedAbis, @@ -54,12 +55,11 @@ Future> getDeviceInfo() async { return device_info; } - Map getServerInfo() => { - "version": InvenTreeAPI().version, + "version": InvenTreeAPI().serverVersion, + "apiVersion": InvenTreeAPI().apiVersion, }; - Future> getAppInfo() async { // Add app info final package_info = await PackageInfo.fromPlatform(); @@ -72,7 +72,6 @@ Future> getAppInfo() async { }; } - bool isInDebugMode() { bool inDebugMode = false; @@ -81,7 +80,13 @@ 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; + } final server_info = getServerInfo(); final app_info = await getAppInfo(); @@ -98,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 -----"); @@ -122,13 +126,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.setContexts("stacktrace", StackTrace.current.toString()); }); try { @@ -141,8 +148,19 @@ Future sentryReportMessage(String message, {Map? context}) } } - -Future sentryReportError(dynamic error, dynamic stackTrace) async { +/* + * Report an error message to sentry.io + */ +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); @@ -151,32 +169,85 @@ Future sentryReportError(dynamic error, dynamic stackTrace) async { // 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; } - final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; + if (SENTRY_DSN_KEY.isEmpty) { + return; + } + + final upload = + await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) + as bool; if (!upload) { print("----- Error reporting disabled -----"); return; } + // 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/")) { + return; + } + + // Local file system exception + if (errorString.contains("FileSystemException")) { + return; + } + } + final server_info = getServerInfo(); final app_info = await getAppInfo(); final device_info = await getDeviceInfo(); + // Ensure we pass the 'source' of the error + context["source"] = source; + + if (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); - scope.setExtra("device", device_info); + 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) { - print("Error uploading information to Sentry.io:"); - print(error); - }).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")) { + return true; + } + } + + return false; } diff --git a/lib/inventree/status_codes.dart b/lib/inventree/status_codes.dart new file mode 100644 index 0000000..0058fc8 --- /dev/null +++ b/lib/inventree/status_codes.dart @@ -0,0 +1,145 @@ +/* + * 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/app_colors.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 = {}; + + /* + * 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 { + // 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 '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); + + String color_name = (_entry["color"] ?? "") as String; + + switch (color_name.toLowerCase()) { + case "success": + return COLOR_SUCCESS; + case "primary": + return COLOR_PROGRESS; + case "secondary": + return Colors.grey; + case "dark": + return Colors.black; + case "danger": + return COLOR_DANGER; + case "warning": + return COLOR_WARNING; + case "info": + return Colors.lightBlue; + default: + return Colors.black; + } + } +} diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 45808d2..657a218 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -1,182 +1,183 @@ import "dart:async"; import "package:flutter/material.dart"; -import "package:intl/intl.dart"; +import "package:inventree/api.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/inventree/part.dart"; +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/"; @override - Map formFields() { - return { - "stock_item": { - "hidden": true - }, + List get rolesRequired => ["stock"]; + + @override + 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 => (jsondata["key"] ?? "") as String; + String get key => getString("key"); - String get testName => (jsondata["test"] ?? "") as String; + int get templateId => getInt("template"); - bool get result => (jsondata["result"] ?? false) as bool; + String get testName => getString("test"); - String get value => (jsondata["value"] ?? "") as String; + bool get result => getBool("result"); - String get attachment => (jsondata["attachment"] ?? "") as String; + String get value => getString("value"); - String get date => (jsondata["date"] ?? "") as String; + 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) { - return InvenTreeStockItemHistory.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => + InvenTreeStockItemHistory.fromJson(json); @override String get URL => "stock/track/"; @override - Map defaultListFilters() { - + Map defaultFilters() { // By default, order by decreasing date - return { - "ordering": "-date", - }; + return {"ordering": "-date", "user_detail": "true"}; } - 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; + String get dateString => getDateString("date"); - if (d == null) { - return ""; - } + String get label => getString("label"); - return DateFormat("yyyy-MM-dd").format(d); - } - - String get label => (jsondata["label"] ?? "") as String; + // Return the "deltas" associated with this historical object + Map get deltas => getMap("deltas"); + // Return the quantity string for this historical object String get quantityString { - Map deltas = (jsondata["deltas"] ?? {}) as Map; + var _deltas = deltas; - // 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; + if (_deltas.containsKey("quantity")) { + double q = double.tryParse(_deltas["quantity"].toString()) ?? 0; return simpleNumberString(q); } else { return ""; } } + + int? get user => getValue("user") as int?; + + String get userString { + if (user != null) { + return getString("username", subKey: "user_detail"); + } else { + return ""; + } + } } - +/* + * Class representing a StockItem database instance + */ class InvenTreeStockItem extends InvenTreeModel { - InvenTreeStockItem() : super(); 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 RETURNED = 85; - - String statusLabel(BuildContext context) { - - // TODO: Delete me - The translated status values are 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 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 LOST: - default: - return Color(0xFFAAAAAA); - } - } - @override String get URL => "stock/"; - // URLs for performing stock actions + static const String MODEL_TYPE = "stockitem"; + @override + List get rolesRequired => ["stock"]; + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + 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}, + "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/"; static String countStockUrl() => "stock/count/"; @@ -189,38 +190,32 @@ class InvenTreeStockItem extends InvenTreeModel { String get WEB_URL => "stock/item/"; @override - Map formFields() { - return { + Map> formFields() { + Map> fields = { "part": {}, "location": {}, "quantity": {}, + "serial": {}, + "serial_numbers": {"label": L10().serialNumbers, "type": "string"}, "status": {}, "batch": {}, + "purchase_price": {}, + "purchase_price_currency": {}, "packaging": {}, "link": {}, }; + + return fields; } @override - Map defaultGetFilters() { - - return { - "part_detail": "true", - "location_detail": "true", - "supplier_detail": "true", - "cascade": "false" - }; - } - - @override - Map defaultListFilters() { - + Map defaultFilters() { return { "part_detail": "true", "location_detail": "true", "supplier_detail": "true", + "supplier_part_detail": "true", "cascade": "false", - "in_stock": "true", }; } @@ -229,20 +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}", - }, - ).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 = []; @@ -250,101 +243,86 @@ 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); + } + } + }); } - String get uid => (jsondata["uid"] ?? "") as String; + bool get isInStock => getBool("in_stock", backup: true); - int get status => (jsondata["status"] ?? -1) as int; + 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 => getInt("part"); - int get partId => (jsondata["part"] ?? -1) as int; - - String get purchasePrice => (jsondata["purchase_price"] ?? "") as String; + double? get purchasePrice { + String pp = getString("purchase_price"); + + if (pp.isEmpty) { + return null; + } else { + return double.tryParse(pp); + } + } + + String get purchasePriceCurrency => getString("purchase_price_currency"); 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; + int get purchaseOrderId => getInt("purchase_order"); - int get trackingItemCount => (jsondata["tracking_items"] ?? 0) as int; + int get trackingItemCount => getInt("tracking_items", backup: 0); - bool get isBuilding => (jsondata["is_building"] ?? false) as bool; + bool get isBuilding => getBool("is_building"); + + int get salesOrderId => getInt("sales_order"); + + bool get hasSalesOrder => salesOrderId > 0; + + int get customerId => getInt("customer"); + + 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 { - String nm = ""; // 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 if (nm.isEmpty) { - nm = (jsondata["part__name"] ?? "") as String; + nm = getString("part__name"); } return nm; @@ -355,11 +333,11 @@ 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) { - desc = (jsondata["part__description"] ?? "") as String; + desc = getString("part__description"); } return desc; @@ -369,11 +347,11 @@ 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) { - img = (jsondata["part__thumbnail"] ?? "") as String; + img = getString("part__thumbnail"); } return img; @@ -383,7 +361,6 @@ class InvenTreeStockItem extends InvenTreeModel { * Return the Part thumbnail for this stock item. */ String get partThumbnail { - String thumb = ""; thumb = (jsondata["part_detail"]?["thumbnail"] ?? "") as String; @@ -395,7 +372,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 @@ -404,49 +381,42 @@ 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 = ""; - if (jsondata.containsKey("supplier_detail")) { - thumb = (jsondata["supplier_detail"]["supplier_logo"] ?? "") as String; + 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; } - 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"); + + String get supplierSKU => getString("SKU", subKey: "supplier_part_detail"); + + String get serialNumber => getString("serial"); + + double get quantity => getDouble("quantity"); + + String quantityString({bool includeUnits = true}) { + String q = ""; + + if (allocated > 0) { + q += simpleNumberString(available); + q += " / "; } - return sname; - } - - String get units { - return (jsondata["part_detail"]?["units"] ?? "") as String; - } - - String get supplierSKU { - String sku = ""; - - if (jsondata.containsKey("supplier_detail")) { - sku = (jsondata["supplier_detail"]["SKU"] ?? "") as String; - } - - return sku; - } - - String get serialNumber => (jsondata["serial"] ?? "") as String; - - double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; - - String quantityString({bool includeUnits = false}){ - - String q = simpleNumberString(quantity); + q += simpleNumberString(quantity); if (includeUnits && units.isNotEmpty) { q += " ${units}"; @@ -455,39 +425,45 @@ class InvenTreeStockItem extends InvenTreeModel { return q; } - int get locationId => (jsondata["location"] ?? -1) as int; + 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); } - - return simpleNumberString(quantity); } String get locationName { - String loc = ""; + if (locationId == -1 || !jsondata.containsKey("location_detail")) { + return "Unknown Location"; + } - 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; } 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 = getString("pathstring", subKey: "location_detail"); if (_loc.isNotEmpty) { return _loc; } else { @@ -501,14 +477,19 @@ 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; } } @override - InvenTreeModel createFromJson(Map json) { - return InvenTreeStockItem.fromJson(json); - } + InvenTreeModel createFromJson(Map json) => + InvenTreeStockItem.fromJson(json); /* * Perform stocktake action: @@ -517,9 +498,12 @@ 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 { - + 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; @@ -532,72 +516,46 @@ class InvenTreeStockItem extends InvenTreeModel { Map data = {}; - // Note: Format of adjustment API was updated in API v14 - if (InvenTreeAPI().supportModernStockTransactions()) { - // Modern (> 14) API - data = { - "items": [ - { - "pk": "${pk}", - "quantity": "${quantity}", - } - ], - }; - } else { - // Legacy (<= 14) API - data = { - "item": { - "pk": "${pk}", - "quantity": "${quantity}", - }, - }; - } - - data["notes"] = notes ?? ""; + data = { + "items": [ + {"pk": "${pk}", "quantity": "${quantity}"}, + ], + "notes": notes ?? "", + }; if (location != null) { data["location"] = location; } - // Expected API return code depends on server API version - final int expected_response = InvenTreeAPI().supportModernStockTransactions() ? 201 : 200; + var response = await api.post(endpoint, body: data); - var response = await api.post( - endpoint, - body: data, - expectedStatusCode: expected_response, - ); - - return response.isValid(); + return response.isValid() && + (response.statusCode == 200 || response.statusCode == 201); } - // 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); + Future countStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/count/", q, notes: notes); 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); + Future addStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/add/", q, notes: notes); 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); + Future removeStock(double q, {String? notes}) async { + final bool result = await adjustStock("/stock/remove/", q, notes: notes); 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 { - + Future transferStock( + int location, { + double? quantity, + String? notes, + }) async { double q = this.quantity; if (quantity != null) { @@ -605,7 +563,6 @@ class InvenTreeStockItem extends InvenTreeModel { } final bool result = await adjustStock( - context, "/stock/transfer/", q, notes: notes, @@ -616,29 +573,43 @@ class InvenTreeStockItem extends InvenTreeModel { } } - 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/"; - String get pathstring => (jsondata["pathstring"] ?? "") as String; + static const String MODEL_TYPE = "stocklocation"; @override - Map formFields() { - return { + List get rolesRequired => ["stock"]; + + String get pathstring => getString("pathstring"); + + @override + Future goToDetailPage(BuildContext context) async { + return Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(this)), + ); + } + + @override + Map> formFields() { + Map> fields = { "name": {}, "description": {}, "parent": {}, + "structural": {}, }; + + return fields; } - String get parentpathstring { - // TODO - Drive the refactor tractor through this + String get parentPathString { List psplit = pathstring.split("/"); if (psplit.isNotEmpty) { @@ -657,10 +628,6 @@ class InvenTreeStockLocation extends InvenTreeModel { int get itemcount => (jsondata["items"] ?? 0) as int; @override - InvenTreeModel createFromJson(Map json) { - - var loc = InvenTreeStockLocation.fromJson(json); - - return loc; - } -} \ No newline at end of file + InvenTreeModel createFromJson(Map json) => + InvenTreeStockLocation.fromJson(json); +} diff --git a/lib/l10.dart b/lib/l10.dart index ce9f319..4b58a93 100644 --- a/lib/l10.dart +++ b/lib/l10.dart @@ -1,12 +1,18 @@ -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"; +import "package:inventree/helpers.dart"; + // Shortcut function to reduce boilerplate! -I18N L10() -{ +I18N L10() { + // Testing mode - ignore context + if (!hasContext()) { + return I18NEn(); + } + BuildContext? _ctx = OneContext().context; if (_ctx != null) { @@ -18,5 +24,5 @@ I18N L10() } // Fallback for "null" context - return I18NEn(); -} \ No newline at end of file + return I18NEn(); +} 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 diff --git a/lib/l10n/.gitignore b/lib/l10n/.gitignore new file mode 100644 index 0000000..d0e30b8 --- /dev/null +++ b/lib/l10n/.gitignore @@ -0,0 +1,3 @@ +# Do not track the collected translation files +collected/ +supported_locales.dart 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!) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..4f6560f --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,1793 @@ +{ + "@@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": {}, + + "allocated": "Allocated", + "@allocated": {}, + + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + + "appSettings": "App Settings", + "@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", + "@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 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": {}, + + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + + "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": {}, + + "companyAdd": "Add Company", + "@companyAdd": {}, + + "companyEdit": "Edit Company", + "@companyEdit": {}, + + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + + "companies": "Companies", + "@companies": {}, + + "complete": "Complete", + "@complete": {}, + + "completeOrder": "Complete Order", + "@completeOrder": {}, + + "completionDate": "Completion Date", + "@completionDate": {}, + + "configureServer": "Configure server settings", + "@configureServer": {}, + + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + + "count": "Count", + "@count": { + "description": "Count" + }, + + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + + "credits": "Credits", + "@credits": {}, + + "crop": "Crop", + "@crop": {}, + + "cropImage": "Crop Image", + "@cropImage": {}, + + "customer": "Customer", + "@customer": {}, + + "customers": "Customers", + "@customers": {}, + + "customerReference": "Customer Reference", + "@customerReference": {}, + + "damaged": "Damaged", + "@damaged": {}, + + "colorScheme": "Color Scheme", + "@colorScheme": {}, + + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + + "darkMode": "Dark Mode", + "@darkMode": {}, + + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + + "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": { + "description": "details" + }, + + "documentation": "Documentation", + "@documentation": {}, + + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + + "downloadError": "Error downloading image", + "@downloadError": {}, + + "downloading": "Downloading File", + "@downloading": {}, + + "edit": "Edit", + "@edit": { + "description": "edit" + }, + + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + + "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": {}, + + "email": "Email", + "@email": {}, + + "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": {}, + + "expiryDate": "Expiry Date", + "@expiryDate": {}, + + "expiryExpired": "Expired", + "@expiryExpired": {}, + + "expiryStale": "Stale", + "@expiryStale": {}, + + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + + "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", + "@home": {}, + + "homeScreen": "Home Screen", + "@homeScreen": {}, + + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + + "invoice": "Invoice", + "@invoice": {}, + + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + + "issue": "Issue", + "@issue": {}, + + "issueDate": "Issue Date", + "@issueDate": {}, + + "issueOrder": "Issue Order", + "@issueOrder": {}, + + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + + "itemUpdated": "Item updated", + "@itemUpdated": {}, + + "keywords": "Keywords", + "@keywords": {}, + + "labelDriver": "Label Driver", + "@labelDriver": {}, + + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + + "labelTemplate": "Label Template", + "@labelTemplate": {}, + + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + + "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": {}, + + "locationDefault": "Default Location", + "@locationDefault": {}, + + "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": {}, + + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + + "manufacturer": "Manufacturer", + "@manufacturer": {}, + + "manufacturers": "Manufacturers", + "@manufacturers": {}, + + "missingData": "Missing Data", + "@missingData": {}, + + "name": "Name", + "@name": { + }, + + "no": "No", + "@no": {}, + + "notApplicable": "N/A", + "@notApplicable": {}, + + "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": {}, + + "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", + "@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": {}, + + "partPricing": "Part Pricing", + "@partPricing": {}, + + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + + "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": {}, + + "path": "Path", + "@path": {}, + + "pending": "Pending", + "@pending": {}, + + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + + "phone": "Phone", + "@phone": {}, + + "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": {}, + + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + + "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", + "@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": {}, + + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + + "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": {}, + + "responsible": "Responsible", + "@responsible": {}, + + "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": {}, + + "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", + "@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": {}, + + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + + "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": {}, + + "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", + "@sku": {}, + + "sounds": "Sounds", + "@sounds": {}, + + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + + "startDate": "Start Date", + "@startDate": {}, + + "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": {}, + + "switchCamera": "Switch Camera", + "@switchCamera": {}, + + "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": "" + }, + + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + + "tokenError": "Token Error", + "@tokenError": {}, + + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + + "totalPrice": "Total Price", + "@totalPrice": {}, + + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + + "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": {}, + + "unavailable": "Unavailable", + "@unavailable": {}, + + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + + "unitPrice": "Unit Price", + "@unitPrice": {}, + + "units": "Units", + "@units": {}, + + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + + "upload": "Upload", + "@upload": {}, + + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + + "uploadImage": "Upload Image", + "@uploadImage": {}, + + "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": {}, + + "yes": "Yes", + "@yes": {}, + + "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": {} +} 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..af1cb2a --- /dev/null +++ b/lib/l10n/ar_SA/app_ar_SA.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "ar", + "appTitle": "", + "@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": {}, + "allocated": "Allocated", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No attachments found", + "@attachmentNone": {}, + "attachmentNoneDetail": "No attachments found", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Select attachment", + "@attachmentSelect": {}, + "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": "", + "@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 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": "تم فحصها في الموقع", + "@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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "Edit Category", + "@editCategory": {}, + "editLocation": "Edit Location", + "@editLocation": {}, + "editNotes": "Edit Notes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "تعديل المنتج", + "@editPart": { + "description": "edit part" + }, + "editItem": "", + "@editItem": {}, + "editLineItem": "", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "أدخل كلمة المرور", + "@enterPassword": {}, + "enterUsername": "Enter username", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error creating database entry", + "@errorCreate": {}, + "errorDelete": "", + "@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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..0a11bd2 --- /dev/null +++ b/lib/l10n/bg_BG/app_bg_BG.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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..d47bd65 --- /dev/null +++ b/lib/l10n/collect_translations.py @@ -0,0 +1,154 @@ +""" +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 glob +from posixpath import dirname +import shutil +import re + + +def process_locale_file(filename, locale_name): + """ + Process a locale file after copying + + - Ensure the 'locale' matches + """ + + # 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_name}"' + + 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}'") + + 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) + + +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("// dart format off\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("."): + continue + + splt = locale.split("_") + + if len(splt) == 2: + lc, cc = splt + else: + lc = locale + cc = "" + + output.write( + f' Locale("{lc}", "{cc}"), // Translations available 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) + + # Remove existing .arb files from output directory + arbs = glob.glob(os.path.join(output_dir, "*.arb")) + + for arb in arbs: + os.remove(arb) + + locales = ["en"] + + for locale in os.listdir(here): + # Ignore the output directory + if locale == "collected": + continue + + f = os.path.join(here, locale) + + 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 + src = os.path.join(here, "app_en.arb") + 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/l10n/cs_CZ/app_cs_CZ.arb b/lib/l10n/cs_CZ/app_cs_CZ.arb new file mode 100644 index 0000000..37150c8 --- /dev/null +++ b/lib/l10n/cs_CZ/app_cs_CZ.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "cs", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "O aplikaci", + "@about": {}, + "accountDetails": "Podrobnosti účtu", + "@accountDetails": {}, + "actions": "Akce", + "@actions": { + "description": "" + }, + "actionsNone": "Nejsou dostupné žádné akce", + "@actionsNone": {}, + "add": "Přidat", + "@add": { + "description": "add" + }, + "addStock": "Přidat do skladu", + "@addStock": { + "description": "add stock" + }, + "address": "Adresa", + "@address": {}, + "appAbout": "O InvenTree", + "@appAbout": {}, + "appCredits": "Poděkování dalším stranám", + "@appCredits": {}, + "appDetails": "Informace o aplikaci", + "@appDetails": {}, + "allocated": "Přiděleno", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Čtverec (1:1)", + "@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", + "@appSettings": {}, + "appSettingsDetails": "Konfigurovat nastavení aplikace InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Přiřazeno mně", + "@assignedToMe": {}, + "assignedToMeDetail": "Zobrazit objednávky, které jsou mi přiděleny", + "@assignedToMeDetail": {}, + "attachments": "Přílohy", + "@attachments": {}, + "attachImage": "Připojit obrázek", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Žádná příloha nenalezena", + "@attachmentNone": {}, + "attachmentNoneDetail": "Žádná příloha nenalezena", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Vybrat přílohu", + "@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", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Čárový kód přiřazen", + "@barcodeAssigned": {}, + "barcodeError": "Chyba při skenování čárového kódu", + "@barcodeError": {}, + "barcodeInUse": "Čárový kód je již přiřazen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Z odpovědi chybí hash data čárového kódu", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Žádný odpovídající čárový kód", + "@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", + "@barodeScanPaused": {}, + "barcodeScanPause": "Kliknutím pozastavíte skenování", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Skenovat pro přiřazení čárového kódu", + "@barcodeScanAssign": {}, + "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", + "@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", + "@batchCode": {}, + "billOfMaterials": "Kusovník", + "@billOfMaterials": {}, + "bom": "Kusovník", + "@bom": {}, + "bomEnable": "Zobrazit kusovník", + "@bomEnable": {}, + "build": "Sestava", + "@build": {}, + "building": "Sestavení", + "@building": {}, + "cameraCreationError": "Nelze otevřít ovladač kamery", + "@cameraCreationError": {}, + "cameraInternal": "Interní kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Použít interní kameru pro čtení čárových kódů", + "@cameraInternalDetail": {}, + "cancel": "Zrušit", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Zrušit objednávku", + "@cancelOrder": {}, + "category": "Kategorie", + "@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": {}, + "companyAdd": "Přidat firmu", + "@companyAdd": {}, + "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": {}, + "complete": "Dokončit", + "@complete": {}, + "completeOrder": "Dokončit objednávku", + "@completeOrder": {}, + "completionDate": "Datum dokončení", + "@completionDate": {}, + "configureServer": "Konfigurace nastavení serveru", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Počet zásob", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Poděkování", + "@credits": {}, + "crop": "Oříznout", + "@crop": {}, + "cropImage": "Oříznout obrázek", + "@cropImage": {}, + "customer": "Zákazník", + "@customer": {}, + "customers": "Zákazníci", + "@customers": {}, + "customerReference": "Číslo objednávky", + "@customerReference": {}, + "damaged": "Poškozeno", + "@damaged": {}, + "colorScheme": "Barevné schéma", + "@colorScheme": {}, + "colorSchemeDetail": "Vybrat barevné schéma", + "@colorSchemeDetail": {}, + "darkMode": "Tmavý motiv", + "@darkMode": {}, + "darkModeEnable": "Nastaví tmavý motiv aplikace", + "@darkModeEnable": {}, + "delete": "Odstranit", + "@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í", + "@destination": {}, + "destroyed": "Zničeno", + "@destroyed": {}, + "details": "Detaily", + "@details": { + "description": "details" + }, + "documentation": "Dokumentace", + "@documentation": {}, + "downloadComplete": "Stahování dokončeno", + "@downloadComplete": {}, + "downloadError": "Chyba při stahování obrázku", + "@downloadError": {}, + "downloading": "Stahování souboru", + "@downloading": {}, + "edit": "Upravit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Upravit přílohu", + "@editAttachment": {}, + "editCategory": "Upravit kategorii", + "@editCategory": {}, + "editLocation": "Upravit umístění", + "@editLocation": {}, + "editNotes": "Upravit poznámky", + "@editNotes": {}, + "editParameter": "Upravit parametr", + "@editParameter": {}, + "editPart": "Upravit díl", + "@editPart": { + "description": "edit part" + }, + "editItem": "Upravit skladovou položku", + "@editItem": {}, + "editLineItem": "Upravit položku", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "enterPassword": "Zadejte heslo", + "@enterPassword": {}, + "enterUsername": "Zadejte uživatelské jméno", + "@enterUsername": {}, + "error": "Chyba", + "@error": { + "description": "Error" + }, + "errorCreate": "Chyba při vytváření záznamu databáze", + "@errorCreate": {}, + "errorDelete": "Chyba při odstraňování záznamu databáze", + "@errorDelete": {}, + "errorDetails": "Podrobnosti o chybě", + "@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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Nahrát anonymní chybová hlášení a protokoly chyb", + "@errorReportUploadDetails": {}, + "expiryDate": "Datum expirace", + "@expiryDate": {}, + "expiryExpired": "Expirováno", + "@expiryExpired": {}, + "expiryStale": "Zastaralé", + "@expiryStale": {}, + "extraLineItem": "Položka navíc", + "@extraLineItem": {}, + "extraLineItems": "Položky navíc", + "@extraLineItems": {}, + "feedback": "Komentář", + "@feedback": {}, + "feedbackError": "Chyba při odesílání komentáře", + "@feedbackError": {}, + "feedbackSuccess": "Komentář odeslán", + "@feedbackSuccess": {}, + "filterActive": "Aktivní", + "@filterActive": {}, + "filterActiveDetail": "Zobrazit aktivní díly", + "@filterActiveDetail": {}, + "filterAssembly": "Sestavené", + "@filterAssembly": {}, + "filterAssemblyDetail": "Zobrazit smontované díly", + "@filterAssemblyDetail": {}, + "filterComponent": "Součást", + "@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", + "@filterInStockDetail": {}, + "filterSerialized": "Serializované", + "@filterSerialized": {}, + "filterSerializedDetail": "Zobrazit serializované položky skladem", + "@filterSerializedDetail": {}, + "filterTemplate": "Šablona", + "@filterTemplate": {}, + "filterTemplateDetail": "Zobrazit šablony dílů", + "@filterTemplateDetail": {}, + "filterTrackable": "Sledovatelný", + "@filterTrackable": {}, + "filterTrackableDetail": "Zobrazit sledovatelné díly", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuální", + "@filterVirtual": {}, + "filterVirtualDetail": "Zobrazit virtuální díly", + "@filterVirtualDetail": {}, + "filteringOptions": "Možnosti filtrování", + "@filteringOptions": {}, + "formatException": "Výjimka formátování", + "@formatException": {}, + "formatExceptionJson": "Výjimka datového formátu JSON", + "@formatExceptionJson": {}, + "formError": "Chyba formuláře", + "@formError": {}, + "history": "Historie", + "@history": { + "description": "history" + }, + "home": "Domů", + "@home": {}, + "homeScreen": "Domovská obrazovka", + "@homeScreen": {}, + "homeScreenSettings": "Konfigurace nastavení domovské obrazovky", + "@homeScreenSettings": {}, + "homeShowPo": "Zobrazit objednávky", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Odebírané díly", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Zobrazit odebírané díly na domovské obrazovce", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Zobrazit dodavatele", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Zobrazit tlačítko dodavatele na domovské obrazovce", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Zobrazit výrobce", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Zobrazit tlačítko výrobců na domovské obrazovce", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Zobrazit zákazníky", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Zobrazit tlačítko zákazníků na domovské obrazovce", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Nahrání obrázku se nezdařilo", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Obrázek byl nahrán", + "@imageUploadSuccess": {}, + "inactive": "Neaktivní", + "@inactive": {}, + "inactiveCompany": "Tato společnost je označena jako neaktivní", + "@inactiveCompany": {}, + "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": {}, + "internalPart": "Vnitřní součást", + "@internalPart": {}, + "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": {}, + "invoice": "Faktura", + "@invoice": {}, + "invoiceNumber": "Číslo faktury", + "@invoiceNumber": {}, + "issue": "Vystavit", + "@issue": {}, + "issueDate": "Datum nahlášení", + "@issueDate": {}, + "issueOrder": "Vystav objednávku", + "@issueOrder": {}, + "itemInLocation": "Položka je již umístěna", + "@itemInLocation": {}, + "itemDeleted": "Položka byla odebrána", + "@itemDeleted": {}, + "itemUpdated": "Položka byla aktualizována", + "@itemUpdated": {}, + "keywords": "Klíčová slova", + "@keywords": {}, + "labelDriver": "Ovladač pro popisky", + "@labelDriver": {}, + "labelSelectDriver": "Vyberte ovladač pro tiskárnu štítků", + "@labelSelectDriver": {}, + "labelPrinting": "Tisk štítku", + "@labelPrinting": {}, + "labelPrintingDetail": "Povolit tisk štítku", + "@labelPrintingDetail": {}, + "labelTemplate": "Šablona štítku", + "@labelTemplate": {}, + "labelSelectTemplate": "Vybrat šablonu popisku", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Vyberte tiskárnu popisků", + "@labelSelectPrinter": {}, + "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": {}, + "lineItemAdd": "Přidat položku", + "@lineItemAdd": {}, + "lineItem": "Řádek položky", + "@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í", + "@locateLocation": {}, + "locationCreate": "Nové umístění", + "@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", + "@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", + "@lost": {}, + "manufacturerPart": "Díl výrobce", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Editovat díl výrobce", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Číslo dílu výrobce", + "@manufacturerPartNumber": {}, + "manufacturer": "Výrobce", + "@manufacturer": {}, + "manufacturers": "Výrobci", + "@manufacturers": {}, + "missingData": "Chybějící data", + "@missingData": {}, + "name": "Jméno", + "@name": {}, + "no": "Ne", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Neplatné číslo", + "@numberInvalid": {}, + "onOrder": "Na objednávku", + "@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", + "@packageName": {}, + "parameters": "Parametry", + "@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)" + }, + "partCreate": "Nový díl", + "@partCreate": {}, + "partCreateDetail": "Vytvořit nový díl v této kategorii", + "@partCreateDetail": {}, + "partEdited": "Díl byl aktualizován", + "@partEdited": {}, + "parts": "Díly", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Část není označena jako prodejná", + "@partNotSalable": {}, + "partsNone": "Žádné díly", + "@partsNone": {}, + "partNoResults": "Žádné díly neodpovídají dotazu", + "@partNoResults": {}, + "partPricing": "Cena dílu", + "@partPricing": {}, + "partPricingSettingDetail": "Zobrazit cenové informace dílu", + "@pricingSettingDetail": {}, + "partSettings": "Nastavení dílu", + "@partSettings": {}, + "partsStarred": "Odebírané díly", + "@partsStarred": {}, + "partsStarredNone": "Nejsou k dispozici žádné oblíbené díly", + "@partsStarredNone": {}, + "partSuppliers": "Dodavatelé dílů", + "@partSuppliers": {}, + "partCategory": "Kategorie dílu", + "@partCategory": {}, + "partCategoryTopLevel": "Kategorie dílu nejvyšší úrovně", + "@partCategoryTopLevel": {}, + "partCategories": "Kategorie dílu", + "@partCategories": {}, + "partDetails": "Podrobnosti dílu", + "@partDetails": {}, + "partNotes": "Poznámky dílu", + "@partNotes": {}, + "partStock": "Skladové zásoby", + "@partStock": { + "description": "part stock" + }, + "password": "Heslo", + "@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í", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "printLabel": "Tisk štítků", + "@printLabel": {}, + "plugin": "Zásuvný modul", + "@plugin": {}, + "pluginPrinter": "Tiskárna", + "@pluginPrinter": {}, + "pluginSupport": "Podpora zásuvných modulů povolena", + "@pluginSupport": {}, + "pluginSupportDetail": "Server podporuje vlastní zásuvné moduly", + "@pluginSupportDetail": {}, + "printLabelFailure": "Tisk štítku se nezdařil", + "@printLabelFailure": {}, + "printLabelSuccess": "Štítek odeslán do tiskárny", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Přidat profil serveru", + "@profileAdd": {}, + "profileConnect": "Připojit se k serveru", + "@profileConnect": {}, + "profileEdit": "Upravit profil serveru", + "@profileEdit": {}, + "profileDelete": "Odstranit profil serveru", + "@profileDelete": {}, + "profileLogout": "Odhlásit profil", + "@profileLogout": {}, + "profileName": "Název profilu", + "@profileName": {}, + "profileNone": "Žádné profily nejsou k dispozici", + "@profileNone": {}, + "profileNotSelected": "Nebyl zvolen žádný profil", + "@profileNotSelected": {}, + "profileSelect": "Vybrat InvenTree server", + "@profileSelect": {}, + "profileSelectOrCreate": "Vyberte server nebo vytvořte nový profil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Klepnutím vytvoříte nebo vyberte profil", + "@profileTapToCreate": {}, + "projectCode": "Kód projektu", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Potvrdit naskenování dat", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Potvrdit detaily při skenování položek", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Povolit nákupní objednávky", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Povolit funkce nákupní objednávky", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Zástupce kamery", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Povolit zástupce pro nahrání obrázků na obrazovce objednávky", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Objednávka", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nová objednávka", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Upravit objednávku", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Nastavení objednávky", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Objednávky", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Objednávka byla aktualizována", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Nákupní cena", + "@purchasePrice": {}, + "quantity": "Množství", + "@quantity": { + "description": "Quantity" + }, + "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": {}, + "queryEmpty": "Zadejte hledaný dotaz", + "@queryEmpty": {}, + "queryNoResults": "Žádné výsledky dotazu", + "@queryNoResults": {}, + "received": "Přijato", + "@received": {}, + "receivedFilterDetail": "Zobrazit přijaté položky", + "@receivedFilterDetail": {}, + "receiveItem": "Přijaté položky", + "@receiveItem": {}, + "receivedItem": "Přijatá skladová položka", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Obnovit", + "@refresh": {}, + "rotateClockwise": "Otočit o 90° po směru hodinových ručiček", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Odpovědný", + "@responsible": {}, + "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": {}, + "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", + "@result": { + "description": "" + }, + "returned": "Vráceno", + "@returned": {}, + "salesOrder": "Prodejní objednávka", + "@salesOrder": {}, + "salesOrders": "Prodejní objednávky", + "@salesOrders": {}, + "salesOrderEnable": "Povolit prodejní objednávky", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Povolit funkcionality prodejní objednávky", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Zástupce kamery", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Povolit zástupce pro nahrání obrázků na obrazovce objednávky", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "prodejní objednávka", + "@salesOrderSettings": {}, + "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" + }, + "scanBarcode": "Skenovat čarový kód", + "@scanBarcode": {}, + "scanSupplierPart": "Naskenovat čárový kód dílu dodavatele", + "@scanSupplierPart": {}, + "scanIntoLocation": "Skenovat umístění", + "@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" + }, + "searching": "Hledání", + "@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", + "@searchStock": {}, + "select": "Vybrat", + "@select": {}, + "selectFile": "Vyberte soubor", + "@selectFile": {}, + "selectImage": "Vybrat obrázek", + "@selectImage": {}, + "selectLocation": "Vybrat umístění", + "@selectLocation": {}, + "send": "Odeslat", + "@send": {}, + "serialNumber": "Sériové číslo", + "@serialNumber": {}, + "serialNumbers": "Sériová čísla", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Adresa serveru", + "@serverAddress": {}, + "serverApiRequired": "Požadovaná verze API", + "@serverApiRequired": {}, + "serverApiVersion": "Verze API serveru", + "@serverApiVersion": {}, + "serverAuthenticationError": "Chyba ověření", + "@serverAuthenticationError": {}, + "serverCertificateError": "Chyba certifikátu", + "@serverCertificateError": {}, + "serverCertificateInvalid": "HTTPS certifikát serveru je neplatný", + "@serverCertificateInvalid": {}, + "serverConnected": "Připojeno k serveru", + "@serverConnected": {}, + "serverConnecting": "Připojování k serveru", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nelze se připojit k serveru", + "@serverCouldNotConnect": {}, + "serverEmpty": "Název serveru nemůže být prázdný", + "@serverEmpty": {}, + "serverError": "Chyba serveru", + "@serverError": {}, + "serverDetails": "Podrobnosti o serveru", + "@serverDetails": {}, + "serverMissingData": "V odpovědi serveru chybí požadovaná pole", + "@serverMissingData": {}, + "serverOld": "Stará verze serveru", + "@serverOld": {}, + "serverSettings": "Nastavení serveru", + "@serverSettings": {}, + "serverStart": "Název serveru musí začínat s http[s]", + "@serverStart": {}, + "settings": "Nastavení", + "@settings": {}, + "serverInstance": "Instance serveru", + "@serverInstance": {}, + "serverNotConnected": "Server není připojen", + "@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)", + "@sku": {}, + "sounds": "Zvuky", + "@sounds": {}, + "soundOnBarcodeAction": "Přehrát zvuk při použití čárového kódu", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Přehrát zvuk při chybě serveru", + "@soundOnServerError": {}, + "startDate": "Počáteční datum", + "@startDate": {}, + "status": "Stav", + "@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": {}, + "stockItemHistoryDetail": "Zobrazit historické informace o sledování zásob", + "@stockItemHistoryDetail": {}, + "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": {}, + "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", + "@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": {}, + "supplierPartNumber": "Číslo dílu dodavatele", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Dodavatel dílu upraven", + "@supplierPartUpdated": {}, + "supplierParts": "Dodavatel dílů", + "@supplierParts": {}, + "suppliers": "Dodavatelé", + "@suppliers": {}, + "supplierReference": "Kód dodavatele", + "@supplierReference": {}, + "switchCamera": "Přepnout kameru", + "@switchCamera": {}, + "takePicture": "Pořídit snímek", + "@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", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Zobrazit výsledky testu skladových položek", + "@testResultsDetail": {}, + "testResultAdd": "Přidat výsledek testu", + "@testResultAdd": {}, + "testResultNone": "Žádné výsledky testu", + "@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", + "@timeout": { + "description": "" + }, + "toggleTorch": "Rozsvítit baterku", + "@toggleTorch": {}, + "tokenError": "Chyba tokenu", + "@tokenError": {}, + "tokenMissing": "Chybějící token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "V odpovědi chybí přístupový token", + "@tokenMissingFromResponse": {}, + "totalPrice": "Celková cena", + "@totalPrice": {}, + "trackingNumber": "Sledovací číslo", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Není k dispozici", + "@unavailable": {}, + "unavailableDetail": "Položka není k dispozici", + "@unavailableDetail": {}, + "unitPrice": "Jednotková cena", + "@unitPrice": {}, + "units": "Jednotky", + "@units": {}, + "unknownResponse": "Neznámá odpověď", + "@unknownResponse": {}, + "upload": "Nahrát", + "@upload": {}, + "uploadFailed": "Nepodařilo se nahrát soubor", + "@uploadFailed": {}, + "uploadSuccess": "Soubor nahrán", + "@uploadSuccess": {}, + "uploadImage": "Nahrát obrázek", + "@uploadImage": {}, + "usedIn": "Použito v", + "@usedIn": {}, + "usedInDetails": "Sestavy vyžadující tento díl", + "@usedInDetails": {}, + "username": "Uživatelské jméno", + "@username": {}, + "usernameEmpty": "Uživatelské jméno nesmí být prázdné", + "@usernameEmpty": {}, + "value": "Hodnota", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Hodnota nemůže být prázdná", + "@valueCannotBeEmpty": {}, + "valueRequired": "Hodnota je povinná", + "@valueRequired": {}, + "variants": "Varianty", + "@variants": {}, + "version": "Verze", + "@version": {}, + "viewSupplierPart": "Zobrazit díl dodavatele", + "@viewSupplierPart": {}, + "website": "Webová stránka", + "@website": {}, + "yes": "Ano", + "@yes": {}, + "price": "Cena", + "@price": {}, + "priceRange": "Cenový rozsah", + "@priceRange": {}, + "priceOverrideMin": "Přepsání minimální ceny", + "@priceOverrideMin": {}, + "priceOverrideMax": "Přepsání maximální ceny", + "@priceOverrideMax": {}, + "salePrice": "Prodejní cena", + "@salePrice": {}, + "saleHistory": "Historie prodeje", + "@saleHistory": {}, + "supplierPricing": "Cena dodavatele", + "@supplierPricing": {}, + "bomCost": "Náklady na BOM", + "@bomCost": {}, + "internalCost": "Interní cena", + "@internalCost": {}, + "variantCost": "Náklad varianty", + "@variantCost": {}, + "overallPricing": "Celková cena", + "@overallPricing": {}, + "pricingOverrides": "Cenový přehled", + "@pricingOverrides": {}, + "currency": "Měna", + "@currency": {}, + "priceBreaks": "Cena sleva", + "@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 new file mode 100644 index 0000000..c78e5e0 --- /dev/null +++ b/lib/l10n/da_DK/app_da_DK.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "da", + "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 tilgængelige", + "@actionsNone": {}, + "add": "Tilføj ", + "@add": { + "description": "add" + }, + "addStock": "Tilføj Lagerbeholdning", + "@addStock": { + "description": "add stock" + }, + "address": "Adresse", + "@address": {}, + "appAbout": "Om InvenTree", + "@appAbout": {}, + "appCredits": "Yderligere app kredit", + "@appCredits": {}, + "appDetails": "Oplysninger om appen", + "@appDetails": {}, + "allocated": "Tildelt", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Firkantet (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Tildel lager", + "@allocateStock": {}, + "allocatedStock": "Allokeret Lager", + "@allocatedStock": {}, + "appReleaseNotes": "Vis app-udgivelsesnoter", + "@appReleaseNotes": {}, + "appSettings": "Appindstillinger", + "@appSettings": {}, + "appSettingsDetails": "Konfigurer InvenTree app-indstillinger", + "@appSettingsDetails": {}, + "assignedToMe": "Tildelt til Mig", + "@assignedToMe": {}, + "assignedToMeDetail": "Vis ordrer som er tildelt mig", + "@assignedToMeDetail": {}, + "attachments": "Vedhæftede filer", + "@attachments": {}, + "attachImage": "Vedhæft billede", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Ingen vedhæftning fundet", + "@attachmentNone": {}, + "attachmentNoneDetail": "Ingen vedhæftning fundet", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Vælg vedhæftede filer", + "@attachmentSelect": {}, + "attention": "Bemærk", + "@attention": {}, + "available": "Tilgængelig", + "@available": {}, + "availableStock": "Tilgængelig Lager", + "@availableStock": {}, + "barcodes": "Stregkoder", + "@barcodes": {}, + "barcodeSettings": "Stregkode Indstillinger", + "@barcodeSettings": {}, + "barcodeAssign": "Tildel Stregkode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan brugerdefineret stregkode, der skal tildeles", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Stregkode tildelt", + "@barcodeAssigned": {}, + "barcodeError": "Fejl i stregkodeskanning", + "@barcodeError": {}, + "barcodeInUse": "Stregkode allerede tildelt", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data mangler fra respons", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Intet match for stregkode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Stregkode ikke tildelt", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Skan del stregkode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan stregkode for at modtage en del", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Stregkode skanning på pause", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tryk for at pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan for at tildele stregkode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Vælg stregkodeskanners indgangskilde", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Forsinkelse Af Stregkode", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Forsinkelse mellem stregkode scanninger", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan en InvenTree stregkode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan lagervare ind på denne lokation", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan lager lokation", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Enkelt Scan Tilstand", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Sæt stregkodeskanneren på pause efter hver scanning", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scannet ind i lokation", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Element er ikke scannet ind", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scan lagervare", + "@barcodeScanItem": {}, + "barcodeTones": "Stregkodetoner", + "@barcodeTones": {}, + "barcodeUnassign": "Frigiv Stregkode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Stregkode ikke genkendt", + "@barcodeUnknown": {}, + "batchCode": "Batch kode", + "@batchCode": {}, + "billOfMaterials": "Stykliste", + "@billOfMaterials": {}, + "bom": "Stykliste", + "@bom": {}, + "bomEnable": "Vis Stykliste", + "@bomEnable": {}, + "build": "Byg", + "@build": {}, + "building": "Bygger", + "@building": {}, + "cameraCreationError": "Kunne ikke åbne kameracontrolleren", + "@cameraCreationError": {}, + "cameraInternal": "Internt Kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Brug internt kamera til at læse stregkoder", + "@cameraInternalDetail": {}, + "cancel": "Annuller", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Annuller ordre", + "@cancelOrder": {}, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Ny kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Opret ny del kategori", + "@categoryCreateDetail": {}, + "categoryUpdated": "Del kategori opdateret", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyAdd": "Tilføj firma", + "@companyAdd": {}, + "companyEdit": "Rediger virksomhed", + "@companyEdit": {}, + "companyNoResults": "Ingen virksomheder, der matcher forespørgsel", + "@companyNoResults": {}, + "companyUpdated": "Virksomhedsoplysninger opdateret", + "@companyUpdated": {}, + "companies": "Firmaer", + "@companies": {}, + "complete": "Færdiggjort", + "@complete": {}, + "completeOrder": "Fuldfør ordre", + "@completeOrder": {}, + "completionDate": "Færdiggørelsesdato", + "@completionDate": {}, + "configureServer": "Konfigurer serverindstillinger", + "@configureServer": {}, + "confirmScan": "Bekræft overførsel", + "@confirmScan": {}, + "confirmScanDetail": "Bekræft lageroverførsel detaljer ved scanning stregkoder", + "@confirmScanDetail": {}, + "connectionRefused": "Forbindelse Afvist", + "@connectionRefused": {}, + "count": "Antal", + "@count": { + "description": "Count" + }, + "countStock": "Tæl Lager", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Anerkendelser", + "@credits": {}, + "crop": "Beskær", + "@crop": {}, + "cropImage": "Beskær billede", + "@cropImage": {}, + "customer": "Kunde", + "@customer": {}, + "customers": "Kunder", + "@customers": {}, + "customerReference": "Kundens Reference", + "@customerReference": {}, + "damaged": "Beskadiget", + "@damaged": {}, + "colorScheme": "Farveskema", + "@colorScheme": {}, + "colorSchemeDetail": "Vælg farveskema", + "@colorSchemeDetail": {}, + "darkMode": "Mørk tilstand", + "@darkMode": {}, + "darkModeEnable": "Aktiver mørk tilstand", + "@darkModeEnable": {}, + "delete": "Slet", + "@delete": {}, + "deleteFailed": "Sletning fejlede", + "@deleteFailed": {}, + "deleteImageConfirmation": "Er du sikker på at du vil slette dette billede?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Slet billede", + "@deleteImageTooltip": {}, + "deleteImage": "Slet billede", + "@deleteImage": {}, + "deletePart": "Slet Del", + "@deletePart": {}, + "deletePartDetail": "Fjern denne del fra databasen", + "@deletePartDetail": {}, + "deleteSuccess": "Sletning lykkedes", + "@deleteSuccess": {}, + "deliveryDate": "Leveringsdato", + "@deliveryDate": {}, + "description": "Beskrivelse", + "@description": {}, + "destination": "Destination", + "@destination": {}, + "destroyed": "Destrueret", + "@destroyed": {}, + "details": "Detaljer", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloadComplete": "Download fuldført", + "@downloadComplete": {}, + "downloadError": "Fejl ved download af billede", + "@downloadError": {}, + "downloading": "Overfører fil", + "@downloading": {}, + "edit": "Rediger", + "@edit": { + "description": "edit" + }, + "editAttachment": "Rediger Vedhæftning", + "@editAttachment": {}, + "editCategory": "Rediger kategori", + "@editCategory": {}, + "editLocation": "Redigér placering", + "@editLocation": {}, + "editNotes": "Redigér noter", + "@editNotes": {}, + "editParameter": "Redigér parameter", + "@editParameter": {}, + "editPart": "Rediger Del", + "@editPart": { + "description": "edit part" + }, + "editItem": "Rediger Lagervare", + "@editItem": {}, + "editLineItem": "Rediger Linjeelement", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "enterPassword": "Indtast adgangskode", + "@enterPassword": {}, + "enterUsername": "Indtast brugernavn", + "@enterUsername": {}, + "error": "Fejl", + "@error": { + "description": "Error" + }, + "errorCreate": "Fejl under oprettelse af database post", + "@errorCreate": {}, + "errorDelete": "Fejl ved sletning af databasepost", + "@errorDelete": {}, + "errorDetails": "Fejldetaljer", + "@errorDetails": {}, + "errorFetch": "Fejl ved hentning af data fra server", + "@errorFetch": {}, + "errorUserRoles": "Fejl ved forespørgsel af brugerroller fra server", + "@errorUserRoles": {}, + "errorPluginInfo": "Fejl ved forespørgsel af plugin data fra server", + "@errorPluginInfo": {}, + "errorReporting": "Fejlrapportering", + "@errorReporting": {}, + "errorReportUpload": "Upload Fejlrapporter", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonyme fejlrapporter og nedbrudslogs", + "@errorReportUploadDetails": {}, + "expiryDate": "Udløbsdato", + "@expiryDate": {}, + "expiryExpired": "Udløbet", + "@expiryExpired": {}, + "expiryStale": "Forældet", + "@expiryStale": {}, + "extraLineItem": "Ekstra linjepost", + "@extraLineItem": {}, + "extraLineItems": "Ekstra linjeposter", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Indsendelse af feedback mislykkedes", + "@feedbackError": {}, + "feedbackSuccess": "Feedback indsendt", + "@feedbackSuccess": {}, + "filterActive": "Aktiv", + "@filterActive": {}, + "filterActiveDetail": "Vis aktive dele", + "@filterActiveDetail": {}, + "filterAssembly": "Samlede", + "@filterAssembly": {}, + "filterAssemblyDetail": "Vis samledele", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponent", + "@filterComponent": {}, + "filterComponentDetail": "Vis komponentdele", + "@filterComponentDetail": {}, + "filterExternal": "Ekstern", + "@filterExternal": {}, + "filterExternalDetail": "Vis lager på eksterne lokationer", + "@filterExternalDetail": {}, + "filterInStock": "På Lager", + "@filterInStock": {}, + "filterInStockDetail": "Vis dele som har lagerbeholdning", + "@filterInStockDetail": {}, + "filterSerialized": "Serialiseret", + "@filterSerialized": {}, + "filterSerializedDetail": "Vis serialiserede lagervarer", + "@filterSerializedDetail": {}, + "filterTemplate": "Skabelon", + "@filterTemplate": {}, + "filterTemplateDetail": "Vis skabelon dele", + "@filterTemplateDetail": {}, + "filterTrackable": "Sporbar", + "@filterTrackable": {}, + "filterTrackableDetail": "Vis sporbare dele", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuel", + "@filterVirtual": {}, + "filterVirtualDetail": "Vis virtuelle dele", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtreringsindstillinger", + "@filteringOptions": {}, + "formatException": "Format Undtagelse", + "@formatException": {}, + "formatExceptionJson": "Undtagelse fra JSON-dataformat", + "@formatExceptionJson": {}, + "formError": "Formular Fejl", + "@formError": {}, + "history": "Historik", + "@history": { + "description": "history" + }, + "home": "Hjem", + "@home": {}, + "homeScreen": "Startskærm", + "@homeScreen": {}, + "homeScreenSettings": "Konfigurér indstillinger for startskærmen", + "@homeScreenSettings": {}, + "homeShowPo": "Vis Indkøbsordrer", + "@homeShowPo": {}, + "homeShowPoDescription": "Vis indkøbsordreknap på startskærmen", + "@homeShowPoDescription": {}, + "homeShowShipments": "Vis Forsendelser", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Vis afventende forsendelser på startskærmen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Vis Salgs ordrer", + "@homeShowSo": {}, + "homeShowSoDescription": "Vis salgsknap på startskærmen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Abonnerede Dele", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Vis abonnerede dele på startskærmen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Vis Leverandører", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Vis leverandørknap på startskærmen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Vis Producenter", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Vis producent-knap på startskærmen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Vis Kunder", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Vis kunde-knap på startskærmen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Upload af billede fejlede", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Billede uploadet", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveCompany": "Virksomheden er markeret som inaktiv", + "@inactiveCompany": {}, + "inactiveDetail": "Denne del er markeret som inaktiv", + "@inactiveDetail": {}, + "includeSubcategories": "Inkluder underkategorier", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Vis resultater fra underkategorier", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inkluder underlokationer", + "@includeSublocations": {}, + "includeSublocationsDetail": "Vis resultater fra underkategorier", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Ukomplette profiloplysninger", + "@incompleteDetails": {}, + "internalPartNumber": "Internt Delnummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "I Produktion", + "@inProduction": {}, + "inProductionDetail": "Denne lagervare er i produktion", + "@inProductionDetail": {}, + "internalPart": "Intern Del", + "@internalPart": {}, + "invalidHost": "Ugyldigt hostnavn", + "@invalidHost": {}, + "invalidHostDetails": "Det angivne hostnavn er ikke gyldigt", + "@invalidHostDetails": {}, + "invalidPart": "Ugyldig Del", + "@invalidPart": {}, + "invalidPartCategory": "Ugyldig Del Kategori", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ugyldig Lagerplacering", + "@invalidStockLocation": {}, + "invalidStockItem": "Ugyldig Lagervare", + "@invalidStockItem": {}, + "invalidSupplierPart": "Ugyldig Leverandørdel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Ugyldigt brugernavn/adgangskode-kombination", + "@invalidUsernamePassword": {}, + "invoice": "Faktura", + "@invoice": {}, + "invoiceNumber": "Fakturanummer", + "@invoiceNumber": {}, + "issue": "Problem", + "@issue": {}, + "issueDate": "Udstedelsesdato", + "@issueDate": {}, + "issueOrder": "Udstede Ordre", + "@issueOrder": {}, + "itemInLocation": "Element allerede på placering", + "@itemInLocation": {}, + "itemDeleted": "Element er blevet fjernet", + "@itemDeleted": {}, + "itemUpdated": "Element opdateret", + "@itemUpdated": {}, + "keywords": "Nøgleord", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Vælg Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Udskriver", + "@labelPrinting": {}, + "labelPrintingDetail": "Aktiver label udskrivning", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Skabelon", + "@labelTemplate": {}, + "labelSelectTemplate": "Vælg Label Skabelon", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Vælg Label Printer", + "@labelSelectPrinter": {}, + "language": "Sprog", + "@language": {}, + "languageDefault": "Standard systemsprog", + "@languageDefault": {}, + "languageSelect": "Vælg sprog", + "@languageSelect": {}, + "lastStocktake": "Sidste lageroptagelse", + "@lastStocktake": {}, + "lastUpdated": "Senest opdateret", + "@lastUpdated": {}, + "level": "Niveau", + "@level": {}, + "lineItemAdd": "Tilføj Linjeelement", + "@lineItemAdd": {}, + "lineItem": "Linje Element", + "@lineItem": {}, + "lineItems": "Linjeelementer", + "@lineItems": {}, + "lineItemUpdated": "Linje element opdateret", + "@lineItemUpdated": {}, + "locateItem": "Find lagervare", + "@locateItem": {}, + "locateLocation": "Find lager lokation", + "@locateLocation": {}, + "locationCreate": "Ny lokation", + "@locationCreate": {}, + "locationCreateDetail": "Opret ny lagerlokation", + "@locationCreateDetail": {}, + "locationDefault": "Standard lokation", + "@locationDefault": {}, + "locationNotSet": "Ingen lokation specificeret", + "@locationNotSet": {}, + "locationUpdated": "Lager lokation opdateret", + "@locationUpdated": {}, + "login": "Log ind", + "@login": {}, + "loginEnter": "Indtast login detaljer", + "@loginEnter": {}, + "loginEnterDetails": "Brugernavn og adgangskode er ikke gemt lokalt", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Mistet", + "@lost": {}, + "manufacturerPart": "Producent Del", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Rediger Producent Del", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Producent Delnummer", + "@manufacturerPartNumber": {}, + "manufacturer": "Producent", + "@manufacturer": {}, + "manufacturers": "Producenter", + "@manufacturers": {}, + "missingData": "Mangler data", + "@missingData": {}, + "name": "Navn", + "@name": {}, + "no": "Nej", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Ikke Forbundet", + "@notConnected": {}, + "notes": "Noter", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifikationer", + "@notifications": {}, + "notificationsEmpty": "Ingen ulæste notifikationer", + "@notificationsEmpty": {}, + "noResponse": "Intet svar fra server", + "@noResponse": {}, + "noResults": "Ingen Resultater", + "@noResults": {}, + "noImageAvailable": "Intet billede tilgængeligt", + "@noImageAvailable": {}, + "noPricingAvailable": "Ingen priser tilgængelig", + "@noPricingAvailable": {}, + "noPricingDataFound": "Ingen prisdata fundet for denne del", + "@noPricingDataFound": {}, + "noSubcategories": "Ingen Underkategorier", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Ingen underkategorier tilgængelige", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ugyldigt nummer", + "@numberInvalid": {}, + "onOrder": "På bestilling", + "@onOrder": {}, + "onOrderDetails": "Elementer i øjeblikket på ordre", + "@onOrderDetails": {}, + "orientation": "Skærm Orientering", + "@orientation": {}, + "orientationDetail": "Skærm orientering (kræver genstart)", + "@orientationDetail": {}, + "orientationLandscape": "Landskab", + "@orientationLandscape": {}, + "orientationPortrait": "Portræt", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Udestående", + "@outstanding": {}, + "outstandingOrderDetail": "Vis udestående ordrer", + "@outstandingOrderDetail": {}, + "overdue": "Overskredet", + "@overdue": {}, + "overdueDetail": "Vis forfaldne ordre", + "@overdueDetail": {}, + "packaging": "Emballage", + "@packaging": {}, + "packageName": "Pakkenavn", + "@packageName": {}, + "parameters": "Parametre", + "@parameters": {}, + "parametersSettingDetail": "Vis delparametre", + "@parametersSettingDetail": {}, + "parent": "Overordnet", + "@parent": {}, + "parentCategory": "Overordnet kategori", + "@parentCategory": {}, + "parentLocation": "Overordnet Placering", + "@parentLocation": {}, + "part": "Del", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Ny Del", + "@partCreate": {}, + "partCreateDetail": "Opret ny del i denne kategori", + "@partCreateDetail": {}, + "partEdited": "Del opdateret", + "@partEdited": {}, + "parts": "Dele", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Del ikke markeret som salgbart", + "@partNotSalable": {}, + "partsNone": "Ingen Dele", + "@partsNone": {}, + "partNoResults": "Ingen dele matcher forespørgsel", + "@partNoResults": {}, + "partPricing": "Del Prisfastsættelse", + "@partPricing": {}, + "partPricingSettingDetail": "Vis delprisinformation", + "@pricingSettingDetail": {}, + "partSettings": "Del Indstillinger", + "@partSettings": {}, + "partsStarred": "Abonnerede Dele", + "@partsStarred": {}, + "partsStarredNone": "Ingen markerede dele til rådighed", + "@partsStarredNone": {}, + "partSuppliers": "Del Leverandører", + "@partSuppliers": {}, + "partCategory": "Del Kategori", + "@partCategory": {}, + "partCategoryTopLevel": "Top niveau del kategori", + "@partCategoryTopLevel": {}, + "partCategories": "Del Kategorier", + "@partCategories": {}, + "partDetails": "Del Detaljer", + "@partDetails": {}, + "partNotes": "Del Noter", + "@partNotes": {}, + "partStock": "Del Lagerbeholdning", + "@partStock": { + "description": "part stock" + }, + "password": "Adgangskode", + "@password": {}, + "passwordEmpty": "Adgangskode kan ikke være tom", + "@passwordEmpty": {}, + "pending": "Afventende", + "@pending": {}, + "permissionAccountDenied": "Din konto har ikke de nødvendige tilladelser til at udføre denne handling", + "@permissionAccountDenied": {}, + "permissionRequired": "Tilladelse påkrævet", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "printLabel": "Udskriv label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Printer", + "@pluginPrinter": {}, + "pluginSupport": "Plugin Support Aktiveret", + "@pluginSupport": {}, + "pluginSupportDetail": "Serveren understøtter brugerdefinerede plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Label udskrivning mislykkedes", + "@printLabelFailure": {}, + "printLabelSuccess": "Label sendt til printer", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Tilføj Serverprofil", + "@profileAdd": {}, + "profileConnect": "Opretter forbindelse til server", + "@profileConnect": {}, + "profileEdit": "Rediger serverprofil", + "@profileEdit": {}, + "profileDelete": "Slet Server Profil", + "@profileDelete": {}, + "profileLogout": "Log Af Profil", + "@profileLogout": {}, + "profileName": "Profilnavn", + "@profileName": {}, + "profileNone": "Ingen profiler til rådighed", + "@profileNone": {}, + "profileNotSelected": "Ingen Profil Valgt", + "@profileNotSelected": {}, + "profileSelect": "Vælg InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Vælg server eller opret ny profil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tryk for at oprette eller vælge en profil", + "@profileTapToCreate": {}, + "projectCode": "Projektkode", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Bekræft Scanningsdata", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Bekræft detaljer ved ind scanning af elementer", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Aktive Indkøbsordrer", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Aktiver salgsordre funktionalitet", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Genvej Til Kamera", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Aktiver genvej til billedupload på købsordre skærmen", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Købsordre", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Ny købsordre", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Rediger Købsordre", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Indstillinger for indkøbsordre", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Indkøbsordrer", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Købsordre opdateret", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Købspris", + "@purchasePrice": {}, + "quantity": "Antal", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Antal Tilgængelig", + "@quantityAvailable": {}, + "quantityEmpty": "Antal er tomt", + "@quantityEmpty": {}, + "quantityInvalid": "Antal er ugyldigt", + "@quantityInvalid": {}, + "quantityPositive": "Antallet skal være positivt", + "@quantityPositive": {}, + "queryEmpty": "Indtast søgestreng", + "@queryEmpty": {}, + "queryNoResults": "Ingen resultater fundet", + "@queryNoResults": {}, + "received": "Modtaget", + "@received": {}, + "receivedFilterDetail": "Vis modtagne elementer", + "@receivedFilterDetail": {}, + "receiveItem": "Modtage Element", + "@receiveItem": {}, + "receivedItem": "Modtaget Lagervare", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Genindlæs", + "@refresh": {}, + "rotateClockwise": "Roter 90° med uret", + "@rotateClockwise": {}, + "refreshing": "Genindlæser", + "@refreshing": {}, + "rejected": "Afvist", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Fjern", + "@remove": { + "description": "remove" + }, + "removeStock": "Fjern Lagervarer", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Rapporter fejl", + "@reportBug": {}, + "reportBugDescription": "Indsend fejlrapport (kræver GitHub konto)", + "@reportBugDescription": {}, + "responsible": "Ansvarlig", + "@responsible": {}, + "results": "Resultater", + "@results": {}, + "request": "Anmodning", + "@request": {}, + "requestFailed": "Anmodning fejlede", + "@requestFailed": {}, + "requestSuccessful": "Anmodning succesfuld", + "@requestSuccessful": {}, + "requestingData": "Anmoder Data", + "@requestingData": {}, + "required": "Påkrævet", + "@required": { + "description": "This field is required" + }, + "response400": "Dårlig anmodning", + "@response400": {}, + "response401": "Uautoriseret", + "@response401": {}, + "response403": "Adgang nægtet", + "@response403": {}, + "response404": "Ressource Ikke Fundet", + "@response404": {}, + "response405": "Metode ikke tilladt", + "@response405": {}, + "response429": "For Mange Anmodninger", + "@response429": {}, + "response500": "Intern serverfejl", + "@response500": {}, + "response501": "Ikke implementeret", + "@response501": {}, + "response502": "Dårlig Gateway", + "@response502": {}, + "response503": "Service er utilgængelig", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP-version understøttes ikke", + "@response505": {}, + "responseData": "Svardata", + "@responseData": {}, + "responseInvalid": "Ugyldig Svar Kode", + "@responseInvalid": {}, + "responseUnknown": "Ukendt Svar", + "@responseUnknown": {}, + "result": "Resultat", + "@result": { + "description": "" + }, + "returned": "Returneret", + "@returned": {}, + "salesOrder": "Salgsordrer", + "@salesOrder": {}, + "salesOrders": "Salgsordrer", + "@salesOrders": {}, + "salesOrderEnable": "Aktiver Salgsordrer", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Aktiver salgsordre funktionalitet", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Genvej Til Kamera", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Aktiver genvej til billedupload til salgsordre på skærmen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Indstillinger for salgsordre", + "@salesOrderSettings": {}, + "salesOrderCreate": "Ny salgsordre", + "@saleOrderCreate": {}, + "salesOrderEdit": "Rediger Salgsordre", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Salgs ordre opdateret", + "@salesOrderUpdated": {}, + "save": "Gem", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan stregkode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan leverandørdel stregkode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Til Placering", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Skan dette element til placering", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Ekstern Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Brug ekstern scanner til at læse stregkoder (kiletilstand)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Modtagne Dele", + "@scanReceivedParts": {}, + "search": "Søg", + "@search": { + "description": "search" + }, + "searching": "Søger", + "@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", + "@searchStock": {}, + "select": "Vælg", + "@select": {}, + "selectFile": "Vælg fil", + "@selectFile": {}, + "selectImage": "Vælg billede", + "@selectImage": {}, + "selectLocation": "Vælg en placering", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "serialNumbers": "Serienummer", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradresse", + "@serverAddress": {}, + "serverApiRequired": "Kræver API-version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API Version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Autentificeringsfejl", + "@serverAuthenticationError": {}, + "serverCertificateError": "Certifikatfejl", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS certifikat er ugyldigt", + "@serverCertificateInvalid": {}, + "serverConnected": "Forbundet til server", + "@serverConnected": {}, + "serverConnecting": "Opretter forbindelse til server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Kunne ikke forbinde til server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serveren kan ikke være tom", + "@serverEmpty": {}, + "serverError": "Serverfejl", + "@serverError": {}, + "serverDetails": "Server detaljer", + "@serverDetails": {}, + "serverMissingData": "Server svar mangler obligatoriske felter", + "@serverMissingData": {}, + "serverOld": "Gammel Server Version", + "@serverOld": {}, + "serverSettings": "Server indstillinger", + "@serverSettings": {}, + "serverStart": "Server skal starte med http[s]", + "@serverStart": {}, + "settings": "Indstillinger", + "@settings": {}, + "serverInstance": "Server Instans", + "@serverInstance": {}, + "serverNotConnected": "Server ikke forbundet", + "@serverNotConnected": {}, + "serverNotSelected": "Server ikke valgt", + "@serverNotSelected": {}, + "shipment": "Forsendelse", + "@shipment": {}, + "shipments": "Forsendelser", + "@shipments": {}, + "shipmentsPending": "Afventer Forsendelser", + "@shipmentsPending": {}, + "shipmentAdd": "Tilføj Forsendelse", + "@shipmentAdd": {}, + "shipmentCheck": "Tjek Forsendelse", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Marker denne forsendelse som kontrolleret", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Forsendelse Kontrolleret", + "@shipmentChecked": {}, + "shipmentDate": "Afsendelsesdato", + "@shipmentDate": {}, + "shipmentEdit": "Rediger Forsendelse", + "@shipmentEdit": {}, + "shipmentReference": "Forsendelse Reference", + "@shipmentReference": {}, + "shipmentSend": "Send Forsendelse", + "@shipmentSend": {}, + "shipmentUncheck": "Afmarkér Forsendelse", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Marker denne forsendelse som afmarkeret", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Forsendelse Opdateret", + "@shipmentUpdated": {}, + "shipped": "Afsendt", + "@shipped": {}, + "sku": "Lagerbeholdning", + "@sku": {}, + "sounds": "Lyde", + "@sounds": {}, + "soundOnBarcodeAction": "Afspil hørbar tone ved stregkodehandling", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Afspil akustisk tone ved serverfejl", + "@soundOnServerError": {}, + "startDate": "Startdato", + "@startDate": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Kode", + "@statusCode": {}, + "stock": "Lager", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktuel disponibel lagermængde", + "@stockDetails": {}, + "stockItem": "Lagervarer", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Lagervarer", + "@stockItems": {}, + "stockItemCreate": "Ny Lagervare", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Opret ny lagervare på denne lokation", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Slet Lagervare", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Er du sikker på, at du vil slette denne lagervare?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Kunne ikke slette lagervare", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagervare slettet", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Lager Historik", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Vis historisk lagersporings information", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Lagervare overført", + "@stockItemTransferred": {}, + "stockItemUpdated": "Lagervare opdateret", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Ingen lagervarer tilgængelige", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Lager Vare Noter", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Lagervare opdateret", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Lagervare opdatering mislykkedes", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerlokationer", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerlokationer", + "@stockLocations": {}, + "stockTopLevel": "Top niveau lager lokation", + "@stockTopLevel": {}, + "strictHttps": "Brug Streng HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Håndhæve streng kontrol af HTTPS-certifikater", + "@strictHttpsDetails": {}, + "subcategory": "Underkategori", + "@subcategory": {}, + "subcategories": "Underkategorier", + "@subcategories": {}, + "sublocation": "Under lokation", + "@sublocation": {}, + "sublocations": "Under lokationer", + "@sublocations": {}, + "sublocationNone": "Ingen under lokationer", + "@sublocationNone": {}, + "sublocationNoneDetail": "Ingen under lokationer tilgængelige", + "@sublocationNoneDetail": {}, + "submitFeedback": "Indsend feedback", + "@submitFeedback": {}, + "suppliedParts": "Leveret Dele", + "@suppliedParts": {}, + "supplier": "Leverandør", + "@supplier": {}, + "supplierPart": "Leverandør Del", + "@supplierPart": {}, + "supplierPartEdit": "Rediger Leverandør Del", + "@supplierPartEdit": {}, + "supplierPartNumber": "Leverandør Delnummer", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Leverandør Del Opdateret", + "@supplierPartUpdated": {}, + "supplierParts": "Leverandør Dele", + "@supplierParts": {}, + "suppliers": "Leverandør", + "@suppliers": {}, + "supplierReference": "Leverandør Reference", + "@supplierReference": {}, + "switchCamera": "Skift Kamera", + "@switchCamera": {}, + "takePicture": "Tag billede", + "@takePicture": {}, + "targetDate": "Måldato", + "@targetDate": {}, + "templatePart": "Overordnet Skabelon Del", + "@templatePart": {}, + "testName": "Test navn", + "@testName": {}, + "testPassedOrFailed": "Test bestået eller fejlet", + "@testPassedOrFailed": {}, + "testsRequired": "Påkrævede Test", + "@testsRequired": {}, + "testResults": "Testresultater", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Vis testresultater for lagervarer", + "@testResultsDetail": {}, + "testResultAdd": "Tilføj Testresultat", + "@testResultAdd": {}, + "testResultNone": "Ingen Testresultater", + "@testResultNone": {}, + "testResultNoneDetail": "Ingen testresultater tilgængelige", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fejl under upload af testresultat", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test resultat uploadet", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "toggleTorch": "Tænd/sluk lys", + "@toggleTorch": {}, + "tokenError": "Token Fejl", + "@tokenError": {}, + "tokenMissing": "Mangler Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Adgangstoken mangler fra svar", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Pris", + "@totalPrice": {}, + "trackingNumber": "Sporingsnummer", + "@trackingNumber": {}, + "transfer": "Overfør", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Overfør Lager", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Overfør element til en anden lokation", + "@transferStockDetail": {}, + "transferStockLocation": "Overføre lager lokation", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Overfør denne lager lokation til en anden", + "@transferStockLocationDetail": {}, + "translate": "Oversæt", + "@translate": {}, + "translateHelp": "Hjælp med at oversætte InvenTree appen", + "@translateHelp": {}, + "unavailable": "Utilgængelig", + "@unavailable": {}, + "unavailableDetail": "Elementet er ikke tilgængeligt", + "@unavailableDetail": {}, + "unitPrice": "Enhedspris", + "@unitPrice": {}, + "units": "Enheder", + "@units": {}, + "unknownResponse": "Ukendt Svar", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload mislykkedes", + "@uploadFailed": {}, + "uploadSuccess": "Fil uploadet", + "@uploadSuccess": {}, + "uploadImage": "Upload billede", + "@uploadImage": {}, + "usedIn": "Brugt I", + "@usedIn": {}, + "usedInDetails": "Samlinger som kræver denne del", + "@usedInDetails": {}, + "username": "Brugernavn", + "@username": {}, + "usernameEmpty": "Brugernavn kan ikke være tomt", + "@usernameEmpty": {}, + "value": "Værdi", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Værdien kan ikke være tom", + "@valueCannotBeEmpty": {}, + "valueRequired": "Værdi er påkrævet", + "@valueRequired": {}, + "variants": "Varianter", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Vis Leverandør Del", + "@viewSupplierPart": {}, + "website": "Hjemmeside", + "@website": {}, + "yes": "Ja", + "@yes": {}, + "price": "Pris", + "@price": {}, + "priceRange": "Prisklasse", + "@priceRange": {}, + "priceOverrideMin": "Tilsidesættelse af minimumspris", + "@priceOverrideMin": {}, + "priceOverrideMax": "Tilsidesættelse af maksimalpris", + "@priceOverrideMax": {}, + "salePrice": "Salgspris", + "@salePrice": {}, + "saleHistory": "Salgs Historik", + "@saleHistory": {}, + "supplierPricing": "Leverandør Pris", + "@supplierPricing": {}, + "bomCost": "Stykliste Pris", + "@bomCost": {}, + "internalCost": "Intern Omkostning", + "@internalCost": {}, + "variantCost": "Variant Pris", + "@variantCost": {}, + "overallPricing": "Samlet prisfastsættelse", + "@overallPricing": {}, + "pricingOverrides": "Tilsidesætter Prisfastsættelse", + "@pricingOverrides": {}, + "currency": "Valuta", + "@currency": {}, + "priceBreaks": "Prispauser", + "@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 new file mode 100644 index 0000000..66e5dc8 --- /dev/null +++ b/lib/l10n/de_DE/app_de_DE.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Zugewiesen", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Quadratisch (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Bestand zuweisen", + "@allocateStock": {}, + "allocatedStock": "Zugewiesener Bestand", + "@allocatedStock": {}, + "appReleaseNotes": "App-Versionshinweise anzeigen", + "@appReleaseNotes": {}, + "appSettings": "App-Einstellungen", + "@appSettings": {}, + "appSettingsDetails": "InvenTree-App Einstellungen konfigurieren", + "@appSettingsDetails": {}, + "assignedToMe": "Mir zugewiesen", + "@assignedToMe": {}, + "assignedToMeDetail": "Aufträge anzeigen, die mir zugewiesen sind", + "@assignedToMeDetail": {}, + "attachments": "Anhänge", + "@attachments": {}, + "attachImage": "Bild hinzufügen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Keine Anhänge gefunden", + "@attachmentNone": {}, + "attachmentNoneDetail": "Keine Anhänge gefunden", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Anhang auswählen", + "@attachmentSelect": {}, + "attention": "Achtung", + "@attention": {}, + "available": "verfügbar", + "@available": {}, + "availableStock": "Verfügbarer Lagerbestand", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode-Einstellungen", + "@barcodeSettings": {}, + "barcodeAssign": "Barcode zuweisen", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Eigenen Barcode scannen zum Zuweisen", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Teilebarcode sannen", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Barcode scannen um Teil zu empfangen", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode-Scannen angehalten", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tippen um das Scannen zu pausieren", + "@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", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Einen InvenTree Barcode scannen", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Artikel per Barcode-Scan zu diesem Lagerort hinzufügen", + "@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": "Lagerartikel 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": {}, + "bomEnable": "Stückliste anzeigen", + "@bomEnable": {}, + "build": "Bauauftrag", + "@build": {}, + "building": "Gebäude", + "@building": {}, + "cameraCreationError": "Kamera-Controller konnte nicht geöffnet werden", + "@cameraCreationError": {}, + "cameraInternal": "Integrierte Kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Integrierte Kamera zum Lesen von Barcodes verwenden", + "@cameraInternalDetail": {}, + "cancel": "Abbrechen", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Bestellung stornieren", + "@cancelOrder": {}, + "category": "Kategorie", + "@category": {}, + "categoryCreate": "Neue Kategorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Teile-Kategorie anlegen", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategorie aktualisiert", + "@categoryUpdated": {}, + "company": "Firma", + "@company": {}, + "companyAdd": "Unternehmen hinzufügen", + "@companyAdd": {}, + "companyEdit": "Firma bearbeiten", + "@companyEdit": {}, + "companyNoResults": "Keine Firmen entsprechen der Anfrage", + "@companyNoResults": {}, + "companyUpdated": "Firmendetails aktualisiert", + "@companyUpdated": {}, + "companies": "Firmen", + "@companies": {}, + "complete": "", + "@complete": {}, + "completeOrder": "Bestellung abschließen", + "@completeOrder": {}, + "completionDate": "Abgeschlossen am", + "@completionDate": {}, + "configureServer": "Server-Einstellungen konfigurieren", + "@configureServer": {}, + "confirmScan": "Transfer bestätigen", + "@confirmScan": {}, + "confirmScanDetail": "Bestätigen Sie Bestandsverschiebungen beim Scannen von Barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Verbindung verweigert", + "@connectionRefused": {}, + "count": "Zählen", + "@count": { + "description": "Count" + }, + "countStock": "Bestand zählen", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Danksagungen", + "@credits": {}, + "crop": "Zuschneiden", + "@crop": {}, + "cropImage": "Bild zuschneiden", + "@cropImage": {}, + "customer": "Kunde", + "@customer": {}, + "customers": "Kunden", + "@customers": {}, + "customerReference": "Kundenreferenz", + "@customerReference": {}, + "damaged": "Beschädigt", + "@damaged": {}, + "colorScheme": "Farbschema", + "@colorScheme": {}, + "colorSchemeDetail": "Farbschema auswählen", + "@colorSchemeDetail": {}, + "darkMode": "Dunkles Design", + "@darkMode": {}, + "darkModeEnable": "Dunkles Design aktivieren", + "@darkModeEnable": {}, + "delete": "Löschen", + "@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": "Lieferdatum", + "@deliveryDate": {}, + "description": "Beschreibung", + "@description": {}, + "destination": "Zielort", + "@destination": {}, + "destroyed": "Vernichtet", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloadComplete": "Download abgeschlossen", + "@downloadComplete": {}, + "downloadError": "Fehler beim Herunterladen des Bildes", + "@downloadError": {}, + "downloading": "Datei wird heruntergeladen", + "@downloading": {}, + "edit": "Bearbeiten", + "@edit": { + "description": "edit" + }, + "editAttachment": "Anhang bearbeiten", + "@editAttachment": {}, + "editCategory": "Kategorie bearbeiten", + "@editCategory": {}, + "editLocation": "Ort bearbeiten", + "@editLocation": {}, + "editNotes": "Notizen bearbeiten", + "@editNotes": {}, + "editParameter": "Parameter bearbeiten", + "@editParameter": {}, + "editPart": "Teil bearbeiten", + "@editPart": { + "description": "edit part" + }, + "editItem": "Artikel bearbeiten", + "@editItem": {}, + "editLineItem": "Position bearbeiten", + "@editLineItem": {}, + "email": "E-Mail", + "@email": {}, + "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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonyme Fehlerberichte und Absturzprotokolle hochladen", + "@errorReportUploadDetails": {}, + "expiryDate": "Verfallsdatum", + "@expiryDate": {}, + "expiryExpired": "Verfallen", + "@expiryExpired": {}, + "expiryStale": "überfällig", + "@expiryStale": {}, + "extraLineItem": "Zusätzliche Position", + "@extraLineItem": {}, + "extraLineItems": "Zusätzliche Positionen", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fehler beim Senden des Feedbacks", + "@feedbackError": {}, + "feedbackSuccess": "Feedback gesendet", + "@feedbackSuccess": {}, + "filterActive": "Aktiv", + "@filterActive": {}, + "filterActiveDetail": "Aktive Teile anzeigen", + "@filterActiveDetail": {}, + "filterAssembly": "Zusammengebaut", + "@filterAssembly": {}, + "filterAssemblyDetail": "Zeige zusammengebaute Teile", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponente", + "@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", + "@filterInStockDetail": {}, + "filterSerialized": "Hat Seriennummer", + "@filterSerialized": {}, + "filterSerializedDetail": "Lagerartikel mit Seriennummern anzeigen", + "@filterSerializedDetail": {}, + "filterTemplate": "Vorlage", + "@filterTemplate": {}, + "filterTemplateDetail": "Vorlagen-Teile anzeigen", + "@filterTemplateDetail": {}, + "filterTrackable": "Nachverfolgbar", + "@filterTrackable": {}, + "filterTrackableDetail": "Zeige verfolgbare Teile", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuell", + "@filterVirtual": {}, + "filterVirtualDetail": "Virtuelle Teile anzeigen", + "@filterVirtualDetail": {}, + "filteringOptions": "Filteroptionen", + "@filteringOptions": {}, + "formatException": "Formatfehler", + "@formatException": {}, + "formatExceptionJson": "Format-Fehler im JSON", + "@formatExceptionJson": {}, + "formError": "Formular-Fehler", + "@formError": {}, + "history": "Verlauf", + "@history": { + "description": "history" + }, + "home": "Startseite", + "@home": {}, + "homeScreen": "Startseite", + "@homeScreen": {}, + "homeScreenSettings": "Einstellungen für Startseite konfigurieren", + "@homeScreenSettings": {}, + "homeShowPo": "Bestellungen anzeigen", + "@homeShowPo": {}, + "homeShowPoDescription": "Bestellungen auf Startseite anzeigen", + "@homeShowPoDescription": {}, + "homeShowShipments": "Lieferungen anzeigen", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Ausstehende Lieferaufträge auf der Startseite anzeigen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Aufträge anzeigen", + "@homeShowSo": {}, + "homeShowSoDescription": "Verkaufsknopf auf dem Startbildschirm anzeigen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Abonnierte Teile", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Abonnierte Teile auf Startseite anzeigen", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Dieses Unternehmen ist als inaktiv markiert", + "@inactiveCompany": {}, + "inactiveDetail": "Teil als inaktiv gekennzeichnet", + "@inactiveDetail": {}, + "includeSubcategories": "Unter-Kategorien einschließen", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Ergebnisse aus Unterkategorien anzeigen", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Unter-Lagerorte einschließen", + "@includeSublocations": {}, + "includeSublocationsDetail": "Ergebnisse aus Unterkategorien 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": {}, + "internalPart": "Internes Teil", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Ungültiges Zuliefererteil", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Ungültige Kombination aus Benutzername und Passwort", + "@invalidUsernamePassword": {}, + "invoice": "Rechnung", + "@invoice": {}, + "invoiceNumber": "Rechnungsnummer", + "@invoiceNumber": {}, + "issue": "Aufgeben", + "@issue": {}, + "issueDate": "Ausstellungsdatum", + "@issueDate": {}, + "issueOrder": "Bestellung aufgeben", + "@issueOrder": {}, + "itemInLocation": "Artikel ist bereits in diesem Lagerort", + "@itemInLocation": {}, + "itemDeleted": "Element wurde gelöscht", + "@itemDeleted": {}, + "itemUpdated": "Gegenstand aktualisiert", + "@itemUpdated": {}, + "keywords": "Schlüsselwörter", + "@keywords": {}, + "labelDriver": "Etikettendrucker Treiber", + "@labelDriver": {}, + "labelSelectDriver": "Etikettendrucker Treiber auswählen", + "@labelSelectDriver": {}, + "labelPrinting": "Etikettendruck", + "@labelPrinting": {}, + "labelPrintingDetail": "Etikettendruck aktivieren", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Vorlage", + "@labelTemplate": {}, + "labelSelectTemplate": "Etiketten-Vorlage auswählen", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Etikettendrucker auswählen", + "@labelSelectPrinter": {}, + "language": "Sprache", + "@language": {}, + "languageDefault": "Standard-Systemsprache", + "@languageDefault": {}, + "languageSelect": "Sprache auswählen", + "@languageSelect": {}, + "lastStocktake": "Letzte Inventur", + "@lastStocktake": {}, + "lastUpdated": "Letzte Änderung", + "@lastUpdated": {}, + "level": "Ebene", + "@level": {}, + "lineItemAdd": "Position hinzufügen", + "@lineItemAdd": {}, + "lineItem": "Position", + "@lineItem": {}, + "lineItems": "Positionen", + "@lineItems": {}, + "lineItemUpdated": "Position aktualisiert", + "@lineItemUpdated": {}, + "locateItem": "Lagerbestand lokalisieren", + "@locateItem": {}, + "locateLocation": "Lagerort lokalisieren", + "@locateLocation": {}, + "locationCreate": "Neuer Lagerort", + "@locationCreate": {}, + "locationCreateDetail": "Neuen Lagerort erstellen", + "@locationCreateDetail": {}, + "locationDefault": "Standard Lagerort", + "@locationDefault": {}, + "locationNotSet": "Lagerort nicht angegeben", + "@locationNotSet": {}, + "locationUpdated": "Lagerort aktualisiert", + "@locationUpdated": {}, + "login": "Anmelden", + "@login": {}, + "loginEnter": "Anmeldedaten eingeben", + "@loginEnter": {}, + "loginEnterDetails": "Benutzername und Passwort werden nicht lokal gespeichert", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "manufacturerPart": "Herstellerteil", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Herstellerteil bearbeiten", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Teilenummer des Herstellers", + "@manufacturerPartNumber": {}, + "manufacturer": "Hersteller", + "@manufacturer": {}, + "manufacturers": "Hersteller", + "@manufacturers": {}, + "missingData": "Fehlende Daten", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "Nein", + "@no": {}, + "notApplicable": "Nicht Anwendbar", + "@notApplicable": {}, + "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", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Keine gültige Zahl", + "@numberInvalid": {}, + "onOrder": "Bestellt", + "@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", + "@outstanding": {}, + "outstandingOrderDetail": "Offene Aufträge anzeigen", + "@outstandingOrderDetail": {}, + "overdue": "Überfällig", + "@overdue": {}, + "overdueDetail": "Überfällige Aufträge anzeigen", + "@overdueDetail": {}, + "packaging": "Paket", + "@packaging": {}, + "packageName": "Paket-Name", + "@packageName": {}, + "parameters": "Parameter", + "@parameters": {}, + "parametersSettingDetail": "Teilparameter anzeigen", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Artikel nicht als verkaufbar markiert", + "@partNotSalable": {}, + "partsNone": "Keine Teile", + "@partsNone": {}, + "partNoResults": "Keine Teile entsprechen der Anfrage", + "@partNoResults": {}, + "partPricing": "Teilbepreisung", + "@partPricing": {}, + "partPricingSettingDetail": "Zeige Zeitplanung für Teile", + "@pricingSettingDetail": {}, + "partSettings": "Teil-Einstellungen", + "@partSettings": {}, + "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": {}, + "pending": "Ausstehend", + "@pending": {}, + "permissionAccountDenied": "Das Konto hat die erforderlichen Berechtigungen zum Ausführen dieses Vorgangs nicht", + "@permissionAccountDenied": {}, + "permissionRequired": "Berechtigung erforderlich", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "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", + "@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": {}, + "profileLogout": "Profil abmelden", + "@profileLogout": {}, + "profileName": "Profil-Name", + "@profileName": {}, + "profileNone": "Keine Profile angelegt", + "@profileNone": {}, + "profileNotSelected": "Kein Profil ausgewählt", + "@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": {}, + "projectCode": "Projektcode", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Scan daten bestätigen", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Details beim Scannen bestätigen", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Bestellungen aktivieren", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Bestellfunktion aktivieren", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Kamera Verknüpfung", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Bild-Upload-Verknüpfung auf Bestellbildschirm aktivieren", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Bestellung", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Neue Bestellung", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Bestellung bearbeiten", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Bestelleinstellungen", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Bestellungen", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bestellung aktualisiert", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Einkaufspreis", + "@purchasePrice": {}, + "quantity": "Anzahl", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Verfügbare Menge", + "@quantityAvailable": {}, + "quantityEmpty": "Menge ist leer", + "@quantityEmpty": {}, + "quantityInvalid": "Menge ist ungültig", + "@quantityInvalid": {}, + "quantityPositive": "Menge muss positiv sein", + "@quantityPositive": {}, + "queryEmpty": "Suchanfrage eingeben", + "@queryEmpty": {}, + "queryNoResults": "Keine Ergebnisse für die Anfrage", + "@queryNoResults": {}, + "received": "Empfangen", + "@received": {}, + "receivedFilterDetail": "Empfangene Artikel anzeigen", + "@receivedFilterDetail": {}, + "receiveItem": "Artikel erhalten", + "@receiveItem": {}, + "receivedItem": "Artikel wurde erhalten", + "@receivedItem": {}, + "reference": "Referenz", + "@reference": {}, + "refresh": "Neu laden", + "@refresh": {}, + "rotateClockwise": "90° im Uhrzeigersinn drehen", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Verantwortlich", + "@responsible": {}, + "results": "Ergebnisse", + "@results": {}, + "request": "Anfrage", + "@request": {}, + "requestFailed": "Anfrage fehlgeschlagen", + "@requestFailed": {}, + "requestSuccessful": "Anfrage erfolgreich", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Auftrag", + "@salesOrder": {}, + "salesOrders": "Kundenauftrag", + "@salesOrders": {}, + "salesOrderEnable": "Aufträge aktivieren", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Auftragsfunktion aktivieren", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Kamera Verknüpfung", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Bild-Upload-Verknüpfung auf Auftragsbildschirm aktivieren", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Auftrags-Einstellungen", + "@salesOrderSettings": {}, + "salesOrderCreate": "Neuer Auftrag", + "@saleOrderCreate": {}, + "salesOrderEdit": "Auftrag bearbeiten", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Auftrag aktualisiert", + "@salesOrderUpdated": {}, + "save": "Speichern", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barcode scannen", + "@scanBarcode": {}, + "scanSupplierPart": "Lieferanten Barcode scannen", + "@scanSupplierPart": {}, + "scanIntoLocation": "In Lagerorten buchen", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Artikel per Scan zu Lagerort hinzufügen", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Externer Scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Benutze externen Scanner um Barcodes zu lesen", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Empfangene Teile scannen", + "@scanReceivedParts": {}, + "search": "Suchen", + "@search": { + "description": "search" + }, + "searching": "Suche", + "@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", + "@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": {}, + "serialNumbers": "Seriennummern", + "@serialNumbers": {}, + "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": {}, + "serverNotSelected": "Server nicht ausgewählt", + "@serverNotSelected": {}, + "shipment": "Lieferung", + "@shipment": {}, + "shipments": "Lieferungen", + "@shipments": {}, + "shipmentsPending": "Ausstehende Lieferungen", + "@shipmentsPending": {}, + "shipmentAdd": "Lieferung hinzufügen", + "@shipmentAdd": {}, + "shipmentCheck": "Lieferung überprüfen", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Diese Lieferung als geprüft markieren", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Lieferung überprüft", + "@shipmentChecked": {}, + "shipmentDate": "Versanddatum", + "@shipmentDate": {}, + "shipmentEdit": "Lieferung bearbeiten", + "@shipmentEdit": {}, + "shipmentReference": "Sendungsreferenz", + "@shipmentReference": {}, + "shipmentSend": "Lieferung versenden", + "@shipmentSend": {}, + "shipmentUncheck": "Lieferung ungeprüft markieren", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Diese Lieferung als ungeprüft markieren", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Lieferung Aktualisiert", + "@shipmentUpdated": {}, + "shipped": "Versandt", + "@shipped": {}, + "sku": "Bestellnummer", + "@sku": {}, + "sounds": "Töne", + "@sounds": {}, + "soundOnBarcodeAction": "Ton bei Barcode-Aktion abspielen", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Ton bei Serverfehler abspielen", + "@soundOnServerError": {}, + "startDate": "Startdatum", + "@startDate": {}, + "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": {}, + "supplierPart": "Zuliefererteil", + "@supplierPart": {}, + "supplierPartEdit": "Zuliefererteil bearbeiten", + "@supplierPartEdit": {}, + "supplierPartNumber": "Teilenummer des Zulieferers", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Zuliefererteil aktualisiert", + "@supplierPartUpdated": {}, + "supplierParts": "Zuliefererteile", + "@supplierParts": {}, + "suppliers": "Lieferanten", + "@suppliers": {}, + "supplierReference": "Lieferanten-Referenz", + "@supplierReference": {}, + "switchCamera": "Kamera wechseln", + "@switchCamera": {}, + "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": "" + }, + "testResultsDetail": "Testergebnisse für Lagerartikel anzeigen", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Taschenlampe umschalten", + "@toggleTorch": {}, + "tokenError": "Token-Fehler", + "@tokenError": {}, + "tokenMissing": "Token fehlt", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Zugangstoken fehlt in Antwort", + "@tokenMissingFromResponse": {}, + "totalPrice": "Gesamtbetrag", + "@totalPrice": {}, + "trackingNumber": "Sendungsverfolgungsnummer", + "@trackingNumber": {}, + "transfer": "Verschieben", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Bestand verschieben", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Artikel an einen anderen Ort übertragen", + "@transferStockDetail": {}, + "transferStockLocation": "Lagerort übertragen", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Diesen Lagerort in einen anderen übertragen", + "@transferStockLocationDetail": {}, + "translate": "Übersetzen", + "@translate": {}, + "translateHelp": "Hilf dabei, die InvenTree App zu übersetzen", + "@translateHelp": {}, + "unavailable": "Nicht verfügbar", + "@unavailable": {}, + "unavailableDetail": "Artikel ist nicht verfügbar", + "@unavailableDetail": {}, + "unitPrice": "Preis pro Einheit", + "@unitPrice": {}, + "units": "Einheiten", + "@units": {}, + "unknownResponse": "Unbekannte Antwort", + "@unknownResponse": {}, + "upload": "Hochladen", + "@upload": {}, + "uploadFailed": "Datei hochladen fehlgeschlagen", + "@uploadFailed": {}, + "uploadSuccess": "Datei hochgeladen", + "@uploadSuccess": {}, + "uploadImage": "Bild hochladen", + "@uploadImage": {}, + "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": {}, + "variants": "Varianten", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Zulieferer-Teil anzeigen", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {}, + "yes": "Ja", + "@yes": {}, + "price": "Preis", + "@price": {}, + "priceRange": "Preisspanne", + "@priceRange": {}, + "priceOverrideMin": "Mindestpreis ignorieren", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximalpreis ignorieren", + "@priceOverrideMax": {}, + "salePrice": "Verkaufspreis", + "@salePrice": {}, + "saleHistory": "Verkaufshistorie", + "@saleHistory": {}, + "supplierPricing": "Zulieferer-Preise", + "@supplierPricing": {}, + "bomCost": "Stücklistenkosten", + "@bomCost": {}, + "internalCost": "Interne Kosten", + "@internalCost": {}, + "variantCost": "Variantenkosten", + "@variantCost": {}, + "overallPricing": "Gesamt Preise", + "@overallPricing": {}, + "pricingOverrides": "Preisgestaltung ignorieren", + "@pricingOverrides": {}, + "currency": "Währung", + "@currency": {}, + "priceBreaks": "Preisstaffel", + "@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 new file mode 100644 index 0000000..7e697ae --- /dev/null +++ b/lib/l10n/el_GR/app_el_GR.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "el", + "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": {}, + "allocated": "Κατανεμημένο", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Τετράγωνο (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Κατανομή Αποθέματος", + "@allocateStock": {}, + "allocatedStock": "Κατανεμημένο Απόθεμα", + "@allocatedStock": {}, + "appReleaseNotes": "Προβολή πληροφοριών έκδοσης εφαρμογής", + "@appReleaseNotes": {}, + "appSettings": "Ρυθμίσεις Εφαρμογής", + "@appSettings": {}, + "appSettingsDetails": "Διαμόρφωση ρυθμίσεων της εφαρμογής InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Ανατεθειμένα σε εμένα", + "@assignedToMe": {}, + "assignedToMeDetail": "Προβολή παραγγελιών που έχουν ανατεθεί σε εμένα", + "@assignedToMeDetail": {}, + "attachments": "Συνημμένα", + "@attachments": {}, + "attachImage": "Επισύναψη Εικόνας", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Δεν βρέθηκαν συνημμένα", + "@attachmentNone": {}, + "attachmentNoneDetail": "Δεν βρέθηκαν συνημμένα", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Επιλογή επισύναψης", + "@attachmentSelect": {}, + "attention": "Προσοχή", + "@attention": {}, + "available": "Διαθέσιμο", + "@available": {}, + "availableStock": "Διαθέσιμο Απόθεμα", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Ρυθμίσεις Barcode", + "@barcodeSettings": {}, + "barcodeAssign": "Αντιστοίχιση Barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Σαρώστε προσαρμοσμένο barcode για ανάθεση", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Το barcode καταχωρήθηκε", + "@barcodeAssigned": {}, + "barcodeError": "Σφάλμα σάρωσης Barcode", + "@barcodeError": {}, + "barcodeInUse": "Το Barcode έχει ήδη ανατεθεί", + "@barcodeInUse": {}, + "barcodeMissingHash": "Λείπουν δεδομένα κατακερματισμού barcode από την απόκριση", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Δεν υπάρχει αντιστοιχία με το barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Το barcode δεν καταχωρήθηκε", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Σάρωση barcode εξαρτήματος", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Σάρωση barcode για λήψη εξαρτήματος", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Παύση σάρωσης barcode", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Σάρωση για εκχώρηση barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Είσοδος Σαρωτή", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Επιλέξτε πηγή εισόδου για σαρωτή barcode", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Καθυστέρηση Σάρωσης Barcode", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Καθυστέρηση μεταξύ σαρώσεων barcode", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Σάρωση InvenTree barcode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Σάρωση αντικειμένων σε αυτήν την τοποθεσία", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Σάρωση τοποθεσίας αποθέματος", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Λειτουργία Μονής Σάρωσης", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Παύση του σαρωτή μετά από κάθε σάρωση", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Σαρώθηκε στην τοποθεσία", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Το αντικείμενο δεν σαρώθηκε", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Σάρωση αντικειμένου αποθέματος", + "@barcodeScanItem": {}, + "barcodeTones": "Ήχοι Barcode", + "@barcodeTones": {}, + "barcodeUnassign": "Αφαίρεση Ανάθεσης Barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "Το barcode δεν αναγνωρίζεται", + "@barcodeUnknown": {}, + "batchCode": "Κωδικός Παρτίδας", + "@batchCode": {}, + "billOfMaterials": "Κατάσταση Υλικών", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Εμφάνιση Κατάστασης Υλικών", + "@bomEnable": {}, + "build": "Κατασκευή", + "@build": {}, + "building": "Κατασκευάζεται", + "@building": {}, + "cameraCreationError": "Αδυναμία ανοίγματος κάμερας", + "@cameraCreationError": {}, + "cameraInternal": "Εσωτερική Κάμερα", + "@cameraInternal": {}, + "cameraInternalDetail": "Χρήση εσωτερικής κάμερας για ανάγνωση barcodes", + "@cameraInternalDetail": {}, + "cancel": "Ακύρωση", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Ακύρωση Παραγγελίας", + "@cancelOrder": {}, + "category": "Κατηγορία", + "@category": {}, + "categoryCreate": "Νέα Κατηγορία", + "@categoryCreate": {}, + "categoryCreateDetail": "Δημιουργία νέας κατηγορίας εξαρτημάτων", + "@categoryCreateDetail": {}, + "categoryUpdated": "Η κατηγορία ενημερώθηκε", + "@categoryUpdated": {}, + "company": "Εταιρεία", + "@company": {}, + "companyAdd": "Προσθήκη Εταιρείας", + "@companyAdd": {}, + "companyEdit": "Επεξεργασία Εταιρείας", + "@companyEdit": {}, + "companyNoResults": "Καμία εταιρεία δεν ταιριάζει με την αναζήτηση", + "@companyNoResults": {}, + "companyUpdated": "Τα στοιχεία της εταιρείας ενημερώθηκαν", + "@companyUpdated": {}, + "companies": "Εταιρείες", + "@companies": {}, + "complete": "Ολοκλήρωση", + "@complete": {}, + "completeOrder": "Ολοκλήρωση Παραγγελίας", + "@completeOrder": {}, + "completionDate": "Ημερομηνία Ολοκλήρωσης", + "@completionDate": {}, + "configureServer": "Ρύθμιση παραμέτρων διακομιστή", + "@configureServer": {}, + "confirmScan": "Επιβεβαίωση Μεταφοράς", + "@confirmScan": {}, + "confirmScanDetail": "Επιβεβαίωση λεπτομερειών μεταφοράς κατά τη σάρωση barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Η σύνδεση απορρίφθηκε", + "@connectionRefused": {}, + "count": "Μέτρηση", + "@count": { + "description": "Count" + }, + "countStock": "Καταμέτρηση Αποθέματος", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Πιστώσεις", + "@credits": {}, + "crop": "Περικοπή", + "@crop": {}, + "cropImage": "Περικοπή Εικόνας", + "@cropImage": {}, + "customer": "Πελάτης", + "@customer": {}, + "customers": "Πελάτες", + "@customers": {}, + "customerReference": "Αναφορά Πελάτη", + "@customerReference": {}, + "damaged": "Κατεστραμμένο", + "@damaged": {}, + "colorScheme": "Συνδυασμός Χρωμάτων", + "@colorScheme": {}, + "colorSchemeDetail": "Επιλογή συνδυασμού χρωμάτων", + "@colorSchemeDetail": {}, + "darkMode": "Σκουρόχρωμη Λειτουργία", + "@darkMode": {}, + "darkModeEnable": "Ενεργοποίηση σκοτεινής λειτουργίας", + "@darkModeEnable": {}, + "delete": "Διαγραφή", + "@delete": {}, + "deleteFailed": "Η διαγραφή απέτυχε", + "@deleteFailed": {}, + "deleteImageConfirmation": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτή την εικόνα;", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Διαγραφή Εικόνας", + "@deleteImageTooltip": {}, + "deleteImage": "Διαγραφή Εικόνας", + "@deleteImage": {}, + "deletePart": "Διαγραφή Εξαρτήματος", + "@deletePart": {}, + "deletePartDetail": "Αφαίρεση αυτού του εξαρτήματος από τη βάση δεδομένων", + "@deletePartDetail": {}, + "deleteSuccess": "Η διαγραφή ολοκληρώθηκε με επιτυχία", + "@deleteSuccess": {}, + "deliveryDate": "Ημερομηνία Παράδοσης", + "@deliveryDate": {}, + "description": "Περιγραφή", + "@description": {}, + "destination": "Προορισμός", + "@destination": {}, + "destroyed": "Καταστράφηκε", + "@destroyed": {}, + "details": "Λεπτομέρειες", + "@details": { + "description": "details" + }, + "documentation": "Τεκμηρίωση", + "@documentation": {}, + "downloadComplete": "Η λήψη ολοκληρώθηκε", + "@downloadComplete": {}, + "downloadError": "Σφάλμα κατά τη λήψη της εικόνας", + "@downloadError": {}, + "downloading": "Λήψη Αρχείου", + "@downloading": {}, + "edit": "Επεξεργασία", + "@edit": { + "description": "edit" + }, + "editAttachment": "Επεξεργασία Συνημμένου", + "@editAttachment": {}, + "editCategory": "Επεξεργασία Κατηγορίας", + "@editCategory": {}, + "editLocation": "Επεξεργασία Τοποθεσίας", + "@editLocation": {}, + "editNotes": "Επεξεργασία Σημειώσεων", + "@editNotes": {}, + "editParameter": "Επεξεργασία Παραμέτρου", + "@editParameter": {}, + "editPart": "Επεξεργασία Εξαρτήματος", + "@editPart": { + "description": "edit part" + }, + "editItem": "Επεξεργασία Αντικειμένου Αποθέματος", + "@editItem": {}, + "editLineItem": "Επεξεργασία Γραμμής", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Εισαγάγετε τον κωδικό", + "@enterPassword": {}, + "enterUsername": "Εισαγάγετε το όνομα χρήστη", + "@enterUsername": {}, + "error": "Σφάλμα", + "@error": { + "description": "Error" + }, + "errorCreate": "Σφάλμα κατά τη δημιουργία εγγραφής", + "@errorCreate": {}, + "errorDelete": "Σφάλμα κατά τη διαγραφή εγγραφής", + "@errorDelete": {}, + "errorDetails": "Λεπτομέρειες Σφάλματος", + "@errorDetails": {}, + "errorFetch": "Σφάλμα κατά την ανάκτηση δεδομένων από τον διακομιστή", + "@errorFetch": {}, + "errorUserRoles": "Σφάλμα κατά το αίτημα ρόλων χρήστη", + "@errorUserRoles": {}, + "errorPluginInfo": "Σφάλμα κατά το αίτημα πληροφοριών plugin", + "@errorPluginInfo": {}, + "errorReporting": "Αναφορά Σφαλμάτων", + "@errorReporting": {}, + "errorReportUpload": "Ανέβασμα Αναφορών Σφαλμάτων", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Ανώνυμη αποστολή αναφορών σφαλμάτων και καταγραφών κρασαρισμάτων", + "@errorReportUploadDetails": {}, + "expiryDate": "Ημερομηνία Λήξης", + "@expiryDate": {}, + "expiryExpired": "Έχει λήξει", + "@expiryExpired": {}, + "expiryStale": "Παλαιό", + "@expiryStale": {}, + "extraLineItem": "Επιπλέον Γραμμή", + "@extraLineItem": {}, + "extraLineItems": "Επιπλέον Γραμμές", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "Εμφάνιση αντικειμένων αποθέματος με σειριακό αριθμό", + "@filterSerializedDetail": {}, + "filterTemplate": "Πρότυπο", + "@filterTemplate": {}, + "filterTemplateDetail": "Εμφάνιση πρότυπων εξαρτημάτων", + "@filterTemplateDetail": {}, + "filterTrackable": "Ιχνηλάσιμο", + "@filterTrackable": {}, + "filterTrackableDetail": "Εμφάνιση ιχνηλάσιμων εξαρτημάτων", + "@filterTrackableDetail": {}, + "filterVirtual": "Εικονικά", + "@filterVirtual": {}, + "filterVirtualDetail": "Εμφάνιση εικονικών εξαρτημάτων", + "@filterVirtualDetail": {}, + "filteringOptions": "Επιλογές Φιλτραρίσματος", + "@filteringOptions": {}, + "formatException": "Εξαίρεση Μορφοποίησης", + "@formatException": {}, + "formatExceptionJson": "Εξαίρεση μορφής JSON", + "@formatExceptionJson": {}, + "formError": "Σφάλμα Φόρμας", + "@formError": {}, + "history": "Ιστορικό", + "@history": { + "description": "history" + }, + "home": "Αρχική", + "@home": {}, + "homeScreen": "Αρχική Οθόνη", + "@homeScreen": {}, + "homeScreenSettings": "Ρύθμιση αρχικής οθόνης", + "@homeScreenSettings": {}, + "homeShowPo": "Εμφάνιση Παραγγελιών Αγοράς", + "@homeShowPo": {}, + "homeShowPoDescription": "Εμφάνιση κουμπιού παραγγελιών αγοράς στην αρχική οθόνη", + "@homeShowPoDescription": {}, + "homeShowShipments": "Εμφάνιση Αποστολών", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Εμφάνιση εκκρεμών αποστολών στην αρχική οθόνη", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Εμφάνιση Παραγγελιών Πώλησης", + "@homeShowSo": {}, + "homeShowSoDescription": "Εμφάνιση κουμπιού παραγγελιών πώλησης στην αρχική οθόνη", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Εγγεγραμμένα Εξαρτήματα", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Εμφάνιση εγγεγραμμένων εξαρτημάτων στην αρχική οθόνη", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Εμφάνιση Προμηθευτών", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Εμφάνιση κουμπιού προμηθευτών στην αρχική οθόνη", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Εμφάνιση Κατασκευαστών", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Εμφάνιση κουμπιού κατασκευαστών στην αρχική οθόνη", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Εμφάνιση Πελατών", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Εμφάνιση κουμπιού πελατών στην αρχική οθόνη", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Αποτυχία μεταφόρτωσης εικόνας", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Η εικόνα μεταφορτώθηκε", + "@imageUploadSuccess": {}, + "inactive": "Ανενεργό", + "@inactive": {}, + "inactiveCompany": "Αυτή η εταιρεία έχει επισημανθεί ως ανενεργή", + "@inactiveCompany": {}, + "inactiveDetail": "Αυτό το εξάρτημα έχει επισημανθεί ως ανενεργό", + "@inactiveDetail": {}, + "includeSubcategories": "Συμπερίληψη Υποκατηγοριών", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Εμφάνιση αποτελεσμάτων από υποκατηγορίες", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Συμπερίληψη Υποτοποθεσιών", + "@includeSublocations": {}, + "includeSublocationsDetail": "Εμφάνιση αποτελεσμάτων από υποτοποθεσίες", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Ελλιπείς λεπτομέρειες προφίλ", + "@incompleteDetails": {}, + "internalPartNumber": "Εσωτερικός Κωδικός Εξαρτήματος", + "@internalPartNumber": {}, + "info": "Πληροφορίες", + "@info": {}, + "inProduction": "Σε Παραγωγή", + "@inProduction": {}, + "inProductionDetail": "Αυτό το αντικείμενο αποθέματος βρίσκεται σε παραγωγή", + "@inProductionDetail": {}, + "internalPart": "Εσωτερικό Εξάρτημα", + "@internalPart": {}, + "invalidHost": "Μη έγκυρο hostname", + "@invalidHost": {}, + "invalidHostDetails": "Το παρεχόμενο hostname δεν είναι έγκυρο", + "@invalidHostDetails": {}, + "invalidPart": "Μη έγκυρο Εξάρτημα", + "@invalidPart": {}, + "invalidPartCategory": "Μη έγκυρη Κατηγορία Εξαρτήματος", + "@invalidPartCategory": {}, + "invalidStockLocation": "Μη έγκυρη Τοποθεσία Αποθέματος", + "@invalidStockLocation": {}, + "invalidStockItem": "Μη έγκυρο Αντικείμενο Αποθέματος", + "@invalidStockItem": {}, + "invalidSupplierPart": "Μη έγκυρο Εξάρτημα Προμηθευτή", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Μη έγκυρος συνδυασμός ονόματος χρήστη / κωδικού", + "@invalidUsernamePassword": {}, + "invoice": "Τιμολόγιο", + "@invoice": {}, + "invoiceNumber": "Αριθμός Τιμολογίου", + "@invoiceNumber": {}, + "issue": "Έκδοση", + "@issue": {}, + "issueDate": "Ημερομηνία Έκδοσης", + "@issueDate": {}, + "issueOrder": "Έκδοση Παραγγελίας", + "@issueOrder": {}, + "itemInLocation": "Το αντικείμενο βρίσκεται ήδη στην τοποθεσία", + "@itemInLocation": {}, + "itemDeleted": "Το αντικείμενο αφαιρέθηκε", + "@itemDeleted": {}, + "itemUpdated": "Το αντικείμενο ενημερώθηκε", + "@itemUpdated": {}, + "keywords": "Λέξεις-Κλειδιά", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Εκτύπωση Ετικετών", + "@labelPrinting": {}, + "labelPrintingDetail": "Ενεργοποίηση εκτύπωσης ετικετών", + "@labelPrintingDetail": {}, + "labelTemplate": "Πρότυπο Ετικέτας", + "@labelTemplate": {}, + "labelSelectTemplate": "Επιλογή Προτύπου Ετικέτας", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Επιλογή Εκτυπωτή Ετικετών", + "@labelSelectPrinter": {}, + "language": "Γλώσσα", + "@language": {}, + "languageDefault": "Προεπιλεγμένη γλώσσα συστήματος", + "@languageDefault": {}, + "languageSelect": "Επιλογή Γλώσσας", + "@languageSelect": {}, + "lastStocktake": "Τελευταία Απογραφή", + "@lastStocktake": {}, + "lastUpdated": "Τελευταία Ενημέρωση", + "@lastUpdated": {}, + "level": "Επίπεδο", + "@level": {}, + "lineItemAdd": "Προσθήκη Γραμμής", + "@lineItemAdd": {}, + "lineItem": "Γραμμή", + "@lineItem": {}, + "lineItems": "Γραμμές", + "@lineItems": {}, + "lineItemUpdated": "Η γραμμή ενημερώθηκε", + "@lineItemUpdated": {}, + "locateItem": "Εντοπισμός αντικειμένου αποθέματος", + "@locateItem": {}, + "locateLocation": "Εντοπισμός τοποθεσίας αποθέματος", + "@locateLocation": {}, + "locationCreate": "Νέα Τοποθεσία", + "@locationCreate": {}, + "locationCreateDetail": "Δημιουργία νέας τοποθεσίας αποθέματος", + "@locationCreateDetail": {}, + "locationDefault": "Προεπιλεγμένη Τοποθεσία", + "@locationDefault": {}, + "locationNotSet": "Δεν έχει οριστεί τοποθεσία", + "@locationNotSet": {}, + "locationUpdated": "Η τοποθεσία ενημερώθηκε", + "@locationUpdated": {}, + "login": "Σύνδεση", + "@login": {}, + "loginEnter": "Εισαγάγετε τα στοιχεία σύνδεσης", + "@loginEnter": {}, + "loginEnterDetails": "Το όνομα χρήστη και ο κωδικός δεν αποθηκεύονται τοπικά", + "@loginEnterDetails": {}, + "link": "Σύνδεσμος", + "@link": {}, + "lost": "Χαμένο", + "@lost": {}, + "manufacturerPart": "Κωδικός Κατασκευαστή", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Επεξεργασία Κωδικού Κατασκευαστή", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Αριθμός Κωδικού Κατασκευαστή", + "@manufacturerPartNumber": {}, + "manufacturer": "Κατασκευαστής", + "@manufacturer": {}, + "manufacturers": "Κατασκευαστές", + "@manufacturers": {}, + "missingData": "Ελλιπή Δεδομένα", + "@missingData": {}, + "name": "Όνομα", + "@name": {}, + "no": "Όχι", + "@no": {}, + "notApplicable": "Μ/Δ", + "@notApplicable": {}, + "notConnected": "Δεν υπάρχει σύνδεση", + "@notConnected": {}, + "notes": "Σημειώσεις", + "@notes": { + "description": "Notes" + }, + "notifications": "Ειδοποιήσεις", + "@notifications": {}, + "notificationsEmpty": "Καμία μη αναγνωσμένη ειδοποίηση", + "@notificationsEmpty": {}, + "noResponse": "Χωρίς απόκριση από τον διακομιστή", + "@noResponse": {}, + "noResults": "Κανένα αποτέλεσμα", + "@noResults": {}, + "noImageAvailable": "Δεν υπάρχει διαθέσιμη εικόνα", + "@noImageAvailable": {}, + "noPricingAvailable": "Δεν υπάρχουν διαθέσιμες τιμές", + "@noPricingAvailable": {}, + "noPricingDataFound": "Δεν βρέθηκαν δεδομένα τιμολόγησης για αυτό το εξάρτημα", + "@noPricingDataFound": {}, + "noSubcategories": "Δεν υπάρχουν υποκατηγορίες", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Δεν υπάρχουν διαθέσιμες υποκατηγορίες", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Μη έγκυρος αριθμός", + "@numberInvalid": {}, + "onOrder": "Σε Παραγγελία", + "@onOrder": {}, + "onOrderDetails": "Αντικείμενα που βρίσκονται σε παραγγελία", + "@onOrderDetails": {}, + "orientation": "Προσανατολισμός Οθόνης", + "@orientation": {}, + "orientationDetail": "Προσανατολισμός οθόνης (απαιτεί επανεκκίνηση)", + "@orientationDetail": {}, + "orientationLandscape": "Οριζόντια", + "@orientationLandscape": {}, + "orientationPortrait": "Κάθετη", + "@orientationPortrait": {}, + "orientationSystem": "Σύστημα", + "@orientationSystem": {}, + "outstanding": "Εκκρεμείς", + "@outstanding": {}, + "outstandingOrderDetail": "Εμφάνιση εκκρεμών παραγγελιών", + "@outstandingOrderDetail": {}, + "overdue": "Καθυστερημένες", + "@overdue": {}, + "overdueDetail": "Εμφάνιση καθυστερημένων παραγγελιών", + "@overdueDetail": {}, + "packaging": "Συσκευασία", + "@packaging": {}, + "packageName": "Όνομα Πακέτου", + "@packageName": {}, + "parameters": "Παράμετροι", + "@parameters": {}, + "parametersSettingDetail": "Εμφάνιση παραμέτρων εξαρτήματος", + "@parametersSettingDetail": {}, + "parent": "Γονικό", + "@parent": {}, + "parentCategory": "Γονική Κατηγορία", + "@parentCategory": {}, + "parentLocation": "Γονική Τοποθεσία", + "@parentLocation": {}, + "part": "Εξάρτημα", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Νέο Εξάρτημα", + "@partCreate": {}, + "partCreateDetail": "Δημιουργία νέου εξαρτήματος σε αυτή την κατηγορία", + "@partCreateDetail": {}, + "partEdited": "Το εξάρτημα ενημερώθηκε", + "@partEdited": {}, + "parts": "Εξαρτήματα", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Το εξάρτημα δεν έχει χαρακτηριστεί ως διαθέσιμο προς πώληση", + "@partNotSalable": {}, + "partsNone": "Δεν υπάρχουν εξαρτήματα", + "@partsNone": {}, + "partNoResults": "Κανένα εξάρτημα δεν ταιριάζει με την αναζήτηση", + "@partNoResults": {}, + "partPricing": "Τιμολόγηση Εξαρτήματος", + "@partPricing": {}, + "partPricingSettingDetail": "Εμφάνιση πληροφοριών τιμολόγησης εξαρτήματος", + "@pricingSettingDetail": {}, + "partSettings": "Ρυθμίσεις Εξαρτημάτων", + "@partSettings": {}, + "partsStarred": "Εγγεγραμμένα Εξαρτήματα", + "@partsStarred": {}, + "partsStarredNone": "Δεν υπάρχουν εγγεγραμμένα εξαρτήματα", + "@partsStarredNone": {}, + "partSuppliers": "Προμηθευτές Εξαρτήματος", + "@partSuppliers": {}, + "partCategory": "Κατηγορία Εξαρτήματος", + "@partCategory": {}, + "partCategoryTopLevel": "Κατηγορία εξαρτήματος ανώτερου επιπέδου", + "@partCategoryTopLevel": {}, + "partCategories": "Κατηγορίες Εξαρτημάτων", + "@partCategories": {}, + "partDetails": "Λεπτομέρειες Εξαρτήματος", + "@partDetails": {}, + "partNotes": "Σημειώσεις Εξαρτήματος", + "@partNotes": {}, + "partStock": "Απόθεμα Εξαρτήματος", + "@partStock": { + "description": "part stock" + }, + "password": "Κωδικός", + "@password": {}, + "passwordEmpty": "Ο κωδικός δεν μπορεί να είναι κενός", + "@passwordEmpty": {}, + "pending": "Σε αναμονή", + "@pending": {}, + "permissionAccountDenied": "Ο λογαριασμός σας δεν έχει τα απαραίτητα δικαιώματα για αυτή την ενέργεια", + "@permissionAccountDenied": {}, + "permissionRequired": "Απαιτούνται Δικαιώματα", + "@permissionRequired": {}, + "phone": "Τηλέφωνο", + "@phone": {}, + "printLabel": "Εκτύπωση Ετικέτας", + "@printLabel": {}, + "plugin": "Πρόσθετο", + "@plugin": {}, + "pluginPrinter": "Εκτυπωτής", + "@pluginPrinter": {}, + "pluginSupport": "Υποστήριξη Plugin ενεργοποιημένη", + "@pluginSupport": {}, + "pluginSupportDetail": "Ο διακομιστής υποστηρίζει προσαρμοσμένα plugins", + "@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": {}, + "purchaseOrderConfirmScan": "Επιβεβαίωση Δεδομένων Σάρωσης", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Επιβεβαίωση λεπτομερειών κατά τη σάρωση αντικειμένων", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Ενεργοποίηση Παραγγελιών Αγοράς", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Ενεργοποίηση λειτουργιών παραγγελίας αγοράς", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Συντόμευση Κάμερας", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Ενεργοποίηση συντόμευσης μεταφόρτωσης εικόνων στην οθόνη παραγγελίας", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Παραγγελία Αγοράς", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Νέα Παραγγελία Αγοράς", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Επεξεργασία Παραγγελίας Αγοράς", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Ρυθμίσεις Παραγγελιών Αγοράς", + "@purchaseOrderSettings": {}, + "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": {}, + "rotateClockwise": "Περιστροφή 90° δεξιόστροφα", + "@rotateClockwise": {}, + "refreshing": "Γίνεται ανανέωση", + "@refreshing": {}, + "rejected": "Απορρίφθηκε", + "@rejected": {}, + "releaseNotes": "Σημειώσεις Έκδοσης", + "@releaseNotes": {}, + "remove": "Αφαίρεση", + "@remove": { + "description": "remove" + }, + "removeStock": "Αφαίρεση Αποθέματος", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Αναφορά Σφάλματος", + "@reportBug": {}, + "reportBugDescription": "Υποβολή αναφοράς σφάλματος (απαιτεί λογαριασμό GitHub)", + "@reportBugDescription": {}, + "responsible": "Υπεύθυνος", + "@responsible": {}, + "results": "Αποτελέσματα", + "@results": {}, + "request": "Αίτημα", + "@request": {}, + "requestFailed": "Η αίτηση απέτυχε", + "@requestFailed": {}, + "requestSuccessful": "Η αίτηση ολοκληρώθηκε με επιτυχία", + "@requestSuccessful": {}, + "requestingData": "Ανάκτηση Δεδομένων", + "@requestingData": {}, + "required": "Απαιτείται", + "@required": { + "description": "This field is required" + }, + "response400": "Μη Έγκυρο Αίτημα", + "@response400": {}, + "response401": "Μη Εξουσιοδοτημένο", + "@response401": {}, + "response403": "Δεν Επιτρέπεται", + "@response403": {}, + "response404": "Ο Πόρος Δεν Βρέθηκε", + "@response404": {}, + "response405": "Μη Επιτρεπτή Μέθοδος", + "@response405": {}, + "response429": "Πάρα Πολλά Αιτήματα", + "@response429": {}, + "response500": "Εσωτερικό Σφάλμα Διακομιστή", + "@response500": {}, + "response501": "Μη Υλοποιημένο", + "@response501": {}, + "response502": "Εσφαλμένη Πύλη (Bad Gateway)", + "@response502": {}, + "response503": "Υπηρεσία Μη Διαθέσιμη", + "@response503": {}, + "response504": "Λήξη Χρόνου Πύλης (Gateway Timeout)", + "@response504": {}, + "response505": "Η Έκδοση HTTP Δεν Υποστηρίζεται", + "@response505": {}, + "responseData": "Δεδομένα Απόκρισης", + "@responseData": {}, + "responseInvalid": "Μη έγκυρος κωδικός απόκρισης", + "@responseInvalid": {}, + "responseUnknown": "Άγνωστη Απόκριση", + "@responseUnknown": {}, + "result": "Αποτέλεσμα", + "@result": { + "description": "" + }, + "returned": "Επιστράφηκε", + "@returned": {}, + "salesOrder": "Παραγγελία Πώλησης", + "@salesOrder": {}, + "salesOrders": "Παραγγελίες Πώλησης", + "@salesOrders": {}, + "salesOrderEnable": "Ενεργοποίηση Παραγγελιών Πώλησης", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Ενεργοποίηση λειτουργιών παραγγελιών πώλησης", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Συντόμευση Κάμερας", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Ενεργοποίηση συντόμευσης μεταφόρτωσης εικόνας στην οθόνη παραγγελίας πώλησης", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Ρυθμίσεις Παραγγελιών Πώλησης", + "@salesOrderSettings": {}, + "salesOrderCreate": "Νέα Παραγγελία Πώλησης", + "@saleOrderCreate": {}, + "salesOrderEdit": "Επεξεργασία Παραγγελίας Πώλησης", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Η παραγγελία πώλησης ενημερώθηκε", + "@salesOrderUpdated": {}, + "save": "Αποθήκευση", + "@save": { + "description": "Save" + }, + "scanBarcode": "Σάρωση Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Σάρωση barcode εξαρτήματος προμηθευτή", + "@scanSupplierPart": {}, + "scanIntoLocation": "Σάρωση σε Τοποθεσία", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Σαρώστε αυτό το αντικείμενο στην τοποθεσία", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Εξωτερικός Σαρωτής", + "@scannerExternal": {}, + "scannerExternalDetail": "Χρήση εξωτερικού σαρωτή για ανάγνωση barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Σάρωση Παραληφθέντων Εξαρτημάτων", + "@scanReceivedParts": {}, + "search": "Αναζήτηση", + "@search": { + "description": "search" + }, + "searching": "Γίνεται αναζήτηση", + "@searching": {}, + "searchLocation": "Αναζήτηση τοποθεσίας", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "Αναζήτηση εξαρτημάτων", + "@searchParts": {}, + "searchStock": "Αναζήτηση αποθέματος", + "@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": "Ο διακομιστής πρέπει να ξεκινά με http[s]", + "@serverStart": {}, + "settings": "Ρυθμίσεις", + "@settings": {}, + "serverInstance": "Περίπτωση Διακομιστή", + "@serverInstance": {}, + "serverNotConnected": "Δεν υπάρχει σύνδεση με τον διακομιστή", + "@serverNotConnected": {}, + "serverNotSelected": "Δεν έχει επιλεγεί διακομιστής", + "@serverNotSelected": {}, + "shipment": "Αποστολή", + "@shipment": {}, + "shipments": "Αποστολές", + "@shipments": {}, + "shipmentsPending": "Εκκρεμείς Αποστολές", + "@shipmentsPending": {}, + "shipmentAdd": "Προσθήκη Αποστολής", + "@shipmentAdd": {}, + "shipmentCheck": "Έλεγχος Αποστολής", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Σημειώστε την αποστολή ως ελεγμένη", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Η Αποστολή Ελέγχθηκε", + "@shipmentChecked": {}, + "shipmentDate": "Ημερομηνία Αποστολής", + "@shipmentDate": {}, + "shipmentEdit": "Επεξεργασία Αποστολής", + "@shipmentEdit": {}, + "shipmentReference": "Αναφορά Αποστολής", + "@shipmentReference": {}, + "shipmentSend": "Αποστολή", + "@shipmentSend": {}, + "shipmentUncheck": "Αναίρεση Ελέγχου Αποστολής", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Σημειώστε την αποστολή ως μη ελεγμένη", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Η Αποστολή Ενημερώθηκε", + "@shipmentUpdated": {}, + "shipped": "Απεστάλη", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Ήχοι", + "@sounds": {}, + "soundOnBarcodeAction": "Αναπαραγωγή ήχου κατά τη δράση barcode", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Αναπαραγωγή ήχου σε σφάλμα διακομιστή", + "@soundOnServerError": {}, + "startDate": "Ημερομηνία Έναρξης", + "@startDate": {}, + "status": "Κατάσταση", + "@status": {}, + "statusCode": "Κωδικός Κατάστασης", + "@statusCode": {}, + "stock": "Απόθεμα", + "@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": "Το αντικείμενο αποθέματος ενημερώθηκε", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Η ενημέρωση του αντικειμένου απέτυχε", + "@stockItemUpdateFailure": {}, + "stockLocation": "Τοποθεσία Αποθέματος", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Τοποθεσίες Αποθέματος", + "@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": "Κωδικός Προμηθευτή", + "@supplierPart": {}, + "supplierPartEdit": "Επεξεργασία Κωδικού Προμηθευτή", + "@supplierPartEdit": {}, + "supplierPartNumber": "Αριθμός Κωδικού Προμηθευτή", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Ο κωδικός προμηθευτή ενημερώθηκε", + "@supplierPartUpdated": {}, + "supplierParts": "Κωδικοί Προμηθευτή", + "@supplierParts": {}, + "suppliers": "Προμηθευτές", + "@suppliers": {}, + "supplierReference": "Αναφορά Προμηθευτή", + "@supplierReference": {}, + "switchCamera": "Αλλαγή Κάμερας", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Εναλλαγή Φακού", + "@toggleTorch": {}, + "tokenError": "Σφάλμα Διακριτικού", + "@tokenError": {}, + "tokenMissing": "Λείπει Διακριτικό", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Το διακριτικό πρόσβασης λείπει από την απόκριση", + "@tokenMissingFromResponse": {}, + "totalPrice": "Συνολική Τιμή", + "@totalPrice": {}, + "trackingNumber": "Αριθμός Παρακολούθησης", + "@trackingNumber": {}, + "transfer": "Μεταφορά", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Μεταφορά Αποθέματος", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Μεταφορά του αντικειμένου σε διαφορετική τοποθεσία", + "@transferStockDetail": {}, + "transferStockLocation": "Μεταφορά Τοποθεσίας Αποθέματος", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Μεταφορά αυτής της τοποθεσίας αποθέματος σε άλλη", + "@transferStockLocationDetail": {}, + "translate": "Μετάφραση", + "@translate": {}, + "translateHelp": "Βοηθήστε στη μετάφραση της εφαρμογής InvenTree", + "@translateHelp": {}, + "unavailable": "Μη Διαθέσιμο", + "@unavailable": {}, + "unavailableDetail": "Το αντικείμενο δεν είναι διαθέσιμο", + "@unavailableDetail": {}, + "unitPrice": "Τιμή Μονάδας", + "@unitPrice": {}, + "units": "Μονάδες", + "@units": {}, + "unknownResponse": "Άγνωστη Απόκριση", + "@unknownResponse": {}, + "upload": "Μεταφόρτωση", + "@upload": {}, + "uploadFailed": "Η μεταφόρτωση του αρχείου απέτυχε", + "@uploadFailed": {}, + "uploadSuccess": "Το αρχείο μεταφορτώθηκε", + "@uploadSuccess": {}, + "uploadImage": "Μεταφόρτωση Εικόνας", + "@uploadImage": {}, + "usedIn": "Χρησιμοποιείται Σε", + "@usedIn": {}, + "usedInDetails": "Συναρμολογήσεις που απαιτούν αυτό το εξάρτημα", + "@usedInDetails": {}, + "username": "Όνομα Χρήστη", + "@username": {}, + "usernameEmpty": "Το όνομα χρήστη δεν μπορεί να είναι κενό", + "@usernameEmpty": {}, + "value": "Τιμή", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Η τιμή δεν μπορεί να είναι κενή", + "@valueCannotBeEmpty": {}, + "valueRequired": "Η τιμή απαιτείται", + "@valueRequired": {}, + "variants": "Παραλλαγές", + "@variants": {}, + "version": "Έκδοση", + "@version": {}, + "viewSupplierPart": "Προβολή Κωδικού Προμηθευτή", + "@viewSupplierPart": {}, + "website": "Ιστοσελίδα", + "@website": {}, + "yes": "Ναι", + "@yes": {}, + "price": "Τιμή", + "@price": {}, + "priceRange": "Εύρος Τιμών", + "@priceRange": {}, + "priceOverrideMin": "Ελάχιστη Τιμή Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Μέγιστη Τιμή Override", + "@priceOverrideMax": {}, + "salePrice": "Τιμή Πώλησης", + "@salePrice": {}, + "saleHistory": "Ιστορικό Πωλήσεων", + "@saleHistory": {}, + "supplierPricing": "Τιμολόγηση Προμηθευτή", + "@supplierPricing": {}, + "bomCost": "Κόστος BOM", + "@bomCost": {}, + "internalCost": "Εσωτερικό Κόστος", + "@internalCost": {}, + "variantCost": "Κόστος Παραλλαγής", + "@variantCost": {}, + "overallPricing": "Συνολική Τιμολόγηση", + "@overallPricing": {}, + "pricingOverrides": "Price Overrides", + "@pricingOverrides": {}, + "currency": "Νόμισμα", + "@currency": {}, + "priceBreaks": "Τμήματα Τιμής", + "@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 new file mode 100644 index 0000000..0fcb849 --- /dev/null +++ b/lib/l10n/es_ES/app_es_ES.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "es-ES", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Acerca de", + "@about": {}, + "accountDetails": "Detalle de la Cuenta", + "@accountDetails": {}, + "actions": "Acciones", + "@actions": { + "description": "" + }, + "actionsNone": "No hay acciones disponibles", + "@actionsNone": {}, + "add": "Añadir", + "@add": { + "description": "add" + }, + "addStock": "Añadir Inventario", + "@addStock": { + "description": "add stock" + }, + "address": "Dirección", + "@address": {}, + "appAbout": "Acerca de InvenTree", + "@appAbout": {}, + "appCredits": "Credito Adicionales de la app", + "@appCredits": {}, + "appDetails": "Detalles de la app", + "@appDetails": {}, + "allocated": "Asignado", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Cuadrado (1:1)", + "@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", + "@appSettings": {}, + "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Asignado a mí", + "@assignedToMe": {}, + "assignedToMeDetail": "Mostrar pedidos asignados a mí", + "@assignedToMeDetail": {}, + "attachments": "Adjuntos", + "@attachments": {}, + "attachImage": "Adjuntar Imagen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No se encontraron adjuntos", + "@attachmentNone": {}, + "attachmentNoneDetail": "No se encontraron archivos adjuntos", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Seleccionar archivo adjunto", + "@attachmentSelect": {}, + "attention": "Atención", + "@attention": {}, + "available": "Disponible", + "@available": {}, + "availableStock": "Inventario Disponible", + "@availableStock": {}, + "barcodes": "Códigos de barras", + "@barcodes": {}, + "barcodeSettings": "Ajustes de códigos de barras", + "@barcodeSettings": {}, + "barcodeAssign": "Asignar código de barras", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Escanear código de barras personalizado para asignar", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Escanear código de barras de parte", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Escanear código de barras para recibir parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Escaneo de código de barras en pausa", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Escanear para asignar código de barras", + "@barcodeScanAssign": {}, + "barcodeScanController": "Entrada de escáner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Seleccionar fuente de entrada del escáner de código de barras", + "@barcodeScanControllerDetail": {}, + "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", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear a la ubicación de Inventario", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Modo de escaneo único", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pausar el escáner de código de barras después de cada escaneado", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artículo no escaneado en", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Escanear artículo de inventario", + "@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": "Codigo Batch", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiales", + "@billOfMaterials": {}, + "bom": "Lista de materiales", + "@bom": {}, + "bomEnable": "Mostrar Lista de Materiales", + "@bomEnable": {}, + "build": "Construir", + "@build": {}, + "building": "Construyendo", + "@building": {}, + "cameraCreationError": "No se pudo abrir el controlador de la cámara", + "@cameraCreationError": {}, + "cameraInternal": "Cámara interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", + "@cameraInternalDetail": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancelar orden", + "@cancelOrder": {}, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nueva Categoría", + "@categoryCreate": {}, + "categoryCreateDetail": "Crear nueva categoría de piezas", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoría actualizada", + "@categoryUpdated": {}, + "company": "Empresa", + "@company": {}, + "companyAdd": "Agregar empresa", + "@companyAdd": {}, + "companyEdit": "Modificar Empresa", + "@companyEdit": {}, + "companyNoResults": "No hay empresas que coincidan con la consulta", + "@companyNoResults": {}, + "companyUpdated": "Detalles de la empresa actualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "complete": "Completado", + "@complete": {}, + "completeOrder": "Completar Pedido", + "@completeOrder": {}, + "completionDate": "Fecha de Finalización", + "@completionDate": {}, + "configureServer": "Configure las opciones de su servidor", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Contar Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "crop": "Recortar", + "@crop": {}, + "cropImage": "Recortar la imagen", + "@cropImage": {}, + "customer": "Cliente", + "@customer": {}, + "customers": "Clientes", + "@customers": {}, + "customerReference": "Referencia del Cliente", + "@customerReference": {}, + "damaged": "Dañado", + "@damaged": {}, + "colorScheme": "Combinación de colores", + "@colorScheme": {}, + "colorSchemeDetail": "Seleccionar combinación de colores", + "@colorSchemeDetail": {}, + "darkMode": "Modo oscuro", + "@darkMode": {}, + "darkModeEnable": "Activar modo oscuro", + "@darkModeEnable": {}, + "delete": "Eliminar", + "@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", + "@destination": {}, + "destroyed": "Destruido", + "@destroyed": {}, + "details": "Detalles", + "@details": { + "description": "details" + }, + "documentation": "Documentación", + "@documentation": {}, + "downloadComplete": "Descarga completa", + "@downloadComplete": {}, + "downloadError": "Error al descargar la imagen", + "@downloadError": {}, + "downloading": "Descargando archivo", + "@downloading": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editAttachment": "Editar archivo adjunto", + "@editAttachment": {}, + "editCategory": "Editar categoría", + "@editCategory": {}, + "editLocation": "Editar ubicación", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editParameter": "Editar Parámetro", + "@editParameter": {}, + "editPart": "Editar Pieza", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar artículo de stock", + "@editItem": {}, + "editLineItem": "Editar Ítem de Línea", + "@editLineItem": {}, + "email": "Correo electrónico", + "@email": {}, + "enterPassword": "Introduzca contraseña", + "@enterPassword": {}, + "enterUsername": "Introduzca su nombre de usuario", + "@enterUsername": {}, + "error": "Error", + "@error": { + "description": "Error" + }, + "errorCreate": "Error al crear entrada de base de datos", + "@errorCreate": {}, + "errorDelete": "Error al eliminar entrada de base de datos", + "@errorDelete": {}, + "errorDetails": "Detalles de error", + "@errorDetails": {}, + "errorFetch": "Error obteniendo datos del servidor", + "@errorFetch": {}, + "errorUserRoles": "Error solicitando roles de usuario desde el servidor", + "@errorUserRoles": {}, + "errorPluginInfo": "Error al solicitar datos del plugin desde el servidor", + "@errorPluginInfo": {}, + "errorReporting": "Reporte de errores", + "@errorReporting": {}, + "errorReportUpload": "Subir Reportes de Error", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Subir reportes de error anónimos y registros de errores", + "@errorReportUploadDetails": {}, + "expiryDate": "Fecha de Expiración", + "@expiryDate": {}, + "expiryExpired": "Expirado", + "@expiryExpired": {}, + "expiryStale": "Obsoleto", + "@expiryStale": {}, + "extraLineItem": "Elemento extra de línea", + "@extraLineItem": {}, + "extraLineItems": "Elementos extra de línea", + "@extraLineItems": {}, + "feedback": "Comentarios", + "@feedback": {}, + "feedbackError": "Error al enviar comentarios", + "@feedbackError": {}, + "feedbackSuccess": "Comentarios enviados", + "@feedbackSuccess": {}, + "filterActive": "Activo", + "@filterActive": {}, + "filterActiveDetail": "Mostrar piezas activas", + "@filterActiveDetail": {}, + "filterAssembly": "Ensamblado", + "@filterAssembly": {}, + "filterAssemblyDetail": "Mostrar piezas ensambladas", + "@filterAssemblyDetail": {}, + "filterComponent": "Componente", + "@filterComponent": {}, + "filterComponentDetail": "Mostrar piezas del componente", + "@filterComponentDetail": {}, + "filterExternal": "Externo", + "@filterExternal": {}, + "filterExternalDetail": "Mostrar stock en ubicaciones externas", + "@filterExternalDetail": {}, + "filterInStock": "En Existencia", + "@filterInStock": {}, + "filterInStockDetail": "Mostrar piezas que tienen existencias", + "@filterInStockDetail": {}, + "filterSerialized": "Serializado", + "@filterSerialized": {}, + "filterSerializedDetail": "Mostrar artículos de stock serializados", + "@filterSerializedDetail": {}, + "filterTemplate": "Plantilla", + "@filterTemplate": {}, + "filterTemplateDetail": "Mostrar plantillas de piezas", + "@filterTemplateDetail": {}, + "filterTrackable": "Rastreable", + "@filterTrackable": {}, + "filterTrackableDetail": "Mostrar piezas rastreables", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Mostrar piezas virtuales", + "@filterVirtualDetail": {}, + "filteringOptions": "Opciones de filtro", + "@filteringOptions": {}, + "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" + }, + "home": "Inicio", + "@home": {}, + "homeScreen": "Pantalla de Inicio", + "@homeScreen": {}, + "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", + "@homeScreenSettings": {}, + "homeShowPo": "Mostrar órdenes de compra", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Piezas Destacadas", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostrar piezas destacadas en la pantalla de inicio", + "@homeShowSubscsribedDescription": {}, + "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 cargar la imagen", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Imagen cargada", + "@imageUploadSuccess": {}, + "inactive": "Inactivo", + "@inactive": {}, + "inactiveCompany": "Esta empresa está marcada como inactiva", + "@inactiveCompany": {}, + "inactiveDetail": "Esta pieza está marcada como inactiva", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir subcategorias", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar resultados de subcategorías", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incluir sub-ubicación", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar resultados de sub-ubicaciones", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Detalles del perfil incompletos", + "@incompleteDetails": {}, + "internalPartNumber": "Número de pieza interno", + "@internalPartNumber": {}, + "info": "Información", + "@info": {}, + "inProduction": "En producción", + "@inProduction": {}, + "inProductionDetail": "El artículo de inventario está en producción", + "@inProductionDetail": {}, + "internalPart": "Pieza Interna", + "@internalPart": {}, + "invalidHost": "Nombre de host no válido", + "@invalidHost": {}, + "invalidHostDetails": "Este nombre de host no es válido", + "@invalidHostDetails": {}, + "invalidPart": "Pieza inválida", + "@invalidPart": {}, + "invalidPartCategory": "Categoría de pieza inválida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ubicación de inventario inválida", + "@invalidStockLocation": {}, + "invalidStockItem": "Artículo de stock inválido", + "@invalidStockItem": {}, + "invalidSupplierPart": "Parte de proveedor no válida", + "@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", + "@issueDate": {}, + "issueOrder": "Emitir pedido", + "@issueOrder": {}, + "itemInLocation": "El artículo ya está en la ubicación", + "@itemInLocation": {}, + "itemDeleted": "El artículo ha sido eliminado", + "@itemDeleted": {}, + "itemUpdated": "Elemento actualizado", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Plantilla de etiqueta", + "@labelTemplate": {}, + "labelSelectTemplate": "Seleccione Plantilla de Etiqueta", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Seleccionar impresora de etiqueta", + "@labelSelectPrinter": {}, + "language": "Idioma", + "@language": {}, + "languageDefault": "Idioma predeterminado del sistema", + "@languageDefault": {}, + "languageSelect": "Seleccionar idioma", + "@languageSelect": {}, + "lastStocktake": "Último inventario", + "@lastStocktake": {}, + "lastUpdated": "Última actualización", + "@lastUpdated": {}, + "level": "Nivel", + "@level": {}, + "lineItemAdd": "Agregar Línea de Pedido", + "@lineItemAdd": {}, + "lineItem": "Artículo del pedido", + "@lineItem": {}, + "lineItems": "Ítems de línea", + "@lineItems": {}, + "lineItemUpdated": "Línea de Pedido Actualizada", + "@lineItemUpdated": {}, + "locateItem": "Localizar artículo de stock", + "@locateItem": {}, + "locateLocation": "Localizar ubicación de stock", + "@locateLocation": {}, + "locationCreate": "Nueva ubicación", + "@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", + "@locationUpdated": {}, + "login": "Iniciar sesión", + "@login": {}, + "loginEnter": "Introduzca los datos de inicio de sesión", + "@loginEnter": {}, + "loginEnterDetails": "Nombre de usuario y contraseña no se almacenan localmente", + "@loginEnterDetails": {}, + "link": "Enlace", + "@link": {}, + "lost": "Perdido", + "@lost": {}, + "manufacturerPart": "Fabricante de la Parte", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Editar Parte del Fabricante", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Número de pieza del fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "missingData": "Faltan datos", + "@missingData": {}, + "name": "Nombre", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "No conectado", + "@notConnected": {}, + "notes": "Notas", + "@notes": { + "description": "Notes" + }, + "notifications": "Notificaciones", + "@notifications": {}, + "notificationsEmpty": "No hay notificaciones sin leer", + "@notificationsEmpty": {}, + "noResponse": "No hay respuesta del servidor", + "@noResponse": {}, + "noResults": "Sin resultados", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Número incorrecto", + "@numberInvalid": {}, + "onOrder": "En pedido", + "@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": "Orientación Horizontal", + "@orientationLandscape": {}, + "orientationPortrait": "Vertical", + "@orientationPortrait": {}, + "orientationSystem": "Sistema", + "@orientationSystem": {}, + "outstanding": "Pendiente", + "@outstanding": {}, + "outstandingOrderDetail": "Mostrar pedidos destacados", + "@outstandingOrderDetail": {}, + "overdue": "Vencido", + "@overdue": {}, + "overdueDetail": "Mostrar pedidos vencidos", + "@overdueDetail": {}, + "packaging": "Empaquetado", + "@packaging": {}, + "packageName": "Nombre del paquete", + "@packageName": {}, + "parameters": "Parámetros", + "@parameters": {}, + "parametersSettingDetail": "Mostrar parámetros de partes", + "@parametersSettingDetail": {}, + "parent": "Superior", + "@parent": {}, + "parentCategory": "Categoría superior", + "@parentCategory": {}, + "parentLocation": "Ubicación superior", + "@parentLocation": {}, + "part": "Pieza", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nueva pieza", + "@partCreate": {}, + "partCreateDetail": "Crear nueva pieza en esta categoría", + "@partCreateDetail": {}, + "partEdited": "Pieza actualizada", + "@partEdited": {}, + "parts": "Piezas", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Parte no marcada como vendible", + "@partNotSalable": {}, + "partsNone": "Sin piezas", + "@partsNone": {}, + "partNoResults": "No hay piezas que coincidan", + "@partNoResults": {}, + "partPricing": "Precio de parte", + "@partPricing": {}, + "partPricingSettingDetail": "Mostrar información de precios de parte", + "@pricingSettingDetail": {}, + "partSettings": "Configuración de partes", + "@partSettings": {}, + "partsStarred": "Piezas destacadas", + "@partsStarred": {}, + "partsStarredNone": "No hay piezas destacadas disponibles", + "@partsStarredNone": {}, + "partSuppliers": "Proveedores de piezas", + "@partSuppliers": {}, + "partCategory": "Categoría de pieza", + "@partCategory": {}, + "partCategoryTopLevel": "Categoría de piezas de nivel superior", + "@partCategoryTopLevel": {}, + "partCategories": "Categorías de piezas", + "@partCategories": {}, + "partDetails": "Detalle de piezas", + "@partDetails": {}, + "partNotes": "Notas de la pieza", + "@partNotes": {}, + "partStock": "Stock de piezas", + "@partStock": { + "description": "part stock" + }, + "password": "Contraseña", + "@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", + "@permissionRequired": {}, + "phone": "Teléfono", + "@phone": {}, + "printLabel": "Imprimir etiqueta", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Impresora", + "@pluginPrinter": {}, + "pluginSupport": "Soporte de plugins habilitado", + "@pluginSupport": {}, + "pluginSupportDetail": "El servidor soporta plugins personalizados", + "@pluginSupportDetail": {}, + "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 al servidor", + "@profileConnect": {}, + "profileEdit": "Editar perfil del servidor", + "@profileEdit": {}, + "profileDelete": "Borrar perfil del servidor", + "@profileDelete": {}, + "profileLogout": "Cerrar sesión", + "@profileLogout": {}, + "profileName": "Nombre de Perfil", + "@profileName": {}, + "profileNone": "No hay perfiles disponibles", + "@profileNone": {}, + "profileNotSelected": "No hay perfil seleccionado", + "@profileNotSelected": {}, + "profileSelect": "Seleccionar servidor InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Seleccionar servidor o crear un nuevo perfil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Toca para crear o seleccionar un perfil", + "@profileTapToCreate": {}, + "projectCode": "Código del proyecto", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirmar Escaneo de Datos", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirmar detalles al escanear objetos", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Habilitar órdenes de compra", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Activar funcionalidad de orden de compra", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Acceso directo a la cámara", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Orden de compra", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nueva orden de compra", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Modificar orden de compra", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Ajustes de orden de compra", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Ordenes de compra", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Orden de compra actualizada", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Precio de compra", + "@purchasePrice": {}, + "quantity": "Cantidad", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Cantidad disponible", + "@quantityAvailable": {}, + "quantityEmpty": "Cantidad está vacía", + "@quantityEmpty": {}, + "quantityInvalid": "Cantidad inválida", + "@quantityInvalid": {}, + "quantityPositive": "La longitud debe ser positiva", + "@quantityPositive": {}, + "queryEmpty": "Ingresar consulta de búsqueda", + "@queryEmpty": {}, + "queryNoResults": "No hay resultados para la consulta", + "@queryNoResults": {}, + "received": "Recibido", + "@received": {}, + "receivedFilterDetail": "Mostrar artículos recibidos", + "@receivedFilterDetail": {}, + "receiveItem": "Artículo recibido", + "@receiveItem": {}, + "receivedItem": "Artículo de Stock recibido", + "@receivedItem": {}, + "reference": "Referencia", + "@reference": {}, + "refresh": "Refrescar", + "@refresh": {}, + "rotateClockwise": "Girar 90° en sentido horario", + "@rotateClockwise": {}, + "refreshing": "Actualizando", + "@refreshing": {}, + "rejected": "Rechazado", + "@rejected": {}, + "releaseNotes": "Notas de la Versión", + "@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": {}, + "responsible": "Responsable", + "@responsible": {}, + "results": "Resultados", + "@results": {}, + "request": "Solicitud", + "@request": {}, + "requestFailed": "Solicitud fallida", + "@requestFailed": {}, + "requestSuccessful": "Solicitud realizada", + "@requestSuccessful": {}, + "requestingData": "Solicitando datos", + "@requestingData": {}, + "required": "Requerido", + "@required": { + "description": "This field is required" + }, + "response400": "Solicitud errónea", + "@response400": {}, + "response401": "No autorizado", + "@response401": {}, + "response403": "Permiso dengado", + "@response403": {}, + "response404": "Recurso no encontrado.", + "@response404": {}, + "response405": "Método no permitido", + "@response405": {}, + "response429": "Demasiadas Solicitudes", + "@response429": {}, + "response500": "Error interno del servidor", + "@response500": {}, + "response501": "No Implementado", + "@response501": {}, + "response502": "Puerta de Enlace Incorrecta", + "@response502": {}, + "response503": "Servicio no disponible", + "@response503": {}, + "response504": "Tiempo de Espera de Puerta de Enlace Agotado", + "@response504": {}, + "response505": "Versión de HTTP no compatible", + "@response505": {}, + "responseData": "Respuesta de datos", + "@responseData": {}, + "responseInvalid": "Código de respuesta inválido", + "@responseInvalid": {}, + "responseUnknown": "Respuesta desconocida", + "@responseUnknown": {}, + "result": "Resultado", + "@result": { + "description": "" + }, + "returned": "Devuelto", + "@returned": {}, + "salesOrder": "Orden de venta", + "@salesOrder": {}, + "salesOrders": "Órdenes de venta", + "@salesOrders": {}, + "salesOrderEnable": "Activar órdenes de venta", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Activar funcionalidad de orden de ventas", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Acceso directo a la cámara", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de ventas", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Ajustes de órdenes de ventas", + "@salesOrderSettings": {}, + "salesOrderCreate": "Nueva orden de venta", + "@saleOrderCreate": {}, + "salesOrderEdit": "Editar orden de venta", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Orden de venta actualizada", + "@salesOrderUpdated": {}, + "save": "Guardar", + "@save": { + "description": "Save" + }, + "scanBarcode": "Escanear código de barras", + "@scanBarcode": {}, + "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": "Escáner externo", + "@scannerExternal": {}, + "scannerExternalDetail": "Usar escáner externo para leer códigos de barras (modo cuña)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Escanear partes recibidas", + "@scanReceivedParts": {}, + "search": "Buscar", + "@search": { + "description": "search" + }, + "searching": "Buscando", + "@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", + "@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": {}, + "serialNumbers": "Números de serie", + "@serialNumbers": {}, + "server": "Servidor", + "@server": {}, + "serverAddress": "Dirección del servidor", + "@serverAddress": {}, + "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 con el 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": {}, + "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", + "@sku": {}, + "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": {}, + "startDate": "Fecha de inicio", + "@startDate": {}, + "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": "Ubicación 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": {}, + "submitFeedback": "Enviar comentarios", + "@submitFeedback": {}, + "suppliedParts": "Piezas suministradas", + "@suppliedParts": {}, + "supplier": "Proveedor", + "@supplier": {}, + "supplierPart": "Pieza del proveedor", + "@supplierPart": {}, + "supplierPartEdit": "Editar Pieza del Proveedor", + "@supplierPartEdit": {}, + "supplierPartNumber": "Número de pieza del proveedor", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Pieza del proveedor actualizada", + "@supplierPartUpdated": {}, + "supplierParts": "Piezas del Proveedor", + "@supplierParts": {}, + "suppliers": "Proveedores", + "@suppliers": {}, + "supplierReference": "Referencia del proveedor", + "@supplierReference": {}, + "switchCamera": "Cambiar Cámara", + "@switchCamera": {}, + "takePicture": "Hacer una foto", + "@takePicture": {}, + "targetDate": "Fecha objetivo", + "@targetDate": {}, + "templatePart": "Plantilla de pieza", + "@templatePart": {}, + "testName": "Nombre de prueba", + "@testName": {}, + "testPassedOrFailed": "Prueba superada o fallida", + "@testPassedOrFailed": {}, + "testsRequired": "Pruebas requeridas", + "@testsRequired": {}, + "testResults": "Resultados de la Prueba", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Mostrar los resultados de prueba de artículos de stock", + "@testResultsDetail": {}, + "testResultAdd": "Añadir Resultado de Prueba", + "@testResultAdd": {}, + "testResultNone": "No hay resultados de la prueba", + "@testResultNone": {}, + "testResultNoneDetail": "No hay resultados disponibles", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error al cargar el resultado de la prueba", + "@testResultUploadFail": {}, + "testResultUploadPass": "Resultado de prueba subido", + "@testResultUploadPass": {}, + "timeout": "Tiempo de espera superado", + "@timeout": { + "description": "" + }, + "toggleTorch": "Linterna", + "@toggleTorch": {}, + "tokenError": "Error de Token", + "@tokenError": {}, + "tokenMissing": "Falta el token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Falta el token de acceso de la respuesta", + "@tokenMissingFromResponse": {}, + "totalPrice": "Precio total", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Transferir", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transferir Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transferir elemento a una ubicación diferente", + "@transferStockDetail": {}, + "transferStockLocation": "Transferir nueva ubicación de stock", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transferir esta ubicación de stock a otra", + "@transferStockLocationDetail": {}, + "translate": "Traducir", + "@translate": {}, + "translateHelp": "Ayuda a traducir la aplicación InvenTree", + "@translateHelp": {}, + "unavailable": "No disponible", + "@unavailable": {}, + "unavailableDetail": "Artículo no disponible", + "@unavailableDetail": {}, + "unitPrice": "Precio Unitario", + "@unitPrice": {}, + "units": "Unidades", + "@units": {}, + "unknownResponse": "Respuesta desconocida", + "@unknownResponse": {}, + "upload": "Subir", + "@upload": {}, + "uploadFailed": "Fallo al cargar el archivo", + "@uploadFailed": {}, + "uploadSuccess": "Archivo subido", + "@uploadSuccess": {}, + "uploadImage": "Subir Imagen", + "@uploadImage": {}, + "usedIn": "Usado En", + "@usedIn": {}, + "usedInDetails": "Ensamblados que requieren esta pieza", + "@usedInDetails": {}, + "username": "Nombre de usuario", + "@username": {}, + "usernameEmpty": "El nombre de usuario no puede estar vacío", + "@usernameEmpty": {}, + "value": "Valor", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "El valor no puede estar vacío", + "@valueCannotBeEmpty": {}, + "valueRequired": "El valor es requerido", + "@valueRequired": {}, + "variants": "Variantes", + "@variants": {}, + "version": "Versión", + "@version": {}, + "viewSupplierPart": "Ver pieza del proveedor", + "@viewSupplierPart": {}, + "website": "Sitio Web", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "price": "Precio", + "@price": {}, + "priceRange": "Rango de precios", + "@priceRange": {}, + "priceOverrideMin": "Reemplazo del precio mínimo", + "@priceOverrideMin": {}, + "priceOverrideMax": "Reemplazo del precio máximo", + "@priceOverrideMax": {}, + "salePrice": "Precio de Venta", + "@salePrice": {}, + "saleHistory": "Historial de ventas", + "@saleHistory": {}, + "supplierPricing": "Precio del Proveedor", + "@supplierPricing": {}, + "bomCost": "Coste BOM", + "@bomCost": {}, + "internalCost": "Coste Interno", + "@internalCost": {}, + "variantCost": "Coste de variante", + "@variantCost": {}, + "overallPricing": "Precio global", + "@overallPricing": {}, + "pricingOverrides": "Anulaciones de precios", + "@pricingOverrides": {}, + "currency": "Divisa", + "@currency": {}, + "priceBreaks": "Diferenciales de precios", + "@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 new file mode 100644 index 0000000..1ea7ace --- /dev/null +++ b/lib/l10n/es_MX/app_es_MX.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "es-MX", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Acerca de", + "@about": {}, + "accountDetails": "Detalle de la Cuenta", + "@accountDetails": {}, + "actions": "Acciones", + "@actions": { + "description": "" + }, + "actionsNone": "No hay acciones disponibles", + "@actionsNone": {}, + "add": "Añadir", + "@add": { + "description": "add" + }, + "addStock": "Añadir Inventario", + "@addStock": { + "description": "add stock" + }, + "address": "Dirección", + "@address": {}, + "appAbout": "Acerca de InvenTree", + "@appAbout": {}, + "appCredits": "Créditos Adicionales de la app", + "@appCredits": {}, + "appDetails": "Detalles de la app", + "@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": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Mostrar notas de versión de la aplicación", + "@appReleaseNotes": {}, + "appSettings": "Ajustes de aplicación", + "@appSettings": {}, + "appSettingsDetails": "Configurar ajustes de la aplicación InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Asignado a mí", + "@assignedToMe": {}, + "assignedToMeDetail": "Mostrar pedidos asignados a mí", + "@assignedToMeDetail": {}, + "attachments": "Adjuntos", + "@attachments": {}, + "attachImage": "Adjuntar Imagen", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "No se encontraron adjuntos", + "@attachmentNone": {}, + "attachmentNoneDetail": "No se encontraron archivos adjuntos", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Seleccionar archivo adjunto", + "@attachmentSelect": {}, + "attention": "Atención", + "@attention": {}, + "available": "Disponible", + "@available": {}, + "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", + "@barcodeAssignDetail": {}, + "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 hash 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": {}, + "barcodeScanPart": "Escanear código de barras de parte", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Escanear código de barras para recibir parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Escaneo de código de barras en pausa", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Escanear para asignar código de barras", + "@barcodeScanAssign": {}, + "barcodeScanController": "Entrada de escáner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Seleccionar fuente de entrada del escáner de código de barras", + "@barcodeScanControllerDetail": {}, + "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", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear ubicación de Inventario", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Modo de escaneo único", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pausar el escáner de código de barras después de cada escaneado", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Escaneado en la ubicación", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Artículo no escaneado en", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Escanear artículo de inventario", + "@barcodeScanItem": {}, + "barcodeTones": "Tonos de código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Desasignar código de barras", + "@barcodeUnassign": {}, + "barcodeUnknown": "El código de barras no res econocido", + "@barcodeUnknown": {}, + "batchCode": "Código de lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiales", + "@billOfMaterials": {}, + "bom": "Lista de materiales", + "@bom": {}, + "bomEnable": "Mostrar Lista de Materiales", + "@bomEnable": {}, + "build": "Construir", + "@build": {}, + "building": "Construyendo", + "@building": {}, + "cameraCreationError": "No se pudo abrir el controlador de la cámara", + "@cameraCreationError": {}, + "cameraInternal": "Cámara interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Usar cámara interna para leer códigos de barras", + "@cameraInternalDetail": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancelar orden", + "@cancelOrder": {}, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nueva Categoría", + "@categoryCreate": {}, + "categoryCreateDetail": "Crear nueva categoría de partes", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoría actualizada", + "@categoryUpdated": {}, + "company": "Empresa", + "@company": {}, + "companyAdd": "Agregar empresa", + "@companyAdd": {}, + "companyEdit": "Modificar Empresa", + "@companyEdit": {}, + "companyNoResults": "No hay empresas que coincidan con la consulta", + "@companyNoResults": {}, + "companyUpdated": "Detalles de la empresa actualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Fecha de finalización", + "@completionDate": {}, + "configureServer": "Configurar ajustes del servidor", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Cantidad de inventario", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Cliente", + "@customer": {}, + "customers": "Clientes", + "@customers": {}, + "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", + "@darkModeEnable": {}, + "delete": "Eliminar", + "@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", + "@destination": {}, + "destroyed": "Destruido", + "@destroyed": {}, + "details": "Detalles", + "@details": { + "description": "details" + }, + "documentation": "Documentación", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Descargando archivo", + "@downloading": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editAttachment": "Editar archivo adjunto", + "@editAttachment": {}, + "editCategory": "Editar categoría", + "@editCategory": {}, + "editLocation": "Editar ubicación", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editParameter": "Editar parámetro", + "@editParameter": {}, + "editPart": "Editar Parte", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar artículo de stock", + "@editItem": {}, + "editLineItem": "Editar artículo de línea", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Subir informes de errores anónimos y registros de errores", + "@errorReportUploadDetails": {}, + "expiryDate": "Fecha de Expiración", + "@expiryDate": {}, + "expiryExpired": "Expirado", + "@expiryExpired": {}, + "expiryStale": "Obsoleto", + "@expiryStale": {}, + "extraLineItem": "Partida extra", + "@extraLineItem": {}, + "extraLineItems": "Partidas extra", + "@extraLineItems": {}, + "feedback": "Comentarios", + "@feedback": {}, + "feedbackError": "Error al enviar comentarios", + "@feedbackError": {}, + "feedbackSuccess": "Comentarios enviados", + "@feedbackSuccess": {}, + "filterActive": "Activo", + "@filterActive": {}, + "filterActiveDetail": "Mostrar partes activas", + "@filterActiveDetail": {}, + "filterAssembly": "Ensamblado", + "@filterAssembly": {}, + "filterAssemblyDetail": "Mostrar partes ensambladas", + "@filterAssemblyDetail": {}, + "filterComponent": "Componente", + "@filterComponent": {}, + "filterComponentDetail": "Mostrar partes del componente", + "@filterComponentDetail": {}, + "filterExternal": "Externo", + "@filterExternal": {}, + "filterExternalDetail": "Mostrar existencias en ubicaciones exteriores", + "@filterExternalDetail": {}, + "filterInStock": "En Existencia", + "@filterInStock": {}, + "filterInStockDetail": "Mostrar partes que tienen existencias", + "@filterInStockDetail": {}, + "filterSerialized": "Serializado", + "@filterSerialized": {}, + "filterSerializedDetail": "Mostrar elementos de inventario serializados", + "@filterSerializedDetail": {}, + "filterTemplate": "Plantilla", + "@filterTemplate": {}, + "filterTemplateDetail": "Mostrar partes de plantilla", + "@filterTemplateDetail": {}, + "filterTrackable": "Rastreable", + "@filterTrackable": {}, + "filterTrackableDetail": "Mostrar partes rastreables", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Mostrar partes virtuales", + "@filterVirtualDetail": {}, + "filteringOptions": "Opciones de filtro", + "@filteringOptions": {}, + "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" + }, + "home": "Inicio", + "@home": {}, + "homeScreen": "Pantalla de Inicio", + "@homeScreen": {}, + "homeScreenSettings": "Configurar ajustes de la pantalla de inicio", + "@homeScreenSettings": {}, + "homeShowPo": "Mostrar órdenes de compra", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Partes Suscritas", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostrar las partes suscritas en la página principal", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Esta empresa está marcada como inactiva", + "@inactiveCompany": {}, + "inactiveDetail": "Esta parte está marcada como inactiva", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir subcategorias", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar resultados de subcategorías", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incluir sub-ubicaciones", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar resultados de sub-ubicaciones", + "@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 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", + "@invalidHostDetails": {}, + "invalidPart": "Parte inválida", + "@invalidPart": {}, + "invalidPartCategory": "Categoría de parte inválida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ubicación de inventario inválida", + "@invalidStockLocation": {}, + "invalidStockItem": "Artículo de inventario inválido", + "@invalidStockItem": {}, + "invalidSupplierPart": "Parte de proveedor inválida", + "@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", + "@issueDate": {}, + "issueOrder": "Emitir pedido", + "@issueOrder": {}, + "itemInLocation": "El artículo ya está en la ubicación", + "@itemInLocation": {}, + "itemDeleted": "El artículo ha sido eliminado", + "@itemDeleted": {}, + "itemUpdated": "Artículo actualizado", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Plantilla de etiqueta", + "@labelTemplate": {}, + "labelSelectTemplate": "Seleccionar Plantilla de Etiqueta", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Seleccionar Impresora de Etiqueta", + "@labelSelectPrinter": {}, + "language": "Idioma", + "@language": {}, + "languageDefault": "Idioma por defecto del sistema", + "@languageDefault": {}, + "languageSelect": "Seleccionar idioma", + "@languageSelect": {}, + "lastStocktake": "Último inventario", + "@lastStocktake": {}, + "lastUpdated": "Última actualización", + "@lastUpdated": {}, + "level": "Nivel", + "@level": {}, + "lineItemAdd": "Añadir Artículo de Línea", + "@lineItemAdd": {}, + "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", + "@locateLocation": {}, + "locationCreate": "Nueva ubicación", + "@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", + "@locationUpdated": {}, + "login": "Iniciar sesión", + "@login": {}, + "loginEnter": "Ingresar datos de acceso", + "@loginEnter": {}, + "loginEnterDetails": "Nombre de usuario y contraseña no se almacenan localmente", + "@loginEnterDetails": {}, + "link": "Vincular", + "@link": {}, + "lost": "Perdido", + "@lost": {}, + "manufacturerPart": "Pieza de Fabricante", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Editar Pieza de Fabricante", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Número de parte del fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "missingData": "Datos faltantes", + "@missingData": {}, + "name": "Nombre", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "No conectado", + "@notConnected": {}, + "notes": "Notas", + "@notes": { + "description": "Notes" + }, + "notifications": "Notificaciones", + "@notifications": {}, + "notificationsEmpty": "No hay notificaciones sin leer", + "@notificationsEmpty": {}, + "noResponse": "Sin respuesta del servidor", + "@noResponse": {}, + "noResults": "Sin resultados", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Número inválido", + "@numberInvalid": {}, + "onOrder": "En pedido", + "@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 pedidos destacados", + "@outstandingOrderDetail": {}, + "overdue": "Vencido", + "@overdue": {}, + "overdueDetail": "Mostrar pedidos vencidos", + "@overdueDetail": {}, + "packaging": "Embalaje", + "@packaging": {}, + "packageName": "Nombre de Paquete", + "@packageName": {}, + "parameters": "Parámetros", + "@parameters": {}, + "parametersSettingDetail": "Mostrar parámetros de parte", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Parte no marcada como vendible", + "@partNotSalable": {}, + "partsNone": "Sin Partes", + "@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", + "@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": "Inventario de parte", + "@partStock": { + "description": "part stock" + }, + "password": "Contraseña", + "@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", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "printLabel": "Imprimir etiqueta", + "@printLabel": {}, + "plugin": "Complemento", + "@plugin": {}, + "pluginPrinter": "Impresora", + "@pluginPrinter": {}, + "pluginSupport": "Soporte de complementos habilitado", + "@pluginSupport": {}, + "pluginSupportDetail": "El servidor soporta complementos personalizados", + "@pluginSupportDetail": {}, + "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": {}, + "profileLogout": "Cerrar sesión", + "@profileLogout": {}, + "profileName": "Nombre de perfil", + "@profileName": {}, + "profileNone": "No hay perfiles disponibles", + "@profileNone": {}, + "profileNotSelected": "Ningún perfil seleccionado", + "@profileNotSelected": {}, + "profileSelect": "Seleccionar servidor de InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Seleccione el servidor o cree un nuevo perfil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Toca para crear o seleccionar un perfil", + "@profileTapToCreate": {}, + "projectCode": "Código del proyecto", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirmar Escaneo", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirmar detalles al escanear artículos", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Habilitar órdenes de compra", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Habilitar funcionalidad de orden de compra", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Acceso directo a la cámara", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Orden de compra", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nueva orden de compra", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Modificar orden de compra", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Ajustes de la orden de compra", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Órdenes de compra", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Orden de compra actualizada", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Precio de compra", + "@purchasePrice": {}, + "quantity": "Cantidad", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Cantidad disponible", + "@quantityAvailable": {}, + "quantityEmpty": "La cantidad está vacía", + "@quantityEmpty": {}, + "quantityInvalid": "La cantidad no es válida", + "@quantityInvalid": {}, + "quantityPositive": "La cantidad debe ser positiva", + "@quantityPositive": {}, + "queryEmpty": "Ingresar consulta de búsqueda", + "@queryEmpty": {}, + "queryNoResults": "No hay resultados para la consulta", + "@queryNoResults": {}, + "received": "Recibido", + "@received": {}, + "receivedFilterDetail": "Mostrar artículos recibidos", + "@receivedFilterDetail": {}, + "receiveItem": "Recibir artículo", + "@receiveItem": {}, + "receivedItem": "Recibir artículo de inventario", + "@receivedItem": {}, + "reference": "Referencia", + "@reference": {}, + "refresh": "Actualizar", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "Actualizando", + "@refreshing": {}, + "rejected": "Rechazado", + "@rejected": {}, + "releaseNotes": "Notas de lanzamiento", + "@releaseNotes": {}, + "remove": "Eliminar", + "@remove": { + "description": "remove" + }, + "removeStock": "Eliminar inventario", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Reportar un error", + "@reportBug": {}, + "reportBugDescription": "Enviar informe de error (requiere cuenta de GitHub)", + "@reportBugDescription": {}, + "responsible": "Responsable", + "@responsible": {}, + "results": "Resultados", + "@results": {}, + "request": "Solicitud", + "@request": {}, + "requestFailed": "Solicitud fallida", + "@requestFailed": {}, + "requestSuccessful": "Solicitud exitosa", + "@requestSuccessful": {}, + "requestingData": "Solicitar datos", + "@requestingData": {}, + "required": "Requerido", + "@required": { + "description": "This field is required" + }, + "response400": "Solicitud incorrecta", + "@response400": {}, + "response401": "No autorizado", + "@response401": {}, + "response403": "Permiso denegado", + "@response403": {}, + "response404": "Recurso no encontrado", + "@response404": {}, + "response405": "Método no permitido", + "@response405": {}, + "response429": "Demasiadas solicitudes", + "@response429": {}, + "response500": "Error interno del servidor", + "@response500": {}, + "response501": "No implementado", + "@response501": {}, + "response502": "Puerta de enlace incorrecta", + "@response502": {}, + "response503": "Servicio no disponible", + "@response503": {}, + "response504": "Tiempo de Espera de Puerta de Enlace Agotado", + "@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": {}, + "salesOrder": "Orden de venta", + "@salesOrder": {}, + "salesOrders": "Órdenes de venta", + "@salesOrders": {}, + "salesOrderEnable": "Activar pedidos de venta", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Habilitar funcionalidad de orden de ventas", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Acceso directo a la cámara", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Activar acceso directo a la imagen en la pantalla de pedido", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Ajustes del pedido de ventas", + "@salesOrderSettings": {}, + "salesOrderCreate": "Nueva orden de venta", + "@saleOrderCreate": {}, + "salesOrderEdit": "Editar orden de venta", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Orden de venta actualizada", + "@salesOrderUpdated": {}, + "save": "Guardar", + "@save": { + "description": "Save" + }, + "scanBarcode": "Escanear código de barras", + "@scanBarcode": {}, + "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": "Escáner externo", + "@scannerExternal": {}, + "scannerExternalDetail": "Usar escáner externo para leer códigos de barras (modo cuña)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Escanear partes recibidas", + "@scanReceivedParts": {}, + "search": "Buscar", + "@search": { + "description": "search" + }, + "searching": "Buscando", + "@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", + "@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": {}, + "serialNumbers": "Números de serie", + "@serialNumbers": {}, + "server": "Servidor", + "@server": {}, + "serverAddress": "Dirección del servidor", + "@serverAddress": {}, + "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 HTTPS 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 de 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": {}, + "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": "Deseleccionar Envío", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Mark this shipment as unchecked", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Shipment Updated", + "@shipmentUpdated": {}, + "shipped": "Enviado", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sonidos", + "@sounds": {}, + "soundOnBarcodeAction": "Reproducir un tono audible en la acción de código de barras", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Reproducir un tono audible en error del servidor", + "@soundOnServerError": {}, + "startDate": "Fecha de inicio", + "@startDate": {}, + "status": "Estado", + "@status": {}, + "statusCode": "Código de estado", + "@statusCode": {}, + "stock": "Inventario", + "@stock": { + "description": "stock" + }, + "stockDetails": "Cantidad actual de inventario disponible", + "@stockDetails": {}, + "stockItem": "Artículo de stock", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Artículos 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": "Ubicación del 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": "Sub-ubicación", + "@sublocation": {}, + "sublocations": "Sub-ubicaciones", + "@sublocations": {}, + "sublocationNone": "Sin sub-ubicaciones", + "@sublocationNone": {}, + "sublocationNoneDetail": "No hay sub-ubicaciones disponibles", + "@sublocationNoneDetail": {}, + "submitFeedback": "Enviar comentarios", + "@submitFeedback": {}, + "suppliedParts": "Partes suministradas", + "@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", + "@supplierReference": {}, + "switchCamera": "Cambiar Cámara", + "@switchCamera": {}, + "takePicture": "Tomar una foto", + "@takePicture": {}, + "targetDate": "Fecha objetivo", + "@targetDate": {}, + "templatePart": "Parte de la plantilla padre", + "@templatePart": {}, + "testName": "Nombre de prueba", + "@testName": {}, + "testPassedOrFailed": "Prueba pasada o fallida", + "@testPassedOrFailed": {}, + "testsRequired": "Pruebas requeridas", + "@testsRequired": {}, + "testResults": "Resultados de la prueba", + "@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 prueba", + "@testResultNone": {}, + "testResultNoneDetail": "No hay resultados de prueba disponibles", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Error al cargar el resultado de prueba", + "@testResultUploadFail": {}, + "testResultUploadPass": "Resultado de prueba cargado", + "@testResultUploadPass": {}, + "timeout": "Tiempo de espera superado", + "@timeout": { + "description": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Error de Token", + "@tokenError": {}, + "tokenMissing": "Falta el token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Falta el token de acceso de la respuesta", + "@tokenMissingFromResponse": {}, + "totalPrice": "Precio total", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Transferir", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transferir Stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transferir elemento a una ubicación diferente", + "@transferStockDetail": {}, + "transferStockLocation": "Transferir ubicación del stock", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transferir esta ubicación de stock a otra", + "@transferStockLocationDetail": {}, + "translate": "Traducir", + "@translate": {}, + "translateHelp": "Ayuda a traducir la aplicación InvenTree", + "@translateHelp": {}, + "unavailable": "No disponible", + "@unavailable": {}, + "unavailableDetail": "Artículo no disponible", + "@unavailableDetail": {}, + "unitPrice": "Precio unitario", + "@unitPrice": {}, + "units": "Unidades", + "@units": {}, + "unknownResponse": "Respuesta desconocida", + "@unknownResponse": {}, + "upload": "Subir", + "@upload": {}, + "uploadFailed": "Error al subir el archivo", + "@uploadFailed": {}, + "uploadSuccess": "Archivo subido", + "@uploadSuccess": {}, + "uploadImage": "Subir Imagen", + "@uploadImage": {}, + "usedIn": "Usado en", + "@usedIn": {}, + "usedInDetails": "Ensambles que requieren esta parte", + "@usedInDetails": {}, + "username": "Nombre de usuario", + "@username": {}, + "usernameEmpty": "El campo de nombre de usuario no puede estar vacío", + "@usernameEmpty": {}, + "value": "Valor", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "El valor no puede estar vacío", + "@valueCannotBeEmpty": {}, + "valueRequired": "El valor es requerido", + "@valueRequired": {}, + "variants": "Variantes", + "@variants": {}, + "version": "Versión", + "@version": {}, + "viewSupplierPart": "Ver Parte de Proveedor", + "@viewSupplierPart": {}, + "website": "Sitio web", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..3616a21 --- /dev/null +++ b/lib/l10n/et_EE/app_et_EE.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Jaota laoseis", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "Rakenduse sätted", + "@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", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Manust pole", + "@attachmentNone": {}, + "attachmentNoneDetail": "Manuseid ei leitud", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Valige manus", + "@attachmentSelect": {}, + "attention": "Tähelepanu", + "@attention": {}, + "available": "Saadaval", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "Vöötkoodid", + "@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 to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan to assign barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Skänneri sisend", + "@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": "Ehita", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Muuda ettevõtet", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Ettevõtted", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Seadista serveri seadeid", + "@configureServer": {}, + "confirmScan": "Kinnita ülekanne", + "@confirmScan": {}, + "confirmScanDetail": "Kinnitage laoseisu ülekande üksikasjad vöötkoodide skaneerimisel", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Kogus", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Klient", + "@customer": {}, + "customers": "Kliendid", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Kahjustatud", + "@damaged": {}, + "colorScheme": "Värviskeem", + "@colorScheme": {}, + "colorSchemeDetail": "Vali värviskeem", + "@colorSchemeDetail": {}, + "darkMode": "Tume režiim", + "@darkMode": {}, + "darkModeEnable": "Lülita tume režiim sisse", + "@darkModeEnable": {}, + "delete": "Kustuta", + "@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", + "@destination": {}, + "destroyed": "Hävitatud", + "@destroyed": {}, + "details": "Üksikasjad", + "@details": { + "description": "details" + }, + "documentation": "Dokumendid", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Faili allalaadimine", + "@downloading": {}, + "edit": "Muuda", + "@edit": { + "description": "edit" + }, + "editAttachment": "Muuda manust", + "@editAttachment": {}, + "editCategory": "Muuda kategooriat", + "@editCategory": {}, + "editLocation": "Muuda asukohta", + "@editLocation": {}, + "editNotes": "Muuda märkmeid", + "@editNotes": {}, + "editParameter": "Muuda parameetrit", + "@editParameter": {}, + "editPart": "Muuda osa", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Sisesta parool", + "@enterPassword": {}, + "enterUsername": "Sisesta kasutajanimi", + "@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": {}, + "expiryDate": "Aegumise kuupäev", + "@expiryDate": {}, + "expiryExpired": "Aegunud", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "Tagasiside", + "@feedback": {}, + "feedbackError": "Error submitting feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback submitted", + "@feedbackSuccess": {}, + "filterActive": "Aktiivne", + "@filterActive": {}, + "filterActiveDetail": "Show active parts", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponent", + "@filterComponent": {}, + "filterComponentDetail": "Show component parts", + "@filterComponentDetail": {}, + "filterExternal": "Väline", + "@filterExternal": {}, + "filterExternalDetail": "Show stock in external locations", + "@filterExternalDetail": {}, + "filterInStock": "Laos", + "@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": "Virtuaalne", + "@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": "Ajalugu", + "@history": { + "description": "history" + }, + "home": "Avaleht", + "@home": {}, + "homeScreen": "Koduekraan", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Subscribed Parts", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Show subscribed parts on home screen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Näita tarnijaid", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Näita avalehel tarnijate nuppu", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Näita tootjaid", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Näita avalehel tootjate nuppu", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Näita kliente", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Näita avalehel klientide nuppu", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Pildi üleslaadimine ebaõnnestus", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Pilt on üles laaditud", + "@imageUploadSuccess": {}, + "inactive": "Mitteaktiivne", + "@inactive": {}, + "inactiveCompany": "See ettevõte on märgitud mitteaktiivseks", + "@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": "Sisemine osa", + "@internalPart": {}, + "invalidHost": "Vigane hostinimi", + "@invalidHost": {}, + "invalidHostDetails": "Provided hostname is not valid", + "@invalidHostDetails": {}, + "invalidPart": "Vigane osa", + "@invalidPart": {}, + "invalidPartCategory": "Vigane osa kategooria", + "@invalidPartCategory": {}, + "invalidStockLocation": "Invalid Stock Location", + "@invalidStockLocation": {}, + "invalidStockItem": "Invalid Stock Item", + "@invalidStockItem": {}, + "invalidSupplierPart": "Invalid Supplier Part", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Invalid username / password combination", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Märksõnad", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "language": "Keel", + "@language": {}, + "languageDefault": "Süsteemi vaikimisi keel", + "@languageDefault": {}, + "languageSelect": "Vali keel", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Tase", + "@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": "Uus asukoht", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Logi sisse", + "@login": {}, + "loginEnter": "Enter login details", + "@loginEnter": {}, + "loginEnterDetails": "Username and password are not stored locally", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Kadunud", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Tootja", + "@manufacturer": {}, + "manufacturers": "Tootjad", + "@manufacturers": {}, + "missingData": "Puuduvad andmed", + "@missingData": {}, + "name": "Nimi", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Pole ühendatud", + "@notConnected": {}, + "notes": "Märkmed", + "@notes": { + "description": "Notes" + }, + "notifications": "Teavitused", + "@notifications": {}, + "notificationsEmpty": "Lugemata teavitusi pole", + "@notificationsEmpty": {}, + "noResponse": "Server ei vasta", + "@noResponse": {}, + "noResults": "Tulemusi pole", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Vigane number", + "@numberInvalid": {}, + "onOrder": "Tellimisel", + "@onOrder": {}, + "onOrderDetails": "Items currently on order", + "@onOrderDetails": {}, + "orientation": "Ekraani suund", + "@orientation": {}, + "orientationDetail": "Ekraani suund (nõuab restarti)", + "@orientationDetail": {}, + "orientationLandscape": "Horisontaalne", + "@orientationLandscape": {}, + "orientationPortrait": "Vertikaalne", + "@orientationPortrait": {}, + "orientationSystem": "Süsteem", + "@orientationSystem": {}, + "outstanding": "Outstanding", + "@outstanding": {}, + "outstandingOrderDetail": "Show outstanding orders", + "@outstandingOrderDetail": {}, + "overdue": "Üle tähtaja", + "@overdue": {}, + "overdueDetail": "Show overdue orders", + "@overdueDetail": {}, + "packaging": "Pakkimine", + "@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)" + }, + "partCreate": "Uus osa", + "@partCreate": {}, + "partCreateDetail": "Loo selles kategoorias uus osa", + "@partCreateDetail": {}, + "partEdited": "Osa on uuendatud", + "@partEdited": {}, + "parts": "Osad", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "No Parts", + "@partsNone": {}, + "partNoResults": "No parts matching query", + "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": "Osa kategooriad", + "@partCategories": {}, + "partDetails": "Osa info", + "@partDetails": {}, + "partNotes": "Osa märkmed", + "@partNotes": {}, + "partStock": "Part Stock", + "@partStock": { + "description": "part stock" + }, + "password": "Parool", + "@password": {}, + "passwordEmpty": "Password cannot be empty", + "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Teie kontol ei ole vajalikke õigusi selle toimingu sooritamiseks", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "printLabel": "Prindi silt", + "@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": "Profiil", + "@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": "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", + "@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", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Kogus", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantity Available", + "@quantityAvailable": {}, + "quantityEmpty": "Kogus on tühi", + "@quantityEmpty": {}, + "quantityInvalid": "Kogus on vigane", + "@quantityInvalid": {}, + "quantityPositive": "Kogus peab olema positiivne", + "@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": "Viide", + "@reference": {}, + "refresh": "Värskenda", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "Värskendan", + "@refreshing": {}, + "rejected": "Tagasi lükatud", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Eemalda", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Report Bug", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "responsible": "Responsible", + "@responsible": {}, + "results": "Tulemused", + "@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": "Tulemus", + "@result": { + "description": "" + }, + "returned": "Tagastatud", + "@returned": {}, + "salesOrder": "Sales Order", + "@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", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Salvesta", + "@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": "Väline skänner", + "@scannerExternal": {}, + "scannerExternalDetail": "Use external scanner to read barcodes (wedge mode)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Otsi", + "@search": { + "description": "search" + }, + "searching": "Otsimine", + "@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", + "@searchStock": {}, + "select": "Vali", + "@select": {}, + "selectFile": "Vali fail", + "@selectFile": {}, + "selectImage": "Vali pilt", + "@selectImage": {}, + "selectLocation": "Vali asukoht", + "@selectLocation": {}, + "send": "Saada", + "@send": {}, + "serialNumber": "Seerianumber", + "@serialNumber": {}, + "serialNumbers": "Seerianumbrid", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveri aadress", + "@serverAddress": {}, + "serverApiRequired": "Nõutud API versioon", + "@serverApiRequired": {}, + "serverApiVersion": "Serveri API versioon", + "@serverApiVersion": {}, + "serverAuthenticationError": "Autentimise viga", + "@serverAuthenticationError": {}, + "serverCertificateError": "Sertifikaadi viga", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Serveri HTTPS sertifikaat on vigane", + "@serverCertificateInvalid": {}, + "serverConnected": "Ühendatud serveriga", + "@serverConnected": {}, + "serverConnecting": "Serveriga ühendamine", + "@serverConnecting": {}, + "serverCouldNotConnect": "Ühenduse loomine serveriga ebaõnnestus", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serveri lahter ei saa olla tühi", + "@serverEmpty": {}, + "serverError": "Serveri tõrge", + "@serverError": {}, + "serverDetails": "Serveri üksikasjad", + "@serverDetails": {}, + "serverMissingData": "Server response missing required fields", + "@serverMissingData": {}, + "serverOld": "Vana serveri versioon", + "@serverOld": {}, + "serverSettings": "Serveri seaded", + "@serverSettings": {}, + "serverStart": "Server peab algama eesliitega http[s]", + "@serverStart": {}, + "settings": "Seaded", + "@settings": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "Staatus", + "@status": {}, + "statusCode": "Olekukood", + "@statusCode": {}, + "stock": "Ladu", + "@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": "Kas olete kindel, et soovite selle üksuse kustutada?", + "@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": "Kohusta ranget HTTPS-sertifikaatide kontrollimist", + "@strictHttpsDetails": {}, + "subcategory": "Alamkategooria", + "@subcategory": {}, + "subcategories": "Alamkategooriad", + "@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": "Tarnija", + "@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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "Aegumine", + "@timeout": { + "description": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Hind kokku", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": "Aita InvenTree rakendust tõlkida", + "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Ühiku hind", + "@unitPrice": {}, + "units": "Ühikud", + "@units": {}, + "unknownResponse": "Tundmatu vastus", + "@unknownResponse": {}, + "upload": "Laadi üles", + "@upload": {}, + "uploadFailed": "Faili laadimine ebaõnnestus", + "@uploadFailed": {}, + "uploadSuccess": "Fail on üles laaditud", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Kasutajanimi", + "@username": {}, + "usernameEmpty": "Username cannot be empty", + "@usernameEmpty": {}, + "value": "Väärtus", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Väärtus ei saa olla tühi", + "@valueCannotBeEmpty": {}, + "valueRequired": "Väärtus on nõutud", + "@valueRequired": {}, + "variants": "Variandid", + "@variants": {}, + "version": "Versioon", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Koduleht", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..8cc41e9 --- /dev/null +++ b/lib/l10n/fa_IR/app_fa_IR.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "fa", + "appTitle": "اینونتری", + "@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": "درباره اینونتری", + "@appAbout": {}, + "appCredits": "", + "@appCredits": {}, + "appDetails": "جزئیات برنامه", + "@appDetails": {}, + "allocated": "اختصاص داده شده", + "@allocated": {}, + "aspectRatio16x9": "۱۶ به ۹", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "۳ به ۲", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "۴ به ۳", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "مربعی (۱ به ۱)", + "@aspectRatioSquare": {}, + "allocateStock": "موجودی اختصاص داده شده", + "@allocateStock": {}, + "allocatedStock": "موجودی اختصاص داده شده", + "@allocatedStock": {}, + "appReleaseNotes": "نمایش یادداشت های انتشار برنامه", + "@appReleaseNotes": {}, + "appSettings": "تنظیمات برنامه", + "@appSettings": {}, + "appSettingsDetails": "پیکربندی تنظیمات برنامه ", + "@appSettingsDetails": {}, + "assignedToMe": "به من اختصاص داده شده", + "@assignedToMe": {}, + "assignedToMeDetail": "نمایش سفارشاتی که به من اختصاص داده شده است", + "@assignedToMeDetail": {}, + "attachments": "پیوست ها", + "@attachments": {}, + "attachImage": "پیوست تصویر", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "پیوستی یافت نشد", + "@attachmentNone": {}, + "attachmentNoneDetail": "پیوستی یافت نشد", + "@attachmentNoneDetail": {}, + "attachmentSelect": "انتخاب پیوست", + "@attachmentSelect": {}, + "attention": "توجه", + "@attention": {}, + "available": "موجود", + "@available": {}, + "availableStock": "ذخیره موجود", + "@availableStock": {}, + "barcodes": "بارکدها", + "@barcodes": {}, + "barcodeSettings": "تنضیمات بارکد", + "@barcodeSettings": {}, + "barcodeAssign": "اضافه بارکد", + "@barcodeAssign": {}, + "barcodeAssignDetail": "ایجاد بارکد سفارشی", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "بارکد اضافه شد", + "@barcodeAssigned": {}, + "barcodeError": "خطای اسکن بارکد", + "@barcodeError": {}, + "barcodeInUse": "بارکد قبلا اضافه شده است", + "@barcodeInUse": {}, + "barcodeMissingHash": "اطلاعات هش بارکد در پاسخ موجود نیست", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "عدم وجود بارکد در سسیستم", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "بارکد اضافه نشده است", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "اسکن بارکد قطعه", + "@barcodeScanPart": {}, + "barcodeReceivePart": "برای دریافت قطعه، بارکد را اسکن کنید", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "اسکن بارکد متوقف شد", + "@barodeScanPaused": {}, + "barcodeScanPause": "برای توقف اسکن لمس کنید", + "@barcodeScanPause": {}, + "barcodeScanAssign": "برای اختصاص بارکد اسکن کنید", + "@barcodeScanAssign": {}, + "barcodeScanController": "", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "منبع ورودی اسکنر بارکد را انتخاب کنید", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "تاخیر اسکن بارکد", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "تاخیر بین اسکن بارکد", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "بارکد InvenTree را اسکن کنید", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "اقلام موجودی را در این مکان اسکن کنید", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "اسکن محل سهام", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "حالت اسکن تکی", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "پس از هر اسکن، اسکنر بارکد را متوقف کنید", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "در محل اسکن شد", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "مورد اسکن نشده است", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "اسکن اقلام سهام", + "@barcodeScanItem": {}, + "barcodeTones": "زنگ بارکد", + "@barcodeTones": {}, + "barcodeUnassign": "لغو اختصاص بارکد", + "@barcodeUnassign": {}, + "barcodeUnknown": "بارکد شناسایی نمی شود", + "@barcodeUnknown": {}, + "batchCode": "کد دسته", + "@batchCode": {}, + "billOfMaterials": "صورتحساب مواد", + "@billOfMaterials": {}, + "bom": "صورتحساب مواد", + "@bom": {}, + "bomEnable": "نمایش صورتحساب مواد", + "@bomEnable": {}, + "build": "ایجاد", + "@build": {}, + "building": "ساختمان", + "@building": {}, + "cameraCreationError": "کنترلر دوربین باز نشد", + "@cameraCreationError": {}, + "cameraInternal": "دوربین داخلی", + "@cameraInternal": {}, + "cameraInternalDetail": "دسترسی دوبین برای خواندن بارکد", + "@cameraInternalDetail": {}, + "cancel": "لغو", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "لغو سفارش", + "@cancelOrder": {}, + "category": "دسته بندی", + "@category": {}, + "categoryCreate": "دسته بندی جدید", + "@categoryCreate": {}, + "categoryCreateDetail": "دسته بندی کالای جدید", + "@categoryCreateDetail": {}, + "categoryUpdated": "دسته بندی کالا آپدیت شد", + "@categoryUpdated": {}, + "company": "شرکت", + "@company": {}, + "companyAdd": "افزودن شرکت", + "@companyAdd": {}, + "companyEdit": "ویرایش شرکت", + "@companyEdit": {}, + "companyNoResults": "شرکت پیدا نشد", + "@companyNoResults": {}, + "companyUpdated": "مشخصات شرکت آپدیت شد", + "@companyUpdated": {}, + "companies": "شرکت‌ها", + "@companies": {}, + "complete": "تکمیل", + "@complete": {}, + "completeOrder": "تکمیل سفارش", + "@completeOrder": {}, + "completionDate": "تاریخ تکمیل", + "@completionDate": {}, + "configureServer": "تنظیم شمخصات سرور", + "@configureServer": {}, + "confirmScan": "تأیید انتقال", + "@confirmScan": {}, + "confirmScanDetail": "هنگام اسکن بارکد، جزئیات انتقال سهام را تأیید کنید", + "@confirmScanDetail": {}, + "connectionRefused": "اتصال رد شد", + "@connectionRefused": {}, + "count": "تعداد", + "@count": { + "description": "Count" + }, + "countStock": "موجودی انبار", + "@countStock": { + "description": "Count Stock" + }, + "credits": "اعتبارات", + "@credits": {}, + "crop": "برش", + "@crop": {}, + "cropImage": "برش تصویر", + "@cropImage": {}, + "customer": "مشتری", + "@customer": {}, + "customers": "مشتریان", + "@customers": {}, + "customerReference": "مرجع مشتری", + "@customerReference": {}, + "damaged": "آسیب دیده", + "@damaged": {}, + "colorScheme": "طرح رنگ", + "@colorScheme": {}, + "colorSchemeDetail": "طرح رنگ را انتخاب کنید", + "@colorSchemeDetail": {}, + "darkMode": "حالت تاریک", + "@darkMode": {}, + "darkModeEnable": "فعالسازی حالت تاریک", + "@darkModeEnable": {}, + "delete": "حذف", + "@delete": {}, + "deleteFailed": "عملیات حذف ناموفق بوده است", + "@deleteFailed": {}, + "deleteImageConfirmation": "آیا مطمئن هستید که میخواهید این تصویر را حذف کنید؟", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "حذف تصویر", + "@deleteImageTooltip": {}, + "deleteImage": "حذف تصویر", + "@deleteImage": {}, + "deletePart": "حذف قسمت", + "@deletePart": {}, + "deletePartDetail": "این قطعه را از پایگاه داده حذف کنید", + "@deletePartDetail": {}, + "deleteSuccess": "عملیات حذف با موفقیت انجام شد", + "@deleteSuccess": {}, + "deliveryDate": "تاریخ تحویل", + "@deliveryDate": {}, + "description": "توضیحات", + "@description": {}, + "destination": "مقصد", + "@destination": {}, + "destroyed": "خراب شده", + "@destroyed": {}, + "details": "جزئیات", + "@details": { + "description": "details" + }, + "documentation": "مستندات", + "@documentation": {}, + "downloadComplete": "دانلود انجام شد", + "@downloadComplete": {}, + "downloadError": "خطای دانلود تصویر", + "@downloadError": {}, + "downloading": "در حال دانلود فایل", + "@downloading": {}, + "edit": "ویرایش", + "@edit": { + "description": "edit" + }, + "editAttachment": "ویرایش پیوست", + "@editAttachment": {}, + "editCategory": "ویرایش دسته بندی", + "@editCategory": {}, + "editLocation": "ویرایش مکان", + "@editLocation": {}, + "editNotes": "ویرایش یادداشت‌ها", + "@editNotes": {}, + "editParameter": "ویرایش پارامتر", + "@editParameter": {}, + "editPart": "ویرایش قطعه", + "@editPart": { + "description": "edit part" + }, + "editItem": "ویرایش اقلام سهام", + "@editItem": {}, + "editLineItem": "ویرایش ایتم خط", + "@editLineItem": {}, + "email": "پست الکترونیکی", + "@email": {}, + "enterPassword": "رمز عبور را وارد کنید", + "@enterPassword": {}, + "enterUsername": "نام کاربری را وارد کنید", + "@enterUsername": {}, + "error": "خطا", + "@error": { + "description": "Error" + }, + "errorCreate": "خطا در ایجاد ورودی پایگاه داده", + "@errorCreate": {}, + "errorDelete": "خطا در حذف ورودی پایگاه داده", + "@errorDelete": {}, + "errorDetails": "جزئیات خطا", + "@errorDetails": {}, + "errorFetch": "خطا در واکشی داده ها از سرور", + "@errorFetch": {}, + "errorUserRoles": "خطا در درخواست نقش های کاربر از سرور", + "@errorUserRoles": {}, + "errorPluginInfo": "خطا در درخواست داده های افزونه از سرور", + "@errorPluginInfo": {}, + "errorReporting": "گزارش خطا", + "@errorReporting": {}, + "errorReportUpload": "آپلود گزارش های خطا", + "@errorReportUpload": {}, + "errorReportUploadDetails": "آپلود گزارش‌ های خطا و لاگ های خرابی ناشناس", + "@errorReportUploadDetails": {}, + "expiryDate": "تاریخ انقضا", + "@expiryDate": {}, + "expiryExpired": "منقضی شده", + "@expiryExpired": {}, + "expiryStale": "کهنه", + "@expiryStale": {}, + "extraLineItem": "آیتم خط اضافی", + "@extraLineItem": {}, + "extraLineItems": "آیتم های خط اضافی", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "نمایش آیتم های موجود سریال گذاری شده", + "@filterSerializedDetail": {}, + "filterTemplate": "الگو", + "@filterTemplate": {}, + "filterTemplateDetail": "نمایش الگوی قطعات", + "@filterTemplateDetail": {}, + "filterTrackable": "قابل پیگیری", + "@filterTrackable": {}, + "filterTrackableDetail": "نمایش قطعات قابل ردیابی", + "@filterTrackableDetail": {}, + "filterVirtual": "مجازی", + "@filterVirtual": {}, + "filterVirtualDetail": "نمایش قطعات مجازی", + "@filterVirtualDetail": {}, + "filteringOptions": "گزینه های فیلتر کردن", + "@filteringOptions": {}, + "formatException": "استثنا فرمت", + "@formatException": {}, + "formatExceptionJson": "استثنا فرمت داده JSON", + "@formatExceptionJson": {}, + "formError": "خطای فرم", + "@formError": {}, + "history": "تاریخچه", + "@history": { + "description": "history" + }, + "home": "خانه", + "@home": {}, + "homeScreen": "صفحه خانه", + "@homeScreen": {}, + "homeScreenSettings": "پیکربندی تنظیمات صفحه خانه", + "@homeScreenSettings": {}, + "homeShowPo": "نمایش سفارش های خرید", + "@homeShowPo": {}, + "homeShowPoDescription": "نمایش دکمه سفارش خرید در صفحه خانه", + "@homeShowPoDescription": {}, + "homeShowShipments": "نمایش محموله", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "نمایش محموله در انتظار ارسال بر روی صفحه اصلی", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "نمایش سفارش های فروش", + "@homeShowSo": {}, + "homeShowSoDescription": "نمایش دکمه سفارش فروش در صفحه خانه", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "قطعات مشترک شده", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "نمایش قطعات مشترک شده در صفحه خانه", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "نمایش تامین کنندگان", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "نمایش دکمه تامین کنندگان در صفحه خانه", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "نمایش تولیدکنندگان", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "نمایش دکمه تولید کنندگان در صفحه خانه", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "نمایش مصرف کنندگان", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "نمایش کلید مصرف کنندگان در صفحه اصلی", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "خطا در اپلود تصویر", + "@imageUploadFailure": {}, + "imageUploadSuccess": "تصویر اپلود شد", + "@imageUploadSuccess": {}, + "inactive": "غیر فعال", + "@inactive": {}, + "inactiveCompany": "این شرکت به عنوان غیر فعال علامت گذاری شده است", + "@inactiveCompany": {}, + "inactiveDetail": "این قطعهبه عنوان غیر فعال علامت گذاری شده است", + "@inactiveDetail": {}, + "includeSubcategories": "شامل زیرمجموعه است", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "نمایش نتایج از زیر مجموعه ها", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "شامل مکان های فرعی است", + "@includeSublocations": {}, + "includeSublocationsDetail": "نمایش نتایج از مکان های فرعی", + "@includeSublocationsDetail": {}, + "incompleteDetails": "جزئیات نمایه ناقص", + "@incompleteDetails": {}, + "internalPartNumber": "شماره قطعه داخلی", + "@internalPartNumber": {}, + "info": "اطلاعات", + "@info": {}, + "inProduction": "در تولید", + "@inProduction": {}, + "inProductionDetail": "این کالای استوک در حال تولید است", + "@inProductionDetail": {}, + "internalPart": "قطعه داخلی", + "@internalPart": {}, + "invalidHost": "نام میزبان نامعتبر", + "@invalidHost": {}, + "invalidHostDetails": "نام میزبان ارائه شده معتبر نیست", + "@invalidHostDetails": {}, + "invalidPart": "قطعه نامعتبر", + "@invalidPart": {}, + "invalidPartCategory": "دسته بندی قطعه نامعتبر", + "@invalidPartCategory": {}, + "invalidStockLocation": "محل سهام نامعتبر", + "@invalidStockLocation": {}, + "invalidStockItem": "اقلام سهام نامعتبر", + "@invalidStockItem": {}, + "invalidSupplierPart": "قطعه تامین کننده نامعتبر", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "ترکیب نام کاربری / رمز عبور نامعتبر", + "@invalidUsernamePassword": {}, + "invoice": "صورت‌حساب", + "@invoice": {}, + "invoiceNumber": "شماره صورت‌حساب", + "@invoiceNumber": {}, + "issue": "موضوع", + "@issue": {}, + "issueDate": "تاریخ صدور", + "@issueDate": {}, + "issueOrder": "صدور سفارش", + "@issueOrder": {}, + "itemInLocation": "مورد در حال حاضر در مکان است", + "@itemInLocation": {}, + "itemDeleted": "مورد حذف شده است", + "@itemDeleted": {}, + "itemUpdated": "مورد به روز شد", + "@itemUpdated": {}, + "keywords": "کلمات کلیدی", + "@keywords": {}, + "labelDriver": "درایور چاپگر برچسب", + "@labelDriver": {}, + "labelSelectDriver": "انتخاب درایور چاپگر برچسب", + "@labelSelectDriver": {}, + "labelPrinting": "چاپ لیبل", + "@labelPrinting": {}, + "labelPrintingDetail": "چاپ لیبل را انتخاب کنید", + "@labelPrintingDetail": {}, + "labelTemplate": "الگوی برچسب", + "@labelTemplate": {}, + "labelSelectTemplate": "الگوی برچسب را انتخاب کنید", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "چاپگر برچسب را انتخاب کنید", + "@labelSelectPrinter": {}, + "language": "زبان", + "@language": {}, + "languageDefault": "زبان پیش فرض سیستم", + "@languageDefault": {}, + "languageSelect": "زبان را انتخاب کنید", + "@languageSelect": {}, + "lastStocktake": "آخرین سرمایه گذاری", + "@lastStocktake": {}, + "lastUpdated": "آخرین به روز رسانی", + "@lastUpdated": {}, + "level": "سطح", + "@level": {}, + "lineItemAdd": "ویرایش ایتم خط", + "@lineItemAdd": {}, + "lineItem": "آیتم خط", + "@lineItem": {}, + "lineItems": "آیتم های خط", + "@lineItems": {}, + "lineItemUpdated": "آیتم خط به روز شد", + "@lineItemUpdated": {}, + "locateItem": "اقلام سهام را مکان یابی کن", + "@locateItem": {}, + "locateLocation": "منطقه انبار را جانمایی کنید", + "@locateLocation": {}, + "locationCreate": "مکان جدید", + "@locationCreate": {}, + "locationCreateDetail": "مکان سهام جدید ایجاد کنید", + "@locationCreateDetail": {}, + "locationDefault": "مکان پیش‌فرض", + "@locationDefault": {}, + "locationNotSet": "هیچ مکانی مشخص نشده است", + "@locationNotSet": {}, + "locationUpdated": "مکان سهام به روز شد", + "@locationUpdated": {}, + "login": "ورود", + "@login": {}, + "loginEnter": "جزئیات ورود را وارد کنید", + "@loginEnter": {}, + "loginEnterDetails": "نام کاربری و پسورد به صورت منطقه ای ذخیره نشده است", + "@loginEnterDetails": {}, + "link": "لینک", + "@link": {}, + "lost": "گم شده", + "@lost": {}, + "manufacturerPart": "سازنده قطعه", + "@manufacturerPart": {}, + "manufacturerPartEdit": "قسمت سازنده را ویرایش کنید", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "شماره قطعه سازنده", + "@manufacturerPartNumber": {}, + "manufacturer": "تولید کننده", + "@manufacturer": {}, + "manufacturers": "تولیدکننده‌ ها", + "@manufacturers": {}, + "missingData": "داده گمشده", + "@missingData": {}, + "name": "نام", + "@name": {}, + "no": "خیر", + "@no": {}, + "notApplicable": "موجود نیست", + "@notApplicable": {}, + "notConnected": "متصل نیست", + "@notConnected": {}, + "notes": "یادداشت ها", + "@notes": { + "description": "Notes" + }, + "notifications": "اعلان ها", + "@notifications": {}, + "notificationsEmpty": "اطلاعیه خوانده نشده‌ای وجود ندارد", + "@notificationsEmpty": {}, + "noResponse": "پاسخی از سرور دریافت نشد", + "@noResponse": {}, + "noResults": "بدون نتیجه", + "@noResults": {}, + "noImageAvailable": "هیچ تصویری موجود نیست", + "@noImageAvailable": {}, + "noPricingAvailable": "هیچ قیمتی موجود نیست", + "@noPricingAvailable": {}, + "noPricingDataFound": "هیچ اطلاعات قیمتی برای این قطعه یافت نشد", + "@noPricingDataFound": {}, + "noSubcategories": "بدون زیر دسته بندی", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "هیچ زیر دسته بندی ای در دسترس نیست", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "عدد نامعتبر", + "@numberInvalid": {}, + "onOrder": "در سفارش", + "@onOrder": {}, + "onOrderDetails": "آیتم ها در حال حاضر در سفارش", + "@onOrderDetails": {}, + "orientation": "جهت صفحه نمایش", + "@orientation": {}, + "orientationDetail": "جهت صفحه نمایش (نیاز به راه‌اندازی مجدد)", + "@orientationDetail": {}, + "orientationLandscape": "افقی", + "@orientationLandscape": {}, + "orientationPortrait": "عمودی", + "@orientationPortrait": {}, + "orientationSystem": "سیستم", + "@orientationSystem": {}, + "outstanding": "وصول نشده‌", + "@outstanding": {}, + "outstandingOrderDetail": "نمایش سفارش های وصول نشده", + "@outstandingOrderDetail": {}, + "overdue": "عقب افتاده", + "@overdue": {}, + "overdueDetail": "نمایش سفارش های عقب افتاده", + "@overdueDetail": {}, + "packaging": "بسته بندی", + "@packaging": {}, + "packageName": "نام بسته", + "@packageName": {}, + "parameters": "پارامترها", + "@parameters": {}, + "parametersSettingDetail": "نمایش پارامترهای قطعه", + "@parametersSettingDetail": {}, + "parent": "بالاسری", + "@parent": {}, + "parentCategory": "دسته بالاسری", + "@parentCategory": {}, + "parentLocation": "مکان بالاسری", + "@parentLocation": {}, + "part": "قطعه", + "@part": { + "description": "Part (single)" + }, + "partCreate": "قطعه جدید", + "@partCreate": {}, + "partCreateDetail": "ساختن قطعه جدید در این دسته", + "@partCreateDetail": {}, + "partEdited": "قطعه به روز رسانی شد", + "@partEdited": {}, + "parts": "قطعه ها", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "قطعه به عنوان قابل فروش علامت گذاری نشده است", + "@partNotSalable": {}, + "partsNone": "بدون قطعه", + "@partsNone": {}, + "partNoResults": "هیچ قطعه ای مطابق با جست و جو یافت نشد", + "@partNoResults": {}, + "partPricing": "قیمت‌گذاری قطعات", + "@partPricing": {}, + "partPricingSettingDetail": "نمایش اطلاعات قیمت‌گذاری قطعات", + "@pricingSettingDetail": {}, + "partSettings": "تنظیمات قطعه", + "@partSettings": {}, + "partsStarred": "قطعه مشترک", + "@partsStarred": {}, + "partsStarredNone": "هیچ قطعه های ستاره دار شده ای در دسترس نیستند", + "@partsStarredNone": {}, + "partSuppliers": "تامین کنندگان قطعه", + "@partSuppliers": {}, + "partCategory": "دسته قطعه", + "@partCategory": {}, + "partCategoryTopLevel": "دسته سطح بالای قطعه", + "@partCategoryTopLevel": {}, + "partCategories": "دسته های قطعه", + "@partCategories": {}, + "partDetails": "جزئیات قطعه", + "@partDetails": {}, + "partNotes": "یادداشت های قطعه", + "@partNotes": {}, + "partStock": "موجودی قطعه", + "@partStock": { + "description": "part stock" + }, + "password": "رمز عبور", + "@password": {}, + "passwordEmpty": "رمز عبور نمی تواند خالی باشد", + "@passwordEmpty": {}, + "pending": "در حال بررسی", + "@pending": {}, + "permissionAccountDenied": "حساب شما مجوزهای لازم برای انجام این عمل را ندارد", + "@permissionAccountDenied": {}, + "permissionRequired": "نیازمند مجوز", + "@permissionRequired": {}, + "phone": "تماس", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "تأیید اسکن داده ها", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "هنگام اسکن آیتم ها، جزئیات را تأیید کنید", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "فعال سازی سفارش های خرید", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "فعال سازی قابلیت سفارش خرید", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "میانبر دوربین", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "فعال سازی میانبر آپلود تصویر در صفحه سفارش خرید", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "سفارش خرید", + "@purchaseOrder": {}, + "purchaseOrderCreate": "سفارش خرید جدید", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "ویرایش سفارش خرید", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "تنظیمات سفارش خرید", + "@purchaseOrderSettings": {}, + "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": {}, + "rotateClockwise": "چرخش °90 درجه در جهت عقربه های ساعت", + "@rotateClockwise": {}, + "refreshing": "در حال تازه سازی", + "@refreshing": {}, + "rejected": "رد شد", + "@rejected": {}, + "releaseNotes": "یادداشت های انتشار", + "@releaseNotes": {}, + "remove": "حذف", + "@remove": { + "description": "remove" + }, + "removeStock": "حذف سهام", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "گزارش باگ", + "@reportBug": {}, + "reportBugDescription": "ارسال گزارش باگ (به حساب GitHub نیاز دارد)", + "@reportBugDescription": {}, + "responsible": "مسئول", + "@responsible": {}, + "results": "نتایج", + "@results": {}, + "request": "درخواست", + "@request": {}, + "requestFailed": "درخواست ناموفق", + "@requestFailed": {}, + "requestSuccessful": "درخواست موفق", + "@requestSuccessful": {}, + "requestingData": "درخواست داده", + "@requestingData": {}, + "required": "الزامات", + "@required": { + "description": "This field is required" + }, + "response400": "درخواست بد", + "@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": "پاسخ ناشناخته", + "@responseUnknown": {}, + "result": "نتایج", + "@result": { + "description": "" + }, + "returned": "برگشت داده شده", + "@returned": {}, + "salesOrder": "سفارش فروش", + "@salesOrder": {}, + "salesOrders": "سفارش های فروش", + "@salesOrders": {}, + "salesOrderEnable": "فعالسازی سفارش های فروش", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "فعالسازی قابلیت سفارش فروش", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "میانبر دوربین", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "فعال سازی میانبر آپلود تصویر در صفحه سفارش فروش", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "تنظیمات سفارش فروش", + "@salesOrderSettings": {}, + "salesOrderCreate": "سفارش فروش جدید", + "@saleOrderCreate": {}, + "salesOrderEdit": "ویرایش سفارش فروش", + "@salesOrderEdit": {}, + "salesOrderUpdated": "سفارش فروش به روزرسانی شد", + "@salesOrderUpdated": {}, + "save": "ذخیره", + "@save": { + "description": "Save" + }, + "scanBarcode": "اسکن بارکد", + "@scanBarcode": {}, + "scanSupplierPart": "اسکن بارکد قطعه تامین کننده", + "@scanSupplierPart": {}, + "scanIntoLocation": "اسکن در موقعیت", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "این آیتم را در موقعیت اسکن کن", + "@scanIntoLocationDetail": {}, + "scannerExternal": "اسکنر خارجی", + "@scannerExternal": {}, + "scannerExternalDetail": "استفاده از اسکنر خارجی برای خواندن بارکد (حالت گوه ای)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "اسکن قطعه های دریافتی", + "@scanReceivedParts": {}, + "search": "جست و جو", + "@search": { + "description": "search" + }, + "searching": "در حال جست و جو", + "@searching": {}, + "searchLocation": "جست و جو موقعیت", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "جست و جو قطعه ها", + "@searchParts": {}, + "searchStock": "جست و جو موجودی", + "@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": "سرور باید با http[s] شروع شود", + "@serverStart": {}, + "settings": "تنظیمات", + "@settings": {}, + "serverInstance": "نمونه سرور", + "@serverInstance": {}, + "serverNotConnected": "سرور متصل نیست", + "@serverNotConnected": {}, + "serverNotSelected": "سرور انتخاب نشده است", + "@serverNotSelected": {}, + "shipment": "محموله", + "@shipment": {}, + "shipments": "محموله ها", + "@shipments": {}, + "shipmentsPending": "محموله در انتظار ارسال", + "@shipmentsPending": {}, + "shipmentAdd": "افزودن محموله", + "@shipmentAdd": {}, + "shipmentCheck": "بررسی محموله", + "@shipmentCheck": {}, + "shipmentCheckDetail": "این محموله را بررسی شده علامت گذاری کن", + "@shipmentCheckDetail": {}, + "shipmentChecked": "محموله بررسی شده", + "@shipmentChecked": {}, + "shipmentDate": "تاریخ ارسال", + "@shipmentDate": {}, + "shipmentEdit": "تغییر محموله", + "@shipmentEdit": {}, + "shipmentReference": "کد محموله", + "@shipmentReference": {}, + "shipmentSend": "ارسال محموله", + "@shipmentSend": {}, + "shipmentUncheck": "محموله بررسی نشده", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "این محموله را بررسی نشده علامت گذاری کن", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "محموله به روز رسانی شد", + "@shipmentUpdated": {}, + "shipped": "ارسال شده", + "@shipped": {}, + "sku": "واحد نگهداری موجودی", + "@sku": {}, + "sounds": "صداها", + "@sounds": {}, + "soundOnBarcodeAction": "پخش آهنگ قابل شنیدن در زمان بارکد خوانی", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "پخش آهنگ قابل شنیدن در زمان خطای سرور", + "@soundOnServerError": {}, + "startDate": "تاریخ شروع", + "@startDate": {}, + "status": "وضعیت", + "@status": {}, + "statusCode": "کد وضعیت", + "@statusCode": {}, + "stock": "موجودی", + "@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": "موجودی کالا به روز رسانی شد", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "به روز رسانی موجودی کالا با خطا مواجه شد", + "@stockItemUpdateFailure": {}, + "stockLocation": "موقعیت موجودی", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "موقعیت های موجودی", + "@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": "قطعه تامین کننده", + "@supplierPart": {}, + "supplierPartEdit": "ویرایش قطعه تامین کننده", + "@supplierPartEdit": {}, + "supplierPartNumber": "شماره قطعه تامین کننده", + "@supplierPartNumber": {}, + "supplierPartUpdated": "قطعه تامین کننده به روز رسانی شد", + "@supplierPartUpdated": {}, + "supplierParts": "قطعه های تامین کننده", + "@supplierParts": {}, + "suppliers": "تامین کننده ها", + "@suppliers": {}, + "supplierReference": "مرجع تامین‌ کننده", + "@supplierReference": {}, + "switchCamera": "تعویض دوربین", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "روشن خاموش کردن چراغ قوه", + "@toggleTorch": {}, + "tokenError": "خطای توکن", + "@tokenError": {}, + "tokenMissing": "توکن گمشده", + "@tokenMissing": {}, + "tokenMissingFromResponse": "توکن دسترسی از پاسخ گمشده است", + "@tokenMissingFromResponse": {}, + "totalPrice": "قیمت کل", + "@totalPrice": {}, + "trackingNumber": "کد رهگیری", + "@trackingNumber": {}, + "transfer": "انتقال", + "@transfer": { + "description": "transfer" + }, + "transferStock": "انتقال موجودی", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "انتقال آیتم به موقعیت متفاوت", + "@transferStockDetail": {}, + "transferStockLocation": "انتقال موقعیت موجودی", + "@transferStockLocation": {}, + "transferStockLocationDetail": "انتقال موقعیت این موجودی به موقعیتی دیگر", + "@transferStockLocationDetail": {}, + "translate": "ترجمه", + "@translate": {}, + "translateHelp": "کمک به ترجمه برنامه InvenTree", + "@translateHelp": {}, + "unavailable": "غیرقابل دسترس", + "@unavailable": {}, + "unavailableDetail": "آیتم در دسترس نیست", + "@unavailableDetail": {}, + "unitPrice": "قیمت واحد", + "@unitPrice": {}, + "units": "واحدها", + "@units": {}, + "unknownResponse": "پاسخ ناشناخته", + "@unknownResponse": {}, + "upload": "آپلود", + "@upload": {}, + "uploadFailed": "خطا در اپلود فایل", + "@uploadFailed": {}, + "uploadSuccess": "فایل اپلود شد", + "@uploadSuccess": {}, + "uploadImage": "بارگذاری تصویر", + "@uploadImage": {}, + "usedIn": "استفاده شده در", + "@usedIn": {}, + "usedInDetails": "مجموعه هایی که به این قطعه نیاز دارند", + "@usedInDetails": {}, + "username": "نام کاربری", + "@username": {}, + "usernameEmpty": "نام کاربری نمی تواند خالی باشد", + "@usernameEmpty": {}, + "value": "مقدار", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "مقدار نمی تواند خالی باشد", + "@valueCannotBeEmpty": {}, + "valueRequired": "مقدار الزامی است", + "@valueRequired": {}, + "variants": "انواع", + "@variants": {}, + "version": "نسخه", + "@version": {}, + "viewSupplierPart": "نمایش قطعه تامین کننده", + "@viewSupplierPart": {}, + "website": "وب سایت", + "@website": {}, + "yes": "بله", + "@yes": {}, + "price": "قیمت", + "@price": {}, + "priceRange": "بازه‌ قیمت", + "@priceRange": {}, + "priceOverrideMin": "قیمت دستی مینیمم", + "@priceOverrideMin": {}, + "priceOverrideMax": "قیمت دستی ماکزیمم", + "@priceOverrideMax": {}, + "salePrice": "قیمت حراج", + "@salePrice": {}, + "saleHistory": "تاریخچه حراج", + "@saleHistory": {}, + "supplierPricing": "قیمت تامین کننده", + "@supplierPricing": {}, + "bomCost": "هزینه تمام شده", + "@bomCost": {}, + "internalCost": "هزینه داخلی", + "@internalCost": {}, + "variantCost": "هزینه متغیر", + "@variantCost": {}, + "overallPricing": "قیمت نهایی", + "@overallPricing": {}, + "pricingOverrides": "قیمت دستی", + "@pricingOverrides": {}, + "currency": "واحد پول", + "@currency": {}, + "priceBreaks": "کاهش قیمت", + "@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 new file mode 100644 index 0000000..ea2c362 --- /dev/null +++ b/lib/l10n/fi_FI/app_fi_FI.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "fi", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@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": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "Sovelluksen tiedot", + "@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": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Näytä sovelluksen julkaisutiedot", + "@appReleaseNotes": {}, + "appSettings": "Sovelluksen asetukset", + "@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", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Liitteitä ei löytynyt", + "@attachmentNone": {}, + "attachmentNoneDetail": "Liitteitä ei löytynyt", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Valitse liite", + "@attachmentSelect": {}, + "attention": "Huomio", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Peruuta", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Peru tilaus", + "@cancelOrder": {}, + "category": "Kategoria", + "@category": {}, + "categoryCreate": "Uusi kategoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Yritys", + "@company": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Muokkaa yritystä", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Yrityksen tiedot päivitetty", + "@companyUpdated": {}, + "companies": "Yritykset", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Määritä palvelimen asetukset", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Yhteys evätty", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Asiakkaat", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Vahingoittunut", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Tumma tila", + "@darkMode": {}, + "darkModeEnable": "Käytä tummaa tilaa", + "@darkModeEnable": {}, + "delete": "Poista", + "@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", + "@destination": {}, + "destroyed": "Tuhottu", + "@destroyed": {}, + "details": "Yksityiskohdat", + "@details": { + "description": "details" + }, + "documentation": "Dokumentaatio", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Ladataan tiedostoa", + "@downloading": {}, + "edit": "Muokkaa", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "Muokkaa kategoriaa", + "@editCategory": {}, + "editLocation": "Muokkaa sijaintia", + "@editLocation": {}, + "editNotes": "Muokkaa merkintää", + "@editNotes": {}, + "editParameter": "Muokkaa Parametria", + "@editParameter": {}, + "editPart": "Muokkaa osaa", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Muokkaa listan riviä", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Lähetä nimettömät virheilmoitukset ja kaatumislokit", + "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "Palaute", + "@feedback": {}, + "feedbackError": "Palautetta lähetettäessä tapahtui virhe", + "@feedbackError": {}, + "feedbackSuccess": "Palaute lähetetty", + "@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" + }, + "home": "Koti", + "@home": {}, + "homeScreen": "Aloitusnäyttö", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": "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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Avainsanat", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Valmistaja", + "@manufacturer": {}, + "manufacturers": "Valmistajat", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Nimi", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Not Connected", + "@notConnected": {}, + "notes": "Merkinnät", + "@notes": { + "description": "Notes" + }, + "notifications": "Ilmoitukset", + "@notifications": {}, + "notificationsEmpty": "Ei lukemattomia ilmoituksia", + "@notificationsEmpty": {}, + "noResponse": "No Response from Server", + "@noResponse": {}, + "noResults": "Ei tuloksia", + "@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", + "@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)" + }, + "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)" + }, + "partNotSalable": "Part not marked as salable", + "@partNotSalable": {}, + "partsNone": "Ei osia", + "@partsNone": {}, + "partNoResults": "Ei hakua vastaavia osia", + "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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ä", + "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Tililläsi ei ole tarvittavia oikeuksia tämän toiminnon suorittamiseen", + "@permissionAccountDenied": {}, + "permissionRequired": "Käyttöoikeus vaaditaan", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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", + "@profileAdd": {}, + "profileConnect": "Yhdistä palvelimeen", + "@profileConnect": {}, + "profileEdit": "Muokkaa palvelinprofiilia", + "@profileEdit": {}, + "profileDelete": "Poista palvelinprofiili", + "@profileDelete": {}, + "profileLogout": "Logout Profile", + "@profileLogout": {}, + "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": {}, + "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", + "@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", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "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": {}, + "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ä", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "Päivitetään", + "@refreshing": {}, + "rejected": "Hylätty", + "@rejected": {}, + "releaseNotes": "Julkaisutiedot", + "@releaseNotes": {}, + "remove": "Poista", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Ilmoita virheestä", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "serverInstance": "Server Instance", + "@serverInstance": {}, + "serverNotConnected": "Server not connected", + "@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", + "@sku": {}, + "sounds": "Äänet", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "Tila", + "@status": {}, + "statusCode": "Tilakoodi", + "@statusCode": {}, + "stock": "Varasto", + "@stock": { + "description": "stock" + }, + "stockDetails": "Current available stock quantity", + "@stockDetails": {}, + "stockItem": "Varastotuote", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Varastotuotteet", + "@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", + "@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": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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ä", + "@usernameEmpty": {}, + "value": "Arvo", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Arvo ei voi olla tyhjä", + "@valueCannotBeEmpty": {}, + "valueRequired": "Arvo vaaditaan", + "@valueRequired": {}, + "variants": "Variants", + "@variants": {}, + "version": "Versio", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Sivusto", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..9831dcb --- /dev/null +++ b/lib/l10n/fr_FR/app_fr_FR.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Allouée", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Carré (1:1)", + "@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", + "@appSettings": {}, + "appSettingsDetails": "Configurer les paramètres de l’application InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Mes assignations", + "@assignedToMe": {}, + "assignedToMeDetail": "Afficher les demandes qui me sont assignées", + "@assignedToMeDetail": {}, + "attachments": "Pieces jointes", + "@attachments": {}, + "attachImage": "Ajouter une image", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Aucune pièce jointe trouvée", + "@attachmentNone": {}, + "attachmentNoneDetail": "Aucune pièce jointe trouvée", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Sélectionner une pièce jointe", + "@attachmentSelect": {}, + "attention": "Avertissement", + "@attention": {}, + "available": "Disponible", + "@available": {}, + "availableStock": "Stock disponible", + "@availableStock": {}, + "barcodes": "Code-barres", + "@barcodes": {}, + "barcodeSettings": "Paramètres des Codes-barres", + "@barcodeSettings": {}, + "barcodeAssign": "Affecter un code-barres", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scannez le code-barres personnalisé pour l'attribuer", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Scanner le code-barres d'une pièce", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scannez le code-barres pour recevoir la pièce", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Scan de code-barres en pause", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@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", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scanner un code-barres InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scannez les éléments de stock dans cet l'emplacement", + "@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", + "@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": "Liste de matériel", + "@bom": {}, + "bomEnable": "Afficher les bordereaux matières", + "@bomEnable": {}, + "build": "Assemblage", + "@build": {}, + "building": "Assemblage en cours", + "@building": {}, + "cameraCreationError": "Activation impossible de la caméra", + "@cameraCreationError": {}, + "cameraInternal": "Caméra interne", + "@cameraInternal": {}, + "cameraInternalDetail": "Utiliser la caméra interne pour lire les codes à barres", + "@cameraInternalDetail": {}, + "cancel": "Annuler", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Annuler la commande", + "@cancelOrder": {}, + "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": {}, + "companyAdd": "Ajouter une entreprise", + "@companyAdd": {}, + "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": {}, + "complete": "Terminé", + "@complete": {}, + "completeOrder": "Finir l'achat", + "@completeOrder": {}, + "completionDate": "Date d'achèvement", + "@completionDate": {}, + "configureServer": "Configurer les paramètres serveur", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Nombre de stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Crédits", + "@credits": {}, + "crop": "Rogner", + "@crop": {}, + "cropImage": "Rogner l'image", + "@cropImage": {}, + "customer": "Client", + "@customer": {}, + "customers": "Clients", + "@customers": {}, + "customerReference": "Référence client", + "@customerReference": {}, + "damaged": "Endommagé", + "@damaged": {}, + "colorScheme": "Palette de couleurs", + "@colorScheme": {}, + "colorSchemeDetail": "Sélection de la palette de couleurs", + "@colorSchemeDetail": {}, + "darkMode": "Mode Sombre", + "@darkMode": {}, + "darkModeEnable": "Activer le mode sombre", + "@darkModeEnable": {}, + "delete": "Supprimer", + "@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", + "@destination": {}, + "destroyed": "Détruit", + "@destroyed": {}, + "details": "Détails", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Téléchargement terminé", + "@downloadComplete": {}, + "downloadError": "Impossible de télécharger l'image", + "@downloadError": {}, + "downloading": "Téléchargement du fichier", + "@downloading": {}, + "edit": "Modifier", + "@edit": { + "description": "edit" + }, + "editAttachment": "Modifier la pièce jointe", + "@editAttachment": {}, + "editCategory": "Modifier la catégorie", + "@editCategory": {}, + "editLocation": "Modifier l’emplacement", + "@editLocation": {}, + "editNotes": "Modifier les notes", + "@editNotes": {}, + "editParameter": "Modifier les Paramètres", + "@editParameter": {}, + "editPart": "Modifier la pièce", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editer l'article en stock", + "@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", + "@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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Envoyer les rapports d'erreur et de crash anonymement", + "@errorReportUploadDetails": {}, + "expiryDate": "Date d'expiration", + "@expiryDate": {}, + "expiryExpired": "Expiré", + "@expiryExpired": {}, + "expiryStale": "Périmé", + "@expiryStale": {}, + "extraLineItem": "Ligne supplémentaire", + "@extraLineItem": {}, + "extraLineItems": "Lignes supplémentaires", + "@extraLineItems": {}, + "feedback": "Donner votre avis", + "@feedback": {}, + "feedbackError": "Erreur lors de l'envoi du commentaire", + "@feedbackError": {}, + "feedbackSuccess": "Commentaire envoyé", + "@feedbackSuccess": {}, + "filterActive": "Actif", + "@filterActive": {}, + "filterActiveDetail": "Afficher les pièces actives", + "@filterActiveDetail": {}, + "filterAssembly": "Assemblé", + "@filterAssembly": {}, + "filterAssemblyDetail": "Afficher les pièces assemblées", + "@filterAssemblyDetail": {}, + "filterComponent": "Composant", + "@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", + "@filterInStockDetail": {}, + "filterSerialized": "Sérialisé", + "@filterSerialized": {}, + "filterSerializedDetail": "Afficher les articles en stock sérialisés", + "@filterSerializedDetail": {}, + "filterTemplate": "Modèle", + "@filterTemplate": {}, + "filterTemplateDetail": "Afficher les pièces du modèle", + "@filterTemplateDetail": {}, + "filterTrackable": "Traçable", + "@filterTrackable": {}, + "filterTrackableDetail": "Afficher les pièces traçables", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuelle", + "@filterVirtual": {}, + "filterVirtualDetail": "Afficher les pièces virtuelles", + "@filterVirtualDetail": {}, + "filteringOptions": "Options de filtrage", + "@filteringOptions": {}, + "formatException": "Exception de format", + "@formatException": {}, + "formatExceptionJson": "Exception de format de données JSON", + "@formatExceptionJson": {}, + "formError": "Erreur de formulaire", + "@formError": {}, + "history": "Historique", + "@history": { + "description": "history" + }, + "home": "Page d’accueil", + "@home": {}, + "homeScreen": "Ecran d'accueil", + "@homeScreen": {}, + "homeScreenSettings": "Configurer les paramètres de l'écran d'accueil", + "@homeScreenSettings": {}, + "homeShowPo": "Voir bon de commande", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Pièces suivies", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Afficher les pièces suivies sur l'écran d'accueil", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Cette entreprise est marquée comme inactive", + "@inactiveCompany": {}, + "inactiveDetail": "Cette pièce est marquée comme inactive", + "@inactiveDetail": {}, + "includeSubcategories": "Inclure les sous-catégories", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Afficher les résultats des sous-catégories", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclure les sous-emplacements", + "@includeSublocations": {}, + "includeSublocationsDetail": "Afficher les résultats des sous-emplacements", + "@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": {}, + "internalPart": "Pièce interne", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Pièce fournisseur invalide", + "@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", + "@issueDate": {}, + "issueOrder": "Émettre la commande", + "@issueOrder": {}, + "itemInLocation": "Article déjà dans l'emplacement", + "@itemInLocation": {}, + "itemDeleted": "L'article a été supprimé", + "@itemDeleted": {}, + "itemUpdated": "Élément mis à jour", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Modèle d'étiquette", + "@labelTemplate": {}, + "labelSelectTemplate": "Sélection du modèle d'étiquette", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Sélection de l'imprimante d'étiquettes", + "@labelSelectPrinter": {}, + "language": "Langue", + "@language": {}, + "languageDefault": "Langue par défaut du système", + "@languageDefault": {}, + "languageSelect": "Sélectionner une langue", + "@languageSelect": {}, + "lastStocktake": "Dernier inventaire", + "@lastStocktake": {}, + "lastUpdated": "Dernière mise à jour", + "@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", + "@locateLocation": {}, + "locationCreate": "Nouvel emplacement", + "@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", + "@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", + "@lost": {}, + "manufacturerPart": "Pièce du fabricant", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Modifier la pièce du fabricant", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Numéro de pièce fabricant", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricant", + "@manufacturer": {}, + "manufacturers": "Fabricants", + "@manufacturers": {}, + "missingData": "Données manquantes", + "@missingData": {}, + "name": "Nom", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nombre invalide", + "@numberInvalid": {}, + "onOrder": "Sur Commande", + "@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": {}, + "orientationSystem": "Système", + "@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", + "@packageName": {}, + "parameters": "Paramètres", + "@parameters": {}, + "parametersSettingDetail": "Afficher les paramètres de la pièce", + "@parametersSettingDetail": {}, + "parent": "Niveau superieur", + "@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)" + }, + "partNotSalable": "Pièce non marquée comme commercialisable", + "@partNotSalable": {}, + "partsNone": "Aucune pièces", + "@partsNone": {}, + "partNoResults": "Pas de pièces correspondant à la requête", + "@partNoResults": {}, + "partPricing": "Tarification des pièces", + "@partPricing": {}, + "partPricingSettingDetail": "Afficher les informations sur le prix des pièces", + "@pricingSettingDetail": {}, + "partSettings": "Paramètres de la pièce", + "@partSettings": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Vous n'avez pas les autorisations requises pour exécuter cette action", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorisation requise", + "@permissionRequired": {}, + "phone": "Téléphone", + "@phone": {}, + "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", + "@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": {}, + "profileLogout": "Déconnexion du profil", + "@profileLogout": {}, + "profileName": "Nom du profil", + "@profileName": {}, + "profileNone": "Aucun profil disponible", + "@profileNone": {}, + "profileNotSelected": "Aucun profil sélectionné", + "@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": {}, + "projectCode": "Code Projet", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirmer les données scannées", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirmer les détails lors du scan d'un objet", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Activer les demandes d'achats", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Activer les fonctionnalités de demande d'achat", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Raccourcie caméra", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Activer le raccourci pour téléverser une image sur l'écran de demande d'achat", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Commande d’achat", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nouveau Bon de Commande", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Modifier la commande d'achat", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Paramètres des demandes d'achats", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Commandes d'achat", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Bon de commande mis à jour", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Prix d'achat", + "@purchasePrice": {}, + "quantity": "Quantité", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantité disponible", + "@quantityAvailable": {}, + "quantityEmpty": "La quantité est vide", + "@quantityEmpty": {}, + "quantityInvalid": "La quantité n'est pas valide", + "@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", + "@received": {}, + "receivedFilterDetail": "Afficher les articles reçus", + "@receivedFilterDetail": {}, + "receiveItem": "Articles reçus", + "@receiveItem": {}, + "receivedItem": "Article de stock reçu", + "@receivedItem": {}, + "reference": "Référence", + "@reference": {}, + "refresh": "Actualiser", + "@refresh": {}, + "rotateClockwise": "Rotation à 90° dans le sens horaire", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsable", + "@responsible": {}, + "results": "Résultats", + "@results": {}, + "request": "Requête", + "@request": {}, + "requestFailed": "Échec de la requête", + "@requestFailed": {}, + "requestSuccessful": "Recherche reussie", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Commandes", + "@salesOrder": {}, + "salesOrders": "Ventes", + "@salesOrders": {}, + "salesOrderEnable": "Activer les demandes de ventes", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Activer la fonctionnalité des demandes de ventes", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Raccourcie caméra", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Activer le raccourci pour téléverser une image sur l'écran de demande de vente", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Paramètres des demandes de vente", + "@salesOrderSettings": {}, + "salesOrderCreate": "Nouvelle commande", + "@saleOrderCreate": {}, + "salesOrderEdit": "Modifier la commande", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Commande mise à jour", + "@salesOrderUpdated": {}, + "save": "Enregistrer", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanner un code-barres", + "@scanBarcode": {}, + "scanSupplierPart": "Scanner le code-barres des pièces des fournisseurs", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scanner vers l'emplacement", + "@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" + }, + "searching": "Recherche en cours", + "@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", + "@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": {}, + "serialNumbers": "Numéros de Série", + "@serialNumbers": {}, + "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": {}, + "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", + "@sku": {}, + "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": {}, + "startDate": "Date de début", + "@startDate": {}, + "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": {}, + "supplierPart": "Pièce fournisseur", + "@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", + "@supplierParts": {}, + "suppliers": "Fournisseurs", + "@suppliers": {}, + "supplierReference": "Référence du fournisseur", + "@supplierReference": {}, + "switchCamera": "Changer de caméra", + "@switchCamera": {}, + "takePicture": "Prendre une photo", + "@takePicture": {}, + "targetDate": "Date Cible", + "@targetDate": {}, + "templatePart": "Modele de composant", + "@templatePart": {}, + "testName": "Nom de test", + "@testName": {}, + "testPassedOrFailed": "Test réussi ou échoué", + "@testPassedOrFailed": {}, + "testsRequired": "Tests requis", + "@testsRequired": {}, + "testResults": "Résultats du test", + "@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", + "@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": "" + }, + "toggleTorch": "Lampe torche", + "@toggleTorch": {}, + "tokenError": "Erreur du jeton", + "@tokenError": {}, + "tokenMissing": "Jeton manquant", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Jeton d'accès manquant dans la réponse", + "@tokenMissingFromResponse": {}, + "totalPrice": "Prix Total", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Transfert", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transférer le stock", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transférer un élément vers un autre emplacement", + "@transferStockDetail": {}, + "transferStockLocation": "Transférer l'Emplacement du Stock", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transférer cet emplacement de stock vers un autre", + "@transferStockLocationDetail": {}, + "translate": "Traduire", + "@translate": {}, + "translateHelp": "Aidez à traduire l'application InvenTree", + "@translateHelp": {}, + "unavailable": "Indisponible", + "@unavailable": {}, + "unavailableDetail": "L'article n'est pas disponible", + "@unavailableDetail": {}, + "unitPrice": "Prix unitaire", + "@unitPrice": {}, + "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": {}, + "uploadImage": "Envoyer une image", + "@uploadImage": {}, + "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": {}, + "variants": "Variantes", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Voir la pièce du fournisseur", + "@viewSupplierPart": {}, + "website": "Site web", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "price": "Prix", + "@price": {}, + "priceRange": "Fourchette de prix", + "@priceRange": {}, + "priceOverrideMin": "Remplacer le prix minimum", + "@priceOverrideMin": {}, + "priceOverrideMax": "Remplacer le prix maximum", + "@priceOverrideMax": {}, + "salePrice": "Prix de vente", + "@salePrice": {}, + "saleHistory": "Historique des ventes", + "@saleHistory": {}, + "supplierPricing": "Tarification du fournisseur", + "@supplierPricing": {}, + "bomCost": "Coût de la nomenclature", + "@bomCost": {}, + "internalCost": "Coût interne", + "@internalCost": {}, + "variantCost": "Cout Variable", + "@variantCost": {}, + "overallPricing": "Cout Global", + "@overallPricing": {}, + "pricingOverrides": "Remplacement des prix", + "@pricingOverrides": {}, + "currency": "Devise", + "@currency": {}, + "priceBreaks": "Ruptures de prix", + "@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 new file mode 100644 index 0000000..c508c93 --- /dev/null +++ b/lib/l10n/he_IL/app_he_IL.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "he", + "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": {}, + "allocated": "מוקצה", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "הקצאת מלאי", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": " הצג הערות פרסום של האפליקציה", + "@appReleaseNotes": {}, + "appSettings": "הגדרות אפליקציה", + "@appSettings": {}, + "appSettingsDetails": "הגדר את הגדרות אפליקציית Inventree", + "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "קבצים מצורפים", + "@attachments": {}, + "attachImage": "צירוף תמונה", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "לא נמצאו קבצים מצורפים", + "@attachmentNone": {}, + "attachmentNoneDetail": "לא נמצאו קבצים מצורפים", + "@attachmentNoneDetail": {}, + "attachmentSelect": "בחר קובץ מצורף", + "@attachmentSelect": {}, + "attention": "תשומת לב", + "@attention": {}, + "available": "זמין", + "@available": {}, + "availableStock": "מלאי זמין", + "@availableStock": {}, + "barcodes": "ברקודים", + "@barcodes": {}, + "barcodeSettings": "הגדרות ברקוד", + "@barcodeSettings": {}, + "barcodeAssign": "הקצה ברקוד", + "@barcodeAssign": {}, + "barcodeAssignDetail": "סרוק ברקוד מותאם אישית להקצאה", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "הוקצה ברקוד", + "@barcodeAssigned": {}, + "barcodeError": "שגיאת סריקת ברקוד", + "@barcodeError": {}, + "barcodeInUse": "הברקוד כבר הוקצה", + "@barcodeInUse": {}, + "barcodeMissingHash": "נתוני גיבוב ברקוד חסרים בתגובה", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "אין התאמה לברקוד", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "ברקוד לא הוקצה", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "סרוק ברקוד של פריט", + "@barcodeScanPart": {}, + "barcodeReceivePart": "סרוק ברקוד כדי לקבל פריט", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "סריקת ברקוד מושהית", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "סרוק כדי להקצות ברקוד", + "@barcodeScanAssign": {}, + "barcodeScanController": "קלט סורק", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "בחר מקור קלט של סורק ברקוד", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "השהיית סריקת ברקוד", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "עיכוב בין סריקת ברקוד", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "סרוק ברקוד של InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "סרוק פריטי מלאי למיקום זה", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "סרוק את מיקום המלאי", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "מצב סריקה בודדת", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "השהה את סורק הברקוד לאחר כל סריקה", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "נסרק למיקום", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "פריט לא נסרק פנימה", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "סרוק פריט במלאי", + "@barcodeScanItem": {}, + "barcodeTones": "צלילי ברקוד", + "@barcodeTones": {}, + "barcodeUnassign": "בטל הקצאת ברקוד", + "@barcodeUnassign": {}, + "barcodeUnknown": "הברקוד אינו מזוהה", + "@barcodeUnknown": {}, + "batchCode": "קוד אצווה", + "@batchCode": {}, + "billOfMaterials": "שטר חומרים [Bom]", + "@billOfMaterials": {}, + "bom": "שטר חומרים [Bom]", + "@bom": {}, + "bomEnable": "הצג את כתב החומרים", + "@bomEnable": {}, + "build": "Build", + "@build": {}, + "building": "Building", + "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "cameraInternal": "מצלמה פנימית", + "@cameraInternal": {}, + "cameraInternalDetail": "השתמש במצלמה פנימית לקריאת ברקודים", + "@cameraInternalDetail": {}, + "cancel": "ביטול", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "ביטול הזמנה", + "@cancelOrder": {}, + "category": "קטגוריה", + "@category": {}, + "categoryCreate": "קטגוריה חדשה", + "@categoryCreate": {}, + "categoryCreateDetail": "צור קטגוריית פריטים חדשה", + "@categoryCreateDetail": {}, + "categoryUpdated": "קטגוריית הפריט עודכנה", + "@categoryUpdated": {}, + "company": "חברה", + "@company": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "ערוך חברה", + "@companyEdit": {}, + "companyNoResults": "אין חברות שתואמות לשאילתה", + "@companyNoResults": {}, + "companyUpdated": "פרטי החברה עודכנו", + "@companyUpdated": {}, + "companies": "חברות", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "קבע את הגדרות השרת", + "@configureServer": {}, + "confirmScan": "אשר העברה", + "@confirmScan": {}, + "confirmScanDetail": "אשר את פרטי העברת המלאי בעת סריקת ברקודים", + "@confirmScanDetail": {}, + "connectionRefused": "החיבור סורב", + "@connectionRefused": {}, + "count": "ספירה", + "@count": { + "description": "Count" + }, + "countStock": "ספירת מלאי", + "@countStock": { + "description": "Count Stock" + }, + "credits": "קרדיטים", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "לקוח", + "@customer": {}, + "customers": "לקוחות", + "@customers": {}, + "customerReference": "הפניה ללקוח", + "@customerReference": {}, + "damaged": "מלאי פגום", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "מצב כהה", + "@darkMode": {}, + "darkModeEnable": "הפעל מצב כהה", + "@darkModeEnable": {}, + "delete": "מחק", + "@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", + "@destination": {}, + "destroyed": "מושמד", + "@destroyed": {}, + "details": "פרטים", + "@details": { + "description": "details" + }, + "documentation": "תיעוד", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "מוריד קובץ", + "@downloading": {}, + "edit": "ערוך", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "ערוך קטגוריה", + "@editCategory": {}, + "editLocation": "ערוך מיקום", + "@editLocation": {}, + "editNotes": "ערוך הערות", + "@editNotes": {}, + "editParameter": "ערוך פרמטר", + "@editParameter": {}, + "editPart": "ערוך פריט", + "@editPart": { + "description": "edit part" + }, + "editItem": "ערוך פריט מלאי", + "@editItem": {}, + "editLineItem": "ערוך פריט", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "הזן סיסמה", + "@enterPassword": {}, + "enterUsername": "הזן שם משתמש", + "@enterUsername": {}, + "error": "שגיאה", + "@error": { + "description": "Error" + }, + "errorCreate": "שגיאה ביצירת ערך מסד הנתונים", + "@errorCreate": {}, + "errorDelete": "שגיאה במחיקת ערך ממסד הנתונים", + "@errorDelete": {}, + "errorDetails": "פרטי שגיאה", + "@errorDetails": {}, + "errorFetch": "שגיאה באחזור נתונים מהשרת", + "@errorFetch": {}, + "errorUserRoles": "שגיאה בבקשת תפקידי משתמש מהשרת", + "@errorUserRoles": {}, + "errorPluginInfo": "שגיאה בבקשת נתוני פלגאין מהשרת", + "@errorPluginInfo": {}, + "errorReporting": "דווח על שגיאות ", + "@errorReporting": {}, + "errorReportUpload": "העלה דוחות שגיאה", + "@errorReportUpload": {}, + "errorReportUploadDetails": "העלאת דוחות שגיאה אנונימיים ויומני קריסה", + "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "משוב", + "@feedback": {}, + "feedbackError": "שגיאה בהגשת משוב", + "@feedbackError": {}, + "feedbackSuccess": "נשלח משוב", + "@feedbackSuccess": {}, + "filterActive": "פעיל", + "@filterActive": {}, + "filterActiveDetail": "הצג פריטים פעילים", + "@filterActiveDetail": {}, + "filterAssembly": "Assembled", + "@filterAssembly": {}, + "filterAssemblyDetail": "Show assembled parts", + "@filterAssemblyDetail": {}, + "filterComponent": "רכיב", + "@filterComponent": {}, + "filterComponentDetail": "הצג פריטי רכיבים", + "@filterComponentDetail": {}, + "filterExternal": "חיצוני", + "@filterExternal": {}, + "filterExternalDetail": "הצג מלאי במקומות חיצוניים", + "@filterExternalDetail": {}, + "filterInStock": "במלאי", + "@filterInStock": {}, + "filterInStockDetail": "הצג פריטים שיש להם מלאי", + "@filterInStockDetail": {}, + "filterSerialized": "בסדרה", + "@filterSerialized": {}, + "filterSerializedDetail": "הצג פריטי מלאי בסדרה", + "@filterSerializedDetail": {}, + "filterTemplate": "תבנית", + "@filterTemplate": {}, + "filterTemplateDetail": "הצג חלקי תבנית", + "@filterTemplateDetail": {}, + "filterTrackable": "ניתן למעקב", + "@filterTrackable": {}, + "filterTrackableDetail": "הצג פריטים שניתנים למעקב", + "@filterTrackableDetail": {}, + "filterVirtual": "וירטואלי", + "@filterVirtual": {}, + "filterVirtualDetail": "הצג פריטים וירטואלים", + "@filterVirtualDetail": {}, + "filteringOptions": "אפשרויות סינון", + "@filteringOptions": {}, + "formatException": "חריגה בפורמט", + "@formatException": {}, + "formatExceptionJson": "חריגה בפורמט הנתונים של JSON", + "@formatExceptionJson": {}, + "formError": "שגיאת טופס", + "@formError": {}, + "history": "היסטוריה", + "@history": { + "description": "history" + }, + "home": "בית", + "@home": {}, + "homeScreen": "מסך הבית", + "@homeScreen": {}, + "homeScreenSettings": "הגדר את הגדרות מסך הבית", + "@homeScreenSettings": {}, + "homeShowPo": "הצג הזמנות רכש", + "@homeShowPo": {}, + "homeShowPoDescription": "הצג את לחצן הזמנת רכש במסך הבית", + "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "הצג הזמנות מכירה", + "@homeShowSo": {}, + "homeShowSoDescription": "הצג את לחצן הזמנות מכירה במסך הבית", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "פריטי מנויים", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "הצכ פריטים רשומים במסך הבית", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "הצג ספקים", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "הצג לחצן ספקים במסך הבית", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "הצג יצרנים", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "הצג את לחצן היצרן במסך הבית", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "הצג לקוחות", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "הצג את לחצן הלקוחות במסך הבית", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "העלאת התמונה נכשלה", + "@imageUploadFailure": {}, + "imageUploadSuccess": "התמונה הועלתה", + "@imageUploadSuccess": {}, + "inactive": "לא פעיל", + "@inactive": {}, + "inactiveCompany": "חברה זו מסומנת כלא פעילה", + "@inactiveCompany": {}, + "inactiveDetail": "פריט זה מסומן כלא פעיל", + "@inactiveDetail": {}, + "includeSubcategories": "כלול קטגוריות משנה", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "הצג תוצאות מקטגוריות משנה", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "כלול מיקומי משנה", + "@includeSublocations": {}, + "includeSublocationsDetail": "הצג תוצאות ממיקומי משנה", + "@includeSublocationsDetail": {}, + "incompleteDetails": "פרטי פרופיל לא מלאים", + "@incompleteDetails": {}, + "internalPartNumber": "מספר פריט פנימי", + "@internalPartNumber": {}, + "info": "מידע", + "@info": {}, + "inProduction": "בתהליך ייצור", + "@inProduction": {}, + "inProductionDetail": "פריט מלאי זה נמצא בייצור", + "@inProductionDetail": {}, + "internalPart": "פריט פנימי", + "@internalPart": {}, + "invalidHost": "שם מארח לא חוקי", + "@invalidHost": {}, + "invalidHostDetails": "שם המארח שסופק אינו חוקי", + "@invalidHostDetails": {}, + "invalidPart": "פריט לא חוקי", + "@invalidPart": {}, + "invalidPartCategory": "קטגוריית פריט לא חוקית", + "@invalidPartCategory": {}, + "invalidStockLocation": "מיקום מלאי לא חוקי", + "@invalidStockLocation": {}, + "invalidStockItem": "פריט מלאי לא חוקי", + "@invalidStockItem": {}, + "invalidSupplierPart": "פריט ספק לא חוקי", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "שילוב שם משתמש/סיסמה לא תקין", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "להנפיק", + "@issue": {}, + "issueDate": "תאריך הנפקה", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "הפריט כבר נמצא במיקום", + "@itemInLocation": {}, + "itemDeleted": "הפרריט הוסר", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "מילות מפתח", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "הדפסת תווית", + "@labelPrinting": {}, + "labelPrintingDetail": "אפשר הדפסת תווית", + "@labelPrintingDetail": {}, + "labelTemplate": "תבנית תווית", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "language": "שפה", + "@language": {}, + "languageDefault": "שפת מערכת ברירת מחדל", + "@languageDefault": {}, + "languageSelect": "בחירת שפה", + "@languageSelect": {}, + "lastStocktake": "סקר אחרון", + "@lastStocktake": {}, + "lastUpdated": "עודכן לאחרונה", + "@lastUpdated": {}, + "level": "רמה", + "@level": {}, + "lineItemAdd": "הוסף שורת פריט", + "@lineItemAdd": {}, + "lineItem": "שורת פריט", + "@lineItem": {}, + "lineItems": "שורת פריט", + "@lineItems": {}, + "lineItemUpdated": "שורת פריט עודכנה", + "@lineItemUpdated": {}, + "locateItem": "אתר פריט במלאי", + "@locateItem": {}, + "locateLocation": "אתר את מיקום המלאי", + "@locateLocation": {}, + "locationCreate": "מיקום חדש", + "@locationCreate": {}, + "locationCreateDetail": "צור מיקום מלאי חדש", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "לא צוין מיקום", + "@locationNotSet": {}, + "locationUpdated": "מיקום המלאי עודכן", + "@locationUpdated": {}, + "login": "כניסה למערכת", + "@login": {}, + "loginEnter": "הזן פרטי כניסה", + "@loginEnter": {}, + "loginEnterDetails": "שם המשתמש והכניסה אינם מאוחסנים באופן מקומי", + "@loginEnterDetails": {}, + "link": "קישור", + "@link": {}, + "lost": "אבודים", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "מספר פריט של היצרן", + "@manufacturerPartNumber": {}, + "manufacturer": "יצרן", + "@manufacturer": {}, + "manufacturers": "יצרנים", + "@manufacturers": {}, + "missingData": "נתונים חסרים", + "@missingData": {}, + "name": "שם", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "לא מחובר", + "@notConnected": {}, + "notes": "הערות", + "@notes": { + "description": "Notes" + }, + "notifications": "התראות", + "@notifications": {}, + "notificationsEmpty": "אין התראות שלא נקראו", + "@notificationsEmpty": {}, + "noResponse": "אין תגובה מהשרת", + "@noResponse": {}, + "noResults": "אין תוצאות", + "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, + "noSubcategories": "אין קטגורית משנה", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "אין קטכוריות משנה זמינות", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "מספר לא חוקי", + "@numberInvalid": {}, + "onOrder": "בהזמנה", + "@onOrder": {}, + "onOrderDetails": "פריטים בהזמנה כרגע", + "@onOrderDetails": {}, + "orientation": "כוון מסך", + "@orientation": {}, + "orientationDetail": "כוון מסך [דורש הפעלה מחדש]", + "@orientationDetail": {}, + "orientationLandscape": "Landscape", + "@orientationLandscape": {}, + "orientationPortrait": "דיוקן [פורטרט]", + "@orientationPortrait": {}, + "orientationSystem": "מערכת", + "@orientationSystem": {}, + "outstanding": "הזמנות יוצאות דופן", + "@outstanding": {}, + "outstandingOrderDetail": "הצג הזמנות יוצאות דופן", + "@outstandingOrderDetail": {}, + "overdue": "באיחור", + "@overdue": {}, + "overdueDetail": "הצג הזמנות באיחור", + "@overdueDetail": {}, + "packaging": "אריזה", + "@packaging": {}, + "packageName": "שם החבילה", + "@packageName": {}, + "parameters": "פרמטרים", + "@parameters": {}, + "parametersSettingDetail": "הצגת פרמטרים של פריטים", + "@parametersSettingDetail": {}, + "parent": "Parent", + "@parent": {}, + "parentCategory": "Parent Category", + "@parentCategory": {}, + "parentLocation": "Parent Location", + "@parentLocation": {}, + "part": "פריט", + "@part": { + "description": "Part (single)" + }, + "partCreate": "פריט חדש", + "@partCreate": {}, + "partCreateDetail": "צור פריט חדש בקטגוריה זו", + "@partCreateDetail": {}, + "partEdited": "פריט עודכן", + "@partEdited": {}, + "parts": "פריטים", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "פריט לא סומן כניתן למכירה", + "@partNotSalable": {}, + "partsNone": "אין פריטים", + "@partsNone": {}, + "partNoResults": "אין פריטים התואמים לשאילתה", + "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "partSettings": "הגדרות פריט", + "@partSettings": {}, + "partsStarred": "Subscribed Parts", + "@partsStarred": {}, + "partsStarredNone": "אין פריטים זמינים שמסומנים בכוכב", + "@partsStarredNone": {}, + "partSuppliers": "ספקי פריטים", + "@partSuppliers": {}, + "partCategory": "קטגוריית פריט", + "@partCategory": {}, + "partCategoryTopLevel": "קטגוריית פריטים ברמה עליונה", + "@partCategoryTopLevel": {}, + "partCategories": "קטגוריית פריטים", + "@partCategories": {}, + "partDetails": "פרטי פריט", + "@partDetails": {}, + "partNotes": "הערות פריט", + "@partNotes": {}, + "partStock": "מלאי פריט", + "@partStock": { + "description": "part stock" + }, + "password": "סיסמה", + "@password": {}, + "passwordEmpty": "הסיסמה לא יכולה להיות ריקה", + "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "לחשבון זה אין את ההרשאות לבצע פעולה זו", + "@permissionAccountDenied": {}, + "permissionRequired": "נדרשת הרשאה", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": "Profile Name", + "@profileName": {}, + "profileNone": "אין פרופילים זמינים", + "@profileNone": {}, + "profileNotSelected": "לא נבחר פרופיל", + "@profileNotSelected": {}, + "profileSelect": "בחר שרת InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "בחר שרת או צור פרופיל חדש", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "הקש כדי לבחור או ליצור פרופיל", + "@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", + "@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": "הזמנות רכש עודכנו", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "מרענן", + "@refreshing": {}, + "rejected": "נדחה", + "@rejected": {}, + "releaseNotes": "הערות פרסום", + "@releaseNotes": {}, + "remove": "להסיר", + "@remove": { + "description": "remove" + }, + "removeStock": "הסר מלאי", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "דווח על באג", + "@reportBug": {}, + "reportBugDescription": "שלח דוח באג [דורש חשבון בגיט-האב]", + "@reportBugDescription": {}, + "responsible": "Responsible", + "@responsible": {}, + "results": "תוצאות", + "@results": {}, + "request": "בקשה", + "@request": {}, + "requestFailed": "הבקשה נכשלה", + "@requestFailed": {}, + "requestSuccessful": "הבקשה מוצלחת", + "@requestSuccessful": {}, + "requestingData": "מבקש נתונים", + "@requestingData": {}, + "required": "דרוש", + "@required": { + "description": "This field is required" + }, + "response400": "בקשה לא תקינה", + "@response400": {}, + "response401": "לא מורשה", + "@response401": {}, + "response403": "הרשאה נדחיתה", + "@response403": {}, + "response404": "משאב לא נמצא", + "@response404": {}, + "response405": "שיטה לא מורשית", + "@response405": {}, + "response429": "יותר מידי בקשות", + "@response429": {}, + "response500": "שגיאת שרת פנימית", + "@response500": {}, + "response501": "לא מיושם", + "@response501": {}, + "response502": "קישור GetAway לא תקין", + "@response502": {}, + "response503": "השירות אינו זמין", + "@response503": {}, + "response504": "טיים אאוט גט אוואי", + "@response504": {}, + "response505": "גרסת HTTP לא נתמכת", + "@response505": {}, + "responseData": "Response data", + "@responseData": {}, + "responseInvalid": "Invalid Response Code", + "@responseInvalid": {}, + "responseUnknown": "תגובה לא ידועה", + "@responseUnknown": {}, + "result": "תוצאה", + "@result": { + "description": "" + }, + "returned": "החזרות", + "@returned": {}, + "salesOrder": "הזמנת מכירה", + "@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": "ערוך הזמנת מכירות", + "@salesOrderEdit": {}, + "salesOrderUpdated": "הזמנת מכירות עודכנה", + "@salesOrderUpdated": {}, + "save": "שמור", + "@save": { + "description": "Save" + }, + "scanBarcode": "סרוק ברקוד", + "@scanBarcode": {}, + "scanSupplierPart": "סרוק ברקוד פריט של ספק", + "@scanSupplierPart": {}, + "scanIntoLocation": "סרוק למיקום", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "סרוק פריט זה למיקום", + "@scanIntoLocationDetail": {}, + "scannerExternal": "סורק חיצוני", + "@scannerExternal": {}, + "scannerExternalDetail": "השתמש בסורק חיצוני לסריקת ברקודים [מצב טריז]", + "@scannerExternalDetail": {}, + "scanReceivedParts": "סרוק פריטים שהתקבלו", + "@scanReceivedParts": {}, + "search": "חפש", + "@search": { + "description": "search" + }, + "searching": "מחפש", + "@searching": {}, + "searchLocation": "חפש מיקום", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "חיפוש פריטים", + "@searchParts": {}, + "searchStock": "חפש מלאי", + "@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": "השרת חייב להתחיל עם Http[s]", + "@serverStart": {}, + "settings": "הגדרות", + "@settings": {}, + "serverInstance": "מופע שרת", + "@serverInstance": {}, + "serverNotConnected": "השרת לא מחובר", + "@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": "מק\"ט [מספר קטלוגי] ", + "@sku": {}, + "sounds": "צלילים", + "@sounds": {}, + "soundOnBarcodeAction": "השמעת צליל בפעולת ברקוד", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "השמעת צליל בשגיאת שרת", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "סטטוס", + "@status": {}, + "statusCode": "סטטוס קוד", + "@statusCode": {}, + "stock": "מלאי", + "@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": "פריט המלאי עודכן", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "עדכון פריט מלאי נכשל", + "@stockItemUpdateFailure": {}, + "stockLocation": "מיקום מלאי", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "מיקום מלאים", + "@stockLocations": {}, + "stockTopLevel": "מיקום מלאי ברמה עליונה ", + "@stockTopLevel": {}, + "strictHttps": "השתמש ב - HTTPS קפדני", + "@strictHttps": {}, + "strictHttpsDetails": "אכוף בדיקה קפדנית של אישורי Http's", + "@strictHttpsDetails": {}, + "subcategory": "קטגוריית משנה", + "@subcategory": {}, + "subcategories": "קטגוריות משנה", + "@subcategories": {}, + "sublocation": "מיקום משנה", + "@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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "takePicture": "צלם תמונה", + "@takePicture": {}, + "targetDate": "תאריך יעד", + "@targetDate": {}, + "templatePart": "פריט תבנית אב", + "@templatePart": {}, + "testName": "שם הבדיקה", + "@testName": {}, + "testPassedOrFailed": "המבחן עבר או נכשל", + "@testPassedOrFailed": {}, + "testsRequired": "Required Tests", + "@testsRequired": {}, + "testResults": "תוצאות המבחן", + "@testResults": { + "description": "" + }, + "testResultsDetail": "הצגת תוצאות בדיקת פריט במלאי", + "@testResultsDetail": {}, + "testResultAdd": "הוסף תוצאות בדיקה", + "@testResultAdd": {}, + "testResultNone": "אין תוצאות בדיקה", + "@testResultNone": {}, + "testResultNoneDetail": "אין תוצאות בדיקה זמינות", + "@testResultNoneDetail": {}, + "testResultUploadFail": "שגיאה בהעלאת תוצאות הבדיקה", + "@testResultUploadFail": {}, + "testResultUploadPass": "תוצאת הבדיקה הועלתה", + "@testResultUploadPass": {}, + "timeout": "פסק זמן [דילאיי]", + "@timeout": { + "description": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "שגיאת טוקן", + "@tokenError": {}, + "tokenMissing": "טוקן חסר", + "@tokenMissing": {}, + "tokenMissingFromResponse": "גישת טוקן חסרה בתגובה", + "@tokenMissingFromResponse": {}, + "totalPrice": "מחיר כולל", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "העבר", + "@transfer": { + "description": "transfer" + }, + "transferStock": "העברת מלאי", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "העברת פריט למקום אחר", + "@transferStockDetail": {}, + "transferStockLocation": "העברת מיקום מלאי", + "@transferStockLocation": {}, + "transferStockLocationDetail": "העבר את מיקום המלאי הזה למיקום אחר", + "@transferStockLocationDetail": {}, + "translate": "תרגם", + "@translate": {}, + "translateHelp": "עזרו לתרגם את אפליקציית InvenTree", + "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "מחיר ליחידה", + "@unitPrice": {}, + "units": "יחידות", + "@units": {}, + "unknownResponse": "תגובה לא ידועה", + "@unknownResponse": {}, + "upload": "העלה", + "@upload": {}, + "uploadFailed": "העלאת הקובץ נכשלה", + "@uploadFailed": {}, + "uploadSuccess": "הקובץ הועלה", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "בשימוש ב ", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "שם משתמש", + "@username": {}, + "usernameEmpty": "שם משתמש לא יכול להיות ריק", + "@usernameEmpty": {}, + "value": "ערך", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "ערך לא יכול להיות ריק", + "@valueCannotBeEmpty": {}, + "valueRequired": "נדרש ערך", + "@valueRequired": {}, + "variants": "גרסאות", + "@variants": {}, + "version": "גרסה", + "@version": {}, + "viewSupplierPart": "צפה בפריט הספק", + "@viewSupplierPart": {}, + "website": "אתר", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..6c8fde6 --- /dev/null +++ b/lib/l10n/hi_IN/app_hi_IN.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@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": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@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 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": "InvenTree बारकोड स्कैन करें", + "@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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..0144f68 --- /dev/null +++ b/lib/l10n/hu_HU/app_hu_HU.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Lefoglalva", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Négyzetes (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Készlet foglalása", + "@allocateStock": {}, + "allocatedStock": "Lefoglalt Készlet", + "@allocatedStock": {}, + "appReleaseNotes": "Kiadási közlemények", + "@appReleaseNotes": {}, + "appSettings": "Alkalmazásbeállítások", + "@appSettings": {}, + "appSettingsDetails": "Inventree alkalmazás beállításai", + "@appSettingsDetails": {}, + "assignedToMe": "Hozzámrendelt", + "@assignedToMe": {}, + "assignedToMeDetail": "Mutasd az én rendeléseim", + "@assignedToMeDetail": {}, + "attachments": "Mellékletek", + "@attachments": {}, + "attachImage": "Kép csatolása", + "@attachImage": { + "description": "Attach an image" + }, + "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", + "@attention": {}, + "available": "Elérhető", + "@available": {}, + "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", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Vonalkód beolvasása", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Olvasd le a vonalkódot a bevételezéshez", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Vonalkód olvasás megállítva", + "@barodeScanPaused": {}, + "barcodeScanPause": "Érintse meg a szkennelés szünetelteté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", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Olvass be egy InvenTree vonalkódot", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Készlet bevételezése erre a helyre", + "@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", + "@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": {}, + "bomEnable": "Alkatrészjegyzék megjelenítése", + "@bomEnable": {}, + "build": "Gyártás", + "@build": {}, + "building": "Gyártásban", + "@building": {}, + "cameraCreationError": "Nem sikerült a kameravezérlőt megnyitni", + "@cameraCreationError": {}, + "cameraInternal": "Belső kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Beépített kamera használata vonalkódolvasásra", + "@cameraInternalDetail": {}, + "cancel": "Mégsem", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Rendelés törlése", + "@cancelOrder": {}, + "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": {}, + "companyAdd": "Cég hozzáadása", + "@companyAdd": {}, + "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": {}, + "complete": "Kész", + "@complete": {}, + "completeOrder": "Rendelés teljesítése", + "@completeOrder": {}, + "completionDate": "Befejezés dátuma", + "@completionDate": {}, + "configureServer": "Kiszolgáló beállítások konfigurálása", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Leltározás", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Közreműködők", + "@credits": {}, + "crop": "Körbevágás", + "@crop": {}, + "cropImage": "Kép körbevágása", + "@cropImage": {}, + "customer": "Vevő", + "@customer": {}, + "customers": "Vevők", + "@customers": {}, + "customerReference": "Vevői azonosító", + "@customerReference": {}, + "damaged": "Sérült", + "@damaged": {}, + "colorScheme": "Színséma", + "@colorScheme": {}, + "colorSchemeDetail": "Színséma választása", + "@colorSchemeDetail": {}, + "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", + "@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": "Szállítási Dátum", + "@deliveryDate": {}, + "description": "Leírás", + "@description": {}, + "destination": "Cél", + "@destination": {}, + "destroyed": "Megsemmisült", + "@destroyed": {}, + "details": "Részletek", + "@details": { + "description": "details" + }, + "documentation": "Dokumentáció", + "@documentation": {}, + "downloadComplete": "Letöltés befejezve", + "@downloadComplete": {}, + "downloadError": "Hiba a kép letöltése közben", + "@downloadError": {}, + "downloading": "Fájl letöltése", + "@downloading": {}, + "edit": "Szerkesztés", + "@edit": { + "description": "edit" + }, + "editAttachment": "Csatolmány szerkesztése", + "@editAttachment": {}, + "editCategory": "Kategória szerkesztése", + "@editCategory": {}, + "editLocation": "Hely szerkesztése", + "@editLocation": {}, + "editNotes": "Megjegyzések szerkesztése", + "@editNotes": {}, + "editParameter": "Paraméter szerkesztése", + "@editParameter": {}, + "editPart": "Alkatrész szerkesztése", + "@editPart": { + "description": "edit part" + }, + "editItem": "Készlet tétel szerkesztése", + "@editItem": {}, + "editLineItem": "Sortétel szerkesztése", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Személytelen hibajelentések és összeomlási naplók feltöltése", + "@errorReportUploadDetails": {}, + "expiryDate": "Lejárati dátum", + "@expiryDate": {}, + "expiryExpired": "Lejárt", + "@expiryExpired": {}, + "expiryStale": "Elavult", + "@expiryStale": {}, + "extraLineItem": "Egyéb tétel", + "@extraLineItem": {}, + "extraLineItems": "Egyéb tételek", + "@extraLineItems": {}, + "feedback": "Visszajelzés", + "@feedback": {}, + "feedbackError": "Visszajelzés küldése sikertelen", + "@feedbackError": {}, + "feedbackSuccess": "Visszajelzés elküldve", + "@feedbackSuccess": {}, + "filterActive": "Aktív", + "@filterActive": {}, + "filterActiveDetail": "Aktív alkatrészek megjelenítése", + "@filterActiveDetail": {}, + "filterAssembly": "Összeszerelve", + "@filterAssembly": {}, + "filterAssemblyDetail": "Összeszerelt alkatrészek megjelenítése", + "@filterAssemblyDetail": {}, + "filterComponent": "Összetevő", + "@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", + "@filterInStockDetail": {}, + "filterSerialized": "Sorozatszámos", + "@filterSerialized": {}, + "filterSerializedDetail": "Sorozatszámos készlet megjelenítése", + "@filterSerializedDetail": {}, + "filterTemplate": "Sablon", + "@filterTemplate": {}, + "filterTemplateDetail": "Sablon alkatrészek megjelenítése", + "@filterTemplateDetail": {}, + "filterTrackable": "Követendő", + "@filterTrackable": {}, + "filterTrackableDetail": "Követendő alkatrészek megjelenítése", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuális", + "@filterVirtual": {}, + "filterVirtualDetail": "Virtuális alkatrészek megjelenítése", + "@filterVirtualDetail": {}, + "filteringOptions": "Szűrési beállítások", + "@filteringOptions": {}, + "formatException": "Formátum hiba", + "@formatException": {}, + "formatExceptionJson": "JSON adatformátum hiba", + "@formatExceptionJson": {}, + "formError": "Form hiba", + "@formError": {}, + "history": "Előzmények", + "@history": { + "description": "history" + }, + "home": "Főoldal", + "@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", + "@homeShowPo": {}, + "homeShowPoDescription": "Beszerzési rendelések gomb megjelenítése a főoldalon", + "@homeShowPoDescription": {}, + "homeShowShipments": "Szállítmányok Mutatása", + "@homeShowShipments": {}, + "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": {}, + "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", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Ez a vállalat inaktív lett", + "@inactiveCompany": {}, + "inactiveDetail": "Ez az alkatrész inaktív lett", + "@inactiveDetail": {}, + "includeSubcategories": "Alkategóriákkal együtt", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Eredmények az alkategóriákból is", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Alhelyekkel együtt", + "@includeSublocations": {}, + "includeSublocationsDetail": "Eredmények az alhelyekről is", + "@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": {}, + "internalPart": "Belső alkatrész", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Érvénytelen beszállítói alkatrész", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Érvénytelen felhasználónév/jelszó kombináció", + "@invalidUsernamePassword": {}, + "invoice": "Számla", + "@invoice": {}, + "invoiceNumber": "Számlaszám", + "@invoiceNumber": {}, + "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": {}, + "itemDeleted": "Termék el lett távolítva", + "@itemDeleted": {}, + "itemUpdated": "Tétel frissítve", + "@itemUpdated": {}, + "keywords": "Kulcsszavak", + "@keywords": {}, + "labelDriver": "Címke Meghajtó", + "@labelDriver": {}, + "labelSelectDriver": "Címkenyomtató Meghajtó Kiválasztása", + "@labelSelectDriver": {}, + "labelPrinting": "Címke nyomtatás", + "@labelPrinting": {}, + "labelPrintingDetail": "Címke nyomtatás engedélyezése", + "@labelPrintingDetail": {}, + "labelTemplate": "Címke sablon", + "@labelTemplate": {}, + "labelSelectTemplate": "Címke sablon kiválasztása", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Címke nyomtató kiválasztása", + "@labelSelectPrinter": {}, + "language": "Nyelv", + "@language": {}, + "languageDefault": "Alapértelmezett nyelv", + "@languageDefault": {}, + "languageSelect": "Nyelv kiválasztása", + "@languageSelect": {}, + "lastStocktake": "Utolsó leltár", + "@lastStocktake": {}, + "lastUpdated": "Utoljára módosítva", + "@lastUpdated": {}, + "level": "Szint", + "@level": {}, + "lineItemAdd": "Sortétel hozzáadása", + "@lineItemAdd": {}, + "lineItem": "Sortétel", + "@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", + "@locateLocation": {}, + "locationCreate": "Új hely", + "@locationCreate": {}, + "locationCreateDetail": "Új készlet hely létrehozása", + "@locationCreateDetail": {}, + "locationDefault": "Alapértelmezett Hely", + "@locationDefault": {}, + "locationNotSet": "Nincs megadva hely", + "@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", + "@lost": {}, + "manufacturerPart": "Gyártói alkatrész", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Gyártói alkatrész szerkesztése", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Gyártói cikkszám", + "@manufacturerPartNumber": {}, + "manufacturer": "Gyártó", + "@manufacturer": {}, + "manufacturers": "Gyártók", + "@manufacturers": {}, + "missingData": "Hiányzó adatok", + "@missingData": {}, + "name": "Név", + "@name": {}, + "no": "Nem", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Nincs kapcsolódva", + "@notConnected": {}, + "notes": "Megjegyzések", + "@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", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Érvénytelen szám", + "@numberInvalid": {}, + "onOrder": "Beszállítás alatt", + "@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": "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", + "@packageName": {}, + "parameters": "Paraméterek", + "@parameters": {}, + "parametersSettingDetail": "Alkatrész paraméterek megjelenítése", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Az alkatrész nincsen értékesíthetőnek jelölve", + "@partNotSalable": {}, + "partsNone": "Nincsenek alkatrészek", + "@partsNone": {}, + "partNoResults": "Nincs a lekérdezéssel egyező alkatrész", + "@partNoResults": {}, + "partPricing": "Alkatrész árazása", + "@partPricing": {}, + "partPricingSettingDetail": "Alkatrész árazási információk megjelenítése", + "@pricingSettingDetail": {}, + "partSettings": "Alkatrész beállítások", + "@partSettings": {}, + "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": {}, + "pending": "Függőben", + "@pending": {}, + "permissionAccountDenied": "Nincs meg a szükséges jogosultságod, hogy végrehajtsd ezt a műveletet", + "@permissionAccountDenied": {}, + "permissionRequired": "Engedély szükséges", + "@permissionRequired": {}, + "phone": "Telefonszám", + "@phone": {}, + "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", + "@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": {}, + "profileLogout": "Kijelentkezés", + "@profileLogout": {}, + "profileName": "Profil neve", + "@profileName": {}, + "profileNone": "Nincsenek profilok", + "@profileNone": {}, + "profileNotSelected": "Nincs kiválasztva profil", + "@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": {}, + "projectCode": "Projektszám", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Beolvasott adatok jóváhagyása", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Tételek részleteinek jóváhagyása beolvasás közben", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Beszerzési rendelések engedélyezése", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Értékesítési rendelés funkció aktiválása", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Kamera gyorsbillentyű", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Képfeltöltés shortcut engedélyezése az beszerzési rendelés oldalon", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Beszerzési rendelés", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Új beszerzési rendelés", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Beszerzési rendelés szerkesztése", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Beszerzési rendelés beállításai", + "@purchaseOrderSettings": {}, + "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" + }, + "quantityAvailable": "Elérhető mennyiség", + "@quantityAvailable": {}, + "quantityEmpty": "Mennyiség üres", + "@quantityEmpty": {}, + "quantityInvalid": "Mennyiség érvénytelen", + "@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", + "@received": {}, + "receivedFilterDetail": "Beérkezett készlet megjelenítése", + "@receivedFilterDetail": {}, + "receiveItem": "Bevételezés", + "@receiveItem": {}, + "receivedItem": "Beérkezett készlet", + "@receivedItem": {}, + "reference": "Azonosító", + "@reference": {}, + "refresh": "Frissítés", + "@refresh": {}, + "rotateClockwise": "Forgatás 90 fokkal óramutató járásával megegyező irányban", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Felelős", + "@responsible": {}, + "results": "Eredmények", + "@results": {}, + "request": "Kérés", + "@request": {}, + "requestFailed": "Kérés sikertelen", + "@requestFailed": {}, + "requestSuccessful": "Kérés sikeres", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Vevői rendelés", + "@salesOrder": {}, + "salesOrders": "Vevői rendelések", + "@salesOrders": {}, + "salesOrderEnable": "Vevői rendelések engedélyezése", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Értékesítési rendelés funkció aktiválása", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Kamera gyorsbillentyű", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Képfeltöltés shortcut engedélyezése az értékesítési rendelés oldalon", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Értékesítési rendelés beállításai", + "@salesOrderSettings": {}, + "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" + }, + "scanBarcode": "Vonalkód beolvasása", + "@scanBarcode": {}, + "scanSupplierPart": "Beszállítói cikk vonalkódjának beolvasása", + "@scanSupplierPart": {}, + "scanIntoLocation": "Beolvasás helyre", + "@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" + }, + "searching": "Keresés", + "@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", + "@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": {}, + "serialNumbers": "Sorozatszámok", + "@serialNumbers": {}, + "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": {}, + "serverNotSelected": "Nincs kiszolgáló választva", + "@serverNotSelected": {}, + "shipment": "Szállítmány", + "@shipment": {}, + "shipments": "Szállítmányok", + "@shipments": {}, + "shipmentsPending": "Függőben Lévő Szállítmányok", + "@shipmentsPending": {}, + "shipmentAdd": "Szállítmány hozzáadása", + "@shipmentAdd": {}, + "shipmentCheck": "Szállítmány Ellenőrzése", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Jelölje meg ezt a szállítmányt ellenőrzöttként", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Szállítmány Ellenőrizve", + "@shipmentChecked": {}, + "shipmentDate": "Szállítmány Dátuma", + "@shipmentDate": {}, + "shipmentEdit": "Szállítmány Szerkesztése", + "@shipmentEdit": {}, + "shipmentReference": "Szállítmány Hivatkozás", + "@shipmentReference": {}, + "shipmentSend": "Szállítmány Küldése", + "@shipmentSend": {}, + "shipmentUncheck": "Szállítmány Ellenőrzés Visszavonása", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Jelölje meg ezt a szállítmányt nem ellenőrzöttként", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Szállítmány Frissítve", + "@shipmentUpdated": {}, + "shipped": "Kiszállítva", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Hangok", + "@sounds": {}, + "soundOnBarcodeAction": "Hang lejátszása vonalkód műveletkor", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Hang lejátszása kiszolgálóhiba esetén", + "@soundOnServerError": {}, + "startDate": "Kezdő dátum", + "@startDate": {}, + "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": {}, + "supplierPart": "Beszállítói alkatrész", + "@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", + "@supplierParts": {}, + "suppliers": "Beszállítók", + "@suppliers": {}, + "supplierReference": "Beszállítói azonosító", + "@supplierReference": {}, + "switchCamera": "Kamera váltása", + "@switchCamera": {}, + "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": "" + }, + "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", + "@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": "" + }, + "toggleTorch": "Zseblámpa", + "@toggleTorch": {}, + "tokenError": "Token hiba", + "@tokenError": {}, + "tokenMissing": "Hiányzó token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Hozzáférési token hiányzik a válaszból", + "@tokenMissingFromResponse": {}, + "totalPrice": "Teljes ár", + "@totalPrice": {}, + "trackingNumber": "Nyomkövetési Szám", + "@trackingNumber": {}, + "transfer": "Áthelyezés", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Készlet áthelyezése", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Tétel áthelyezése egy másik helyre", + "@transferStockDetail": {}, + "transferStockLocation": "Készlet hely áthelyezése", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Készlet hely áthelyezése egy másikba", + "@transferStockLocationDetail": {}, + "translate": "Fordítás", + "@translate": {}, + "translateHelp": "Segíts lefordítani az InvenTree alkalmazást", + "@translateHelp": {}, + "unavailable": "Nem elérhető", + "@unavailable": {}, + "unavailableDetail": "Tétel nem elérhető", + "@unavailableDetail": {}, + "unitPrice": "Egységár", + "@unitPrice": {}, + "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": {}, + "uploadImage": "Kép feltöltése", + "@uploadImage": {}, + "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": {}, + "variants": "Változatok", + "@variants": {}, + "version": "Verzió", + "@version": {}, + "viewSupplierPart": "Beszállítói alkatrész megtekintése", + "@viewSupplierPart": {}, + "website": "Weboldal", + "@website": {}, + "yes": "Igen", + "@yes": {}, + "price": "Ár", + "@price": {}, + "priceRange": "Ártartomány", + "@priceRange": {}, + "priceOverrideMin": "Minimális Ár Felülbírálás", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximumális Ár Felülbírálás", + "@priceOverrideMax": {}, + "salePrice": "Eladási ár", + "@salePrice": {}, + "saleHistory": "Eladási előzmények", + "@saleHistory": {}, + "supplierPricing": "Beszállítói árazás", + "@supplierPricing": {}, + "bomCost": "Alkatrészjegyzék költség", + "@bomCost": {}, + "internalCost": "Belső költség", + "@internalCost": {}, + "variantCost": "Variáns költsége", + "@variantCost": {}, + "overallPricing": "Általános árazás", + "@overallPricing": {}, + "pricingOverrides": "Árazás felülbírálások", + "@pricingOverrides": {}, + "currency": "Pénznem", + "@currency": {}, + "priceBreaks": "Ársávok", + "@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 new file mode 100644 index 0000000..7cce4a5 --- /dev/null +++ b/lib/l10n/id_ID/app_id_ID.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "id", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Tentang", + "@about": {}, + "accountDetails": "Rincian Akun", + "@accountDetails": {}, + "actions": "Tindakan", + "@actions": { + "description": "" + }, + "actionsNone": "Tidak ada aksi yang tersedia", + "@actionsNone": {}, + "add": "Tambah", + "@add": { + "description": "add" + }, + "addStock": "Tambah Stok", + "@addStock": { + "description": "add stock" + }, + "address": "Alamat", + "@address": {}, + "appAbout": "Tentang InvenTree", + "@appAbout": {}, + "appCredits": "App kredit tambahan", + "@appCredits": {}, + "appDetails": "Rincian Aplikasi", + "@appDetails": {}, + "allocated": "Dialokasikan", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Persegi (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Alokasikan Stok", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Tampilkan catatan rilis aplikasi", + "@appReleaseNotes": {}, + "appSettings": "Pengaturan Aplikasi", + "@appSettings": {}, + "appSettingsDetails": "Konfigurasikan pengaturan aplikasi InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Ditugaskan kepada Saya", + "@assignedToMe": {}, + "assignedToMeDetail": "Tampilkan pesanan yang ditugaskan kepada saya", + "@assignedToMeDetail": {}, + "attachments": "Lampiran", + "@attachments": {}, + "attachImage": "Melampirkan Gambar", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Tidak ada lampiran yang ditemukan", + "@attachmentNone": {}, + "attachmentNoneDetail": "Tidak ada lampiran yang ditemukan", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Pilih lampiran", + "@attachmentSelect": {}, + "attention": "Perhatian", + "@attention": {}, + "available": "Tersedia", + "@available": {}, + "availableStock": "Stok Tersedia", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Pengaturan barcode", + "@barcodeSettings": {}, + "barcodeAssign": "Tetapkan barcode", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Pindai barcode khusus untuk menetapkan", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Barcode ditetapkan", + "@barcodeAssigned": {}, + "barcodeError": "Kesalahan Pemindaian barcode", + "@barcodeError": {}, + "barcodeInUse": "Barcode telah ditetapkan", + "@barcodeInUse": {}, + "barcodeMissingHash": "Data hash barcode hilang dari respons", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Tidak ada kecocokan untuk barcode", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode tidak ditetapkan", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Pindai barcode Part", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Pindai barcode untuk menerima Part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Pemindaian barcode dijeda", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Pindai untuk menetapkan barcode", + "@barcodeScanAssign": {}, + "barcodeScanController": "Input pemindai", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Pilih sumber input pemindai barcode", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Penundaan Pemindaian barcode", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Penundaan antara pemindaian barcode", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Pindai barcode InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Pindai item stok ke lokasi ini", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Mode Pemindaian Tunggal", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Jeda pemindai barcode setelah setiap pemindaian", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Dipindai ke lokasi", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Item tidak dipindai di", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Pindai item stok", + "@barcodeScanItem": {}, + "barcodeTones": "Nada barcode", + "@barcodeTones": {}, + "barcodeUnassign": "Batalkan Penetapan barcode", + "@barcodeUnassign": {}, + "barcodeUnknown": "barcode tidak dikenali", + "@barcodeUnknown": {}, + "batchCode": "barcode batch", + "@batchCode": {}, + "billOfMaterials": "Daftar bahan", + "@billOfMaterials": {}, + "bom": "Bill Of Materials", + "@bom": {}, + "bomEnable": "Tampilkan Daftar Bahan Baku", + "@bomEnable": {}, + "build": "Membangun", + "@build": {}, + "building": "Bangunan", + "@building": {}, + "cameraCreationError": "Tidak dapat membuka pengontrol kamera", + "@cameraCreationError": {}, + "cameraInternal": "Kamera Internal", + "@cameraInternal": {}, + "cameraInternalDetail": "Gunakan internal kamera untuk membaca barcode", + "@cameraInternalDetail": {}, + "cancel": "Batalkan", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Batalkan Pesanan", + "@cancelOrder": {}, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Kategori Baru", + "@categoryCreate": {}, + "categoryCreateDetail": "Buat kategori Part baru", + "@categoryCreateDetail": {}, + "categoryUpdated": "Kategori Part diperbarui", + "@categoryUpdated": {}, + "company": "Perusahaan", + "@company": {}, + "companyAdd": "Tambahkan Perusahaan", + "@companyAdd": {}, + "companyEdit": "Rubah Perusahaan", + "@companyEdit": {}, + "companyNoResults": "Tidak ada perusahaan yang cocok dengan query", + "@companyNoResults": {}, + "companyUpdated": "Detail perusahaan diperbarui", + "@companyUpdated": {}, + "companies": "Perusahaan", + "@companies": {}, + "complete": "Selesai", + "@complete": {}, + "completeOrder": "Lengkapi Pesanan", + "@completeOrder": {}, + "completionDate": "Tanggal Selesai", + "@completionDate": {}, + "configureServer": "Konfigurasikan pengaturan server", + "@configureServer": {}, + "confirmScan": "Konfirmasi Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Konfirmasikan detail transfer stok saat memindai barcode", + "@confirmScanDetail": {}, + "connectionRefused": "Koneksi ditolak", + "@connectionRefused": {}, + "count": "Hitung", + "@count": { + "description": "Count" + }, + "countStock": "Hitung stok", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Kredit", + "@credits": {}, + "crop": "Pangkas", + "@crop": {}, + "cropImage": "Pangkas Gambar", + "@cropImage": {}, + "customer": "Pelanggan", + "@customer": {}, + "customers": "Pelanggan", + "@customers": {}, + "customerReference": "Refensi Pelanggan", + "@customerReference": {}, + "damaged": "Rusak", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Mode Gelap", + "@darkMode": {}, + "darkModeEnable": "Aktifkan mode gelap", + "@darkModeEnable": {}, + "delete": "Hapus", + "@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", + "@destination": {}, + "destroyed": "Hancur", + "@destroyed": {}, + "details": "Detail", + "@details": { + "description": "details" + }, + "documentation": "Dokumentasi", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Mengunduh File", + "@downloading": {}, + "edit": "Sunting", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "Sunting Kategori", + "@editCategory": {}, + "editLocation": "Ubah Lokasi", + "@editLocation": {}, + "editNotes": "Ubah Catatan", + "@editNotes": {}, + "editParameter": "Edit parameter", + "@editParameter": {}, + "editPart": "Edit part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit stok item", + "@editItem": {}, + "editLineItem": "Edit item baris", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Masukkan Kata Sandi", + "@enterPassword": {}, + "enterUsername": "Masukkan Nama Pengguna", + "@enterUsername": {}, + "error": "Galat", + "@error": { + "description": "Error" + }, + "errorCreate": "Kesalahan saat membuat entri database", + "@errorCreate": {}, + "errorDelete": "Kesalahan saat menghapus entri database", + "@errorDelete": {}, + "errorDetails": "Detail kesalahan", + "@errorDetails": {}, + "errorFetch": "Kesalahan saat mengambil data dari server", + "@errorFetch": {}, + "errorUserRoles": "Kesalahan saat meminta peran pengguna dari server", + "@errorUserRoles": {}, + "errorPluginInfo": "Kesalahan saat meminta data plugin dari server", + "@errorPluginInfo": {}, + "errorReporting": "Pelaporan kesalahan", + "@errorReporting": {}, + "errorReportUpload": "Unggahan Laporan Kesalahan", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Unggah laporan kesalahan anonim dan log kerusakan", + "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "Umpan Balik", + "@feedback": {}, + "feedbackError": "Kesalahan saat mengirimkan umpan balik", + "@feedbackError": {}, + "feedbackSuccess": "Umpan balik dikirimkan", + "@feedbackSuccess": {}, + "filterActive": "Aktif", + "@filterActive": {}, + "filterActiveDetail": "Tampilkan komponen aktif", + "@filterActiveDetail": {}, + "filterAssembly": "Dirakit", + "@filterAssembly": {}, + "filterAssemblyDetail": "Tampilkan Part yang dirakit", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponen", + "@filterComponent": {}, + "filterComponentDetail": "Tampilkan komponen Part", + "@filterComponentDetail": {}, + "filterExternal": "Eksternal", + "@filterExternal": {}, + "filterExternalDetail": "Tampilkan stok di lokasi eksternal", + "@filterExternalDetail": {}, + "filterInStock": "Tersedia", + "@filterInStock": {}, + "filterInStockDetail": "Tampilkan part yang memiliki stok", + "@filterInStockDetail": {}, + "filterSerialized": "Serial", + "@filterSerialized": {}, + "filterSerializedDetail": "Tampilkan item stok yang diserialisasikan", + "@filterSerializedDetail": {}, + "filterTemplate": "Templat", + "@filterTemplate": {}, + "filterTemplateDetail": "Tampilkan Part templat", + "@filterTemplateDetail": {}, + "filterTrackable": "Dapat dilacak", + "@filterTrackable": {}, + "filterTrackableDetail": "Tampilkan Part yang dapat dilacak", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Tampilkan part virtual", + "@filterVirtualDetail": {}, + "filteringOptions": "Opsi Pemfilteran", + "@filteringOptions": {}, + "formatException": "Pengecualian format", + "@formatException": {}, + "formatExceptionJson": "Pengecualian format data JSON", + "@formatExceptionJson": {}, + "formError": "Kesalahan Formulir", + "@formError": {}, + "history": "Riwayat", + "@history": { + "description": "history" + }, + "home": "Beranda", + "@home": {}, + "homeScreen": "Tampilan Beranda", + "@homeScreen": {}, + "homeScreenSettings": "Konfigurasikan pengaturan layar beranda", + "@homeScreenSettings": {}, + "homeShowPo": "Tampilkan Pembelian Pesanan", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Penjelasan Suku Cadang", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Tampilkan suku cadang yang dilanggan di layar beranda", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Tampilkan Pemasok", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Show suppliers button on home screen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Show Manufacturers", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Show manufacturers button on home screen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Tunjukkan Pelanggan", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Show customers button on home screen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Image upload failed", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Gambar telah diunggah", + "@imageUploadSuccess": {}, + "inactive": "Tidak Aktif", + "@inactive": {}, + "inactiveCompany": "Perusahaan ini ditandai sebagai perusahaan non-aktif", + "@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": "Informasi", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Kata Kunci", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "language": "Bahasa", + "@language": {}, + "languageDefault": "Default system language", + "@languageDefault": {}, + "languageSelect": "Pilih Bahasa", + "@languageSelect": {}, + "lastStocktake": "Last Stocktake", + "@lastStocktake": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "level": "Tingkat", + "@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": "Lokasi Baru", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": "Pranala", + "@link": {}, + "lost": "Lost", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Data Hilang", + "@missingData": {}, + "name": "Nama", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Tidak Tersambung", + "@notConnected": {}, + "notes": "Catatan", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifikasi", + "@notifications": {}, + "notificationsEmpty": "Tidak ada notifikasi yang belum dibaca", + "@notificationsEmpty": {}, + "noResponse": "Tidak ada respon dari server", + "@noResponse": {}, + "noResults": "Tidak ada hasil", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nomor tidak valid", + "@numberInvalid": {}, + "onOrder": "Pada Pesanan", + "@onOrder": {}, + "onOrderDetails": "Item yang saat ini sedang dipesan", + "@onOrderDetails": {}, + "orientation": "Orientasi Layar", + "@orientation": {}, + "orientationDetail": "Orientasi layar (perlu memulai ulang)", + "@orientationDetail": {}, + "orientationLandscape": "Lanskap", + "@orientationLandscape": {}, + "orientationPortrait": "Tegak", + "@orientationPortrait": {}, + "orientationSystem": "Sistem", + "@orientationSystem": {}, + "outstanding": "Belum Selesai", + "@outstanding": {}, + "outstandingOrderDetail": "Tampilkan pesanan yang belum selesai", + "@outstandingOrderDetail": {}, + "overdue": "Terlambat", + "@overdue": {}, + "overdueDetail": "Tampilkan pesanan yang terlambat", + "@overdueDetail": {}, + "packaging": "Kemasan", + "@packaging": {}, + "packageName": "Nama Paket", + "@packageName": {}, + "parameters": "Parameter", + "@parameters": {}, + "parametersSettingDetail": "Tampilkan parameter komponen", + "@parametersSettingDetail": {}, + "parent": "Induk", + "@parent": {}, + "parentCategory": "Kategori Induk", + "@parentCategory": {}, + "parentLocation": "Lokasi Orang Tua", + "@parentLocation": {}, + "part": "Part", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Part baru", + "@partCreate": {}, + "partCreateDetail": "Buat kategori Part baru", + "@partCreateDetail": {}, + "partEdited": "Part diperbarui", + "@partEdited": {}, + "parts": "Parts", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Part tidak ditandai sebagai dapat dijual", + "@partNotSalable": {}, + "partsNone": "Tanpa Part", + "@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", + "@partsStarred": {}, + "partsStarredNone": "Tidak ada part yang diberi bintang yang tersedia", + "@partsStarredNone": {}, + "partSuppliers": "Pemasok Part", + "@partSuppliers": {}, + "partCategory": "Kategori Part", + "@partCategory": {}, + "partCategoryTopLevel": "Kategori Part tingkat atas", + "@partCategoryTopLevel": {}, + "partCategories": "kategori Part", + "@partCategories": {}, + "partDetails": "Detail Part", + "@partDetails": {}, + "partNotes": "Catatan Part", + "@partNotes": {}, + "partStock": "Stok Part", + "@partStock": { + "description": "part stock" + }, + "password": "Kata Sandi", + "@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", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "printLabel": "Cetak Label", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Mesin Cetak", + "@pluginPrinter": {}, + "pluginSupport": "Dukungan Plugin Diaktifkan", + "@pluginSupport": {}, + "pluginSupportDetail": "Server mendukung plugin khusus", + "@pluginSupportDetail": {}, + "printLabelFailure": "Pencetakan label gagal", + "@printLabelFailure": {}, + "printLabelSuccess": "Label dikirim ke printer", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Tambah Profil Server", + "@profileAdd": {}, + "profileConnect": "Sambung ke Server", + "@profileConnect": {}, + "profileEdit": "Edit Profil Server", + "@profileEdit": {}, + "profileDelete": "Hapus Profil Server", + "@profileDelete": {}, + "profileLogout": "Keluar dari Profil", + "@profileLogout": {}, + "profileName": "Profil Nama", + "@profileName": {}, + "profileNone": "Tidak ada profil yang tersedia", + "@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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Purchase Price", + "@purchasePrice": {}, + "quantity": "Jumlah", + "@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": "Telah diterima", + "@received": {}, + "receivedFilterDetail": "Show received items", + "@receivedFilterDetail": {}, + "receiveItem": "Item yang diterima", + "@receiveItem": {}, + "receivedItem": "Received Stock Item", + "@receivedItem": {}, + "reference": "Reference", + "@reference": {}, + "refresh": "Segarkan", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "Refreshing", + "@refreshing": {}, + "rejected": "Ditolak", + "@rejected": {}, + "releaseNotes": "Catatan Rilis", + "@releaseNotes": {}, + "remove": "Hapus", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Laporkan Masalah", + "@reportBug": {}, + "reportBugDescription": "Submit bug report (requires GitHub account)", + "@reportBugDescription": {}, + "responsible": "Responsible", + "@responsible": {}, + "results": "Hasil", + "@results": {}, + "request": "Permintaan", + "@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": "Hasil", + "@result": { + "description": "" + }, + "returned": "Returned", + "@returned": {}, + "salesOrder": "Sales Order", + "@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", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Sales order updated", + "@salesOrderUpdated": {}, + "save": "Simpan", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scan Barcode", + "@scanBarcode": {}, + "scanSupplierPart": "Scan supplier part barcode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Pindai Ke Lokasi", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Pindai item ini ke lokasi", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Pemindai Eksternal", + "@scannerExternal": {}, + "scannerExternalDetail": "Gunakan pemindai eksternal untuk membaca barcode (mode baji)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Pindai Komponen yang Diterima", + "@scanReceivedParts": {}, + "search": "Cari", + "@search": { + "description": "search" + }, + "searching": "Mencari", + "@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", + "@searchStock": {}, + "select": "Pilih", + "@select": {}, + "selectFile": "Pilih Berkas", + "@selectFile": {}, + "selectImage": "Pilih Gambar", + "@selectImage": {}, + "selectLocation": "Pilih Lokasi", + "@selectLocation": {}, + "send": "Kirim", + "@send": {}, + "serialNumber": "Nomor Seri", + "@serialNumber": {}, + "serialNumbers": "Nomor Seri", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Alamat Server", + "@serverAddress": {}, + "serverApiRequired": "Versi API yang diperlukan", + "@serverApiRequired": {}, + "serverApiVersion": "Versi API Server", + "@serverApiVersion": {}, + "serverAuthenticationError": "Kesalahan Autentikasi", + "@serverAuthenticationError": {}, + "serverCertificateError": "Kesalahan Sertifikat", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Sertifikat HTTPS server tidak valid", + "@serverCertificateInvalid": {}, + "serverConnected": "Sambung ke Server", + "@serverConnected": {}, + "serverConnecting": "Menghubungkan ke server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Tidak dapat terhubung ke server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Server tidak boleh kosong", + "@serverEmpty": {}, + "serverError": "Galat Server", + "@serverError": {}, + "serverDetails": "Detail Server", + "@serverDetails": {}, + "serverMissingData": "Respons server tidak memiliki kolom yang diperlukan", + "@serverMissingData": {}, + "serverOld": "Versi Server Lama", + "@serverOld": {}, + "serverSettings": "Pengaturan Server", + "@serverSettings": {}, + "serverStart": "Server harus dimulai dengan http[s]", + "@serverStart": {}, + "settings": "Pengaturan", + "@settings": {}, + "serverInstance": "Instans Server", + "@serverInstance": {}, + "serverNotConnected": "Server tidak terhubung", + "@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", + "@sku": {}, + "sounds": "Suara", + "@sounds": {}, + "soundOnBarcodeAction": "Putar nada suara pada tindakan Barcode", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Putar nada suara pada kesalahan server", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "Status", + "@status": {}, + "statusCode": "Kode Status", + "@statusCode": {}, + "stock": "Persediaan", + "@stock": { + "description": "stock" + }, + "stockDetails": "Jumlah stok yang tersedia saat ini", + "@stockDetails": {}, + "stockItem": "Stok Item", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Item Stok", + "@stockItems": {}, + "stockItemCreate": "Unit Persediaan Baru", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Buat item stok baru di lokasi ini", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Hapus item stok", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Apakah Anda yakin ingin menghapus item stok ini?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Tidak dapat menghapus item stok", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "item stok dihapus", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Riwayat Stok", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Tampilkan informasi pelacakan stok historis", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Item stok ditransfer", + "@stockItemTransferred": {}, + "stockItemUpdated": "Item stok diperbarui", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Tidak ada item stok yang tersedia", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Catatan Item Stok", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Item stok diperbarui", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Pembaruan item stok gagal", + "@stockItemUpdateFailure": {}, + "stockLocation": "lokasi stok", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lokasi Stok", + "@stockLocations": {}, + "stockTopLevel": "Lokasi stok tingkat atas", + "@stockTopLevel": {}, + "strictHttps": "Gunakan HTTPS Ketat", + "@strictHttps": {}, + "strictHttpsDetails": "Enforce strict checking of HTTPs certificates", + "@strictHttpsDetails": {}, + "subcategory": "Subkategori", + "@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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "takePicture": "Ambil Gambar", + "@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": "Waktu Habis", + "@timeout": { + "description": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Harga", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": "Terjemahkan", + "@translate": {}, + "translateHelp": "Help translate the InvenTree app", + "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Harga Unit", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Unggah", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "Berkas telah diunggah", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "Used In", + "@usedIn": {}, + "usedInDetails": "Assemblies which require this part", + "@usedInDetails": {}, + "username": "Nama Pengguna", + "@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": "Versi", + "@version": {}, + "viewSupplierPart": "View Supplier Part", + "@viewSupplierPart": {}, + "website": "Situs", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..6683476 --- /dev/null +++ b/lib/l10n/it_IT/app_it_IT.arb @@ -0,0 +1,1215 @@ +{ + "@@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" + }, + "addStock": "Aggiungi Giacenza", + "@addStock": { + "description": "add stock" + }, + "address": "Indirizzo", + "@address": {}, + "appAbout": "Info su InvenTree", + "@appAbout": {}, + "appCredits": "Riconoscimenti addizionali", + "@appCredits": {}, + "appDetails": "Dettagli App", + "@appDetails": {}, + "allocated": "Allocato", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Quadrato (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Alloca stock", + "@allocateStock": {}, + "allocatedStock": "Scorte Assegnate", + "@allocatedStock": {}, + "appReleaseNotes": "Mostra le note di rilascio dell'app", + "@appReleaseNotes": {}, + "appSettings": "Impostazioni App", + "@appSettings": {}, + "appSettingsDetails": "Configura le impostazioni dell'app InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Assegnato a me", + "@assignedToMe": {}, + "assignedToMeDetail": "Mostra gli ordini che mi sono stati assegnati", + "@assignedToMeDetail": {}, + "attachments": "Allegati", + "@attachments": {}, + "attachImage": "Allega Immagine", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nessun allegato trovato", + "@attachmentNone": {}, + "attachmentNoneDetail": "Nessun allegato trovato", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Seleziona allegato", + "@attachmentSelect": {}, + "attention": "Attenzione", + "@attention": {}, + "available": "Disponibile", + "@available": {}, + "availableStock": "Giacenza Disponibile", + "@availableStock": {}, + "barcodes": "Codici a barre", + "@barcodes": {}, + "barcodeSettings": "Impostazioni codici a barre", + "@barcodeSettings": {}, + "barcodeAssign": "Assegna Codice A Barre", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scansiona codice a barre personalizzato da assegnare", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Scansiona codice a barre del prodotto", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scansiona codice a barre per ricevere la parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Scansione codice a barre in pausa", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tocca per mettere in pausa la scansione", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scansiona per assegnare codice a barre", + "@barcodeScanAssign": {}, + "barcodeScanController": "Input scanner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Seleziona sorgente d'ingresso scanner per codici a barre", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Ritardo scansione codice a barre", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Ritardo tra scansioni di codici a barre", + "@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": "Modalità scansione singola", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Sospendi scanner di codici a barre dopo ogni scansione", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Scansionato nell'ubicazione", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Oggetto non scansionato in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scansiona elemento in giacenza", + "@barcodeScanItem": {}, + "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": {}, + "bomEnable": "Visualizza Distinta base", + "@bomEnable": {}, + "build": "Crea", + "@build": {}, + "building": "In Costruzione", + "@building": {}, + "cameraCreationError": "Impossibile aprire il controllo della fotocamera", + "@cameraCreationError": {}, + "cameraInternal": "Fotocamera interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Utilizza la fotocamera interna per leggere i codici a barre", + "@cameraInternalDetail": {}, + "cancel": "Annulla", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Annulla Ordine", + "@cancelOrder": {}, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nuova categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Crea nuova categoria articoli", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria articolo aggiornata", + "@categoryUpdated": {}, + "company": "Azienda", + "@company": {}, + "companyAdd": "Aggiungi azienda", + "@companyAdd": {}, + "companyEdit": "Modifica azienda", + "@companyEdit": {}, + "companyNoResults": "Nessuna azienda corrispondente alla query", + "@companyNoResults": {}, + "companyUpdated": "Dettagli azienda aggiornati", + "@companyUpdated": {}, + "companies": "Aziende", + "@companies": {}, + "complete": "Completato", + "@complete": {}, + "completeOrder": "Ordine completo", + "@completeOrder": {}, + "completionDate": "Data di completamento", + "@completionDate": {}, + "configureServer": "Configurare le impostazioni del server", + "@configureServer": {}, + "confirmScan": "Conferma trasferimento", + "@confirmScan": {}, + "confirmScanDetail": "Conferma trasferimento dettagli stock durante scansione codici a barre", + "@confirmScanDetail": {}, + "connectionRefused": "Connessione rifiutata", + "@connectionRefused": {}, + "count": "Quantità", + "@count": { + "description": "Count" + }, + "countStock": "Conteggio Giacenze", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Riconoscimenti", + "@credits": {}, + "crop": "Ritaglia", + "@crop": {}, + "cropImage": "Ritaglia immagine", + "@cropImage": {}, + "customer": "Cliente", + "@customer": {}, + "customers": "Clienti", + "@customers": {}, + "customerReference": "Riferimento cliente", + "@customerReference": {}, + "damaged": "Danneggiato", + "@damaged": {}, + "colorScheme": "Combinazione di colori", + "@colorScheme": {}, + "colorSchemeDetail": "Selezionare lo schema colori", + "@colorSchemeDetail": {}, + "darkMode": "Modalità Scura", + "@darkMode": {}, + "darkModeEnable": "Abilita modalità scura", + "@darkModeEnable": {}, + "delete": "Cancella", + "@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": "Data di consegna", + "@deliveryDate": {}, + "description": "Descrizione", + "@description": {}, + "destination": "Destinazione", + "@destination": {}, + "destroyed": "Distrutto", + "@destroyed": {}, + "details": "Dettagli", + "@details": { + "description": "details" + }, + "documentation": "Documentazione", + "@documentation": {}, + "downloadComplete": "Download completato", + "@downloadComplete": {}, + "downloadError": "Errore nel scaricare l'immagine", + "@downloadError": {}, + "downloading": "File in download", + "@downloading": {}, + "edit": "Modifica", + "@edit": { + "description": "edit" + }, + "editAttachment": "Modifica allegato", + "@editAttachment": {}, + "editCategory": "Modifica Categoria", + "@editCategory": {}, + "editLocation": "Modifica Ubicazione", + "@editLocation": {}, + "editNotes": "Modifica Note", + "@editNotes": {}, + "editParameter": "Modifica parametro", + "@editParameter": {}, + "editPart": "Modifica Articolo", + "@editPart": { + "description": "edit part" + }, + "editItem": "Modifica elementi magazzino", + "@editItem": {}, + "editLineItem": "Modifica linea elemento", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Inserire la password", + "@enterPassword": {}, + "enterUsername": "Inserisci nome utente", + "@enterUsername": {}, + "error": "Errore", + "@error": { + "description": "Error" + }, + "errorCreate": "Errore nella creazione della voce del database", + "@errorCreate": {}, + "errorDelete": "Errore nell'eliminazione della voce del database", + "@errorDelete": {}, + "errorDetails": "Dettagli errore", + "@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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Carica i report degli errori anonimi e i crash log", + "@errorReportUploadDetails": {}, + "expiryDate": "Data di Scadenza", + "@expiryDate": {}, + "expiryExpired": "Scaduto", + "@expiryExpired": {}, + "expiryStale": "Scaduto", + "@expiryStale": {}, + "extraLineItem": "Elemento linea extra", + "@extraLineItem": {}, + "extraLineItems": "Elementi linee extra", + "@extraLineItems": {}, + "feedback": "Commenti e suggerimenti", + "@feedback": {}, + "feedbackError": "Errore nell'invio del feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback inviato", + "@feedbackSuccess": {}, + "filterActive": "Attivo", + "@filterActive": {}, + "filterActiveDetail": "Mostra articoli attivi", + "@filterActiveDetail": {}, + "filterAssembly": "Assemblato", + "@filterAssembly": {}, + "filterAssemblyDetail": "Mostra articoli assemblati", + "@filterAssemblyDetail": {}, + "filterComponent": "Componente", + "@filterComponent": {}, + "filterComponentDetail": "Mostra componenti articoli", + "@filterComponentDetail": {}, + "filterExternal": "Esterno", + "@filterExternal": {}, + "filterExternalDetail": "Mostra stock su posizione esterne", + "@filterExternalDetail": {}, + "filterInStock": "In Giacenza", + "@filterInStock": {}, + "filterInStockDetail": "Mostra articoli che sono in giacenza", + "@filterInStockDetail": {}, + "filterSerialized": "Serializzato", + "@filterSerialized": {}, + "filterSerializedDetail": "Mostra gli elementi stock di serie", + "@filterSerializedDetail": {}, + "filterTemplate": "Modello", + "@filterTemplate": {}, + "filterTemplateDetail": "Mostra modello articoli", + "@filterTemplateDetail": {}, + "filterTrackable": "Rintracciabile", + "@filterTrackable": {}, + "filterTrackableDetail": "Mostra articoli rintracciabili", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuale", + "@filterVirtual": {}, + "filterVirtualDetail": "Mostra articoli virtuali", + "@filterVirtualDetail": {}, + "filteringOptions": "Opzioni di filtro", + "@filteringOptions": {}, + "formatException": "Eccezione Formato", + "@formatException": {}, + "formatExceptionJson": "Eccezione formato dati JSON", + "@formatExceptionJson": {}, + "formError": "Errore Modulo", + "@formError": {}, + "history": "Cronologia", + "@history": { + "description": "history" + }, + "home": "Home", + "@home": {}, + "homeScreen": "Schermata Home", + "@homeScreen": {}, + "homeScreenSettings": "Configura le impostazioni della schermata home", + "@homeScreenSettings": {}, + "homeShowPo": "Mostra Ordini di Acquisto", + "@homeShowPo": {}, + "homeShowPoDescription": "Mostra il pulsante ordine d'acquisto nella schermata home", + "@homeShowPoDescription": {}, + "homeShowShipments": "Mostra Spedizioni", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Mostra le spedizioni in sospeso nella schermata home", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Mostra ordini di vendita", + "@homeShowSo": {}, + "homeShowSoDescription": "Mostra bottone ordine di vendita sulla schermata principale", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Articoli Sottoscritti", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostra gli articoli sottoscritti sulla schermata home", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Mostra Fornitori", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Mostra il pulsante fornitori nella schermata home", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Mostra Produttori", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Mostra il pulsante fornitori nella schermata home", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Mostra Clienti", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Mostra il pulsante clienti nella schermata home", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Il caricamento della foto è fallito", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Immagine caricata", + "@imageUploadSuccess": {}, + "inactive": "Inattivo", + "@inactive": {}, + "inactiveCompany": "Questa azienda è contrassegnata come inattiva", + "@inactiveCompany": {}, + "inactiveDetail": "Questo articolo è contrassegnato come inattivo", + "@inactiveDetail": {}, + "includeSubcategories": "Includi sottocategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostra i risultati delle sottocategorie", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Includi sotto allocazioni", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostra i risultati delle sottolocazioni", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Ti preghiamo di completare i dati del tuo account", + "@incompleteDetails": {}, + "internalPartNumber": "Numero Articolo Interno", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Produzione", + "@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", + "@invalidHostDetails": {}, + "invalidPart": "Articolo Non Valido", + "@invalidPart": {}, + "invalidPartCategory": "Categoria Articolo Non Valida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ubicazione di magazzino non valida", + "@invalidStockLocation": {}, + "invalidStockItem": "Elemento di magazzino non valido", + "@invalidStockItem": {}, + "invalidSupplierPart": "Fornitore Articolo Non Valido", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Combinazione nome utente e password non valida", + "@invalidUsernamePassword": {}, + "invoice": "Fattura", + "@invoice": {}, + "invoiceNumber": "Numero Fattura", + "@invoiceNumber": {}, + "issue": "Problema", + "@issue": {}, + "issueDate": "Data di emissione", + "@issueDate": {}, + "issueOrder": "Problema nell'ordine", + "@issueOrder": {}, + "itemInLocation": "Elemento già in posizione", + "@itemInLocation": {}, + "itemDeleted": "L'elemento è stato rimosso", + "@itemDeleted": {}, + "itemUpdated": "Articolo aggiornato", + "@itemUpdated": {}, + "keywords": "Parole Chiave", + "@keywords": {}, + "labelDriver": "Driver Etichetta", + "@labelDriver": {}, + "labelSelectDriver": "Seleziona Il Driver Della Stampante Etichette", + "@labelSelectDriver": {}, + "labelPrinting": "Etichetta in stampa", + "@labelPrinting": {}, + "labelPrintingDetail": "Abilita stampa etichette", + "@labelPrintingDetail": {}, + "labelTemplate": "Modello Etichetta", + "@labelTemplate": {}, + "labelSelectTemplate": "Seleziona Modello Etichetta", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Seleziona Stampante Etichette", + "@labelSelectPrinter": {}, + "language": "Lingua", + "@language": {}, + "languageDefault": "Lingua di sistema predefinita", + "@languageDefault": {}, + "languageSelect": "Seleziona Lingua", + "@languageSelect": {}, + "lastStocktake": "Ultimo Inventario", + "@lastStocktake": {}, + "lastUpdated": "Ultimo aggiornamento", + "@lastUpdated": {}, + "level": "Livello", + "@level": {}, + "lineItemAdd": "Aggiungi Elemento Riga", + "@lineItemAdd": {}, + "lineItem": "Elemento Riga", + "@lineItem": {}, + "lineItems": "Elementi riga", + "@lineItems": {}, + "lineItemUpdated": "Articolo modificato", + "@lineItemUpdated": {}, + "locateItem": "Individua elemento di magazzino", + "@locateItem": {}, + "locateLocation": "Individua ubicazione di magazzino", + "@locateLocation": {}, + "locationCreate": "Nuova Ubicazione", + "@locationCreate": {}, + "locationCreateDetail": "Crea nuova ubicazione di magazzino", + "@locationCreateDetail": {}, + "locationDefault": "Posizione Predefinita", + "@locationDefault": {}, + "locationNotSet": "Nessuna ubicazione specificata", + "@locationNotSet": {}, + "locationUpdated": "Ubicazione di magazzino aggiornata", + "@locationUpdated": {}, + "login": "Accedi", + "@login": {}, + "loginEnter": "Inserisci i dettagli di accesso", + "@loginEnter": {}, + "loginEnterDetails": "Nome utente e password non sono memorizzati localmente", + "@loginEnterDetails": {}, + "link": "Collegamento", + "@link": {}, + "lost": "Perso", + "@lost": {}, + "manufacturerPart": "Articolo Produttore", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Modifica Articolo Produttore", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Codice articolo produttore", + "@manufacturerPartNumber": {}, + "manufacturer": "Produttore", + "@manufacturer": {}, + "manufacturers": "Produttori", + "@manufacturers": {}, + "missingData": "Dati mancanti", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Non connesso", + "@notConnected": {}, + "notes": "Note", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifiche", + "@notifications": {}, + "notificationsEmpty": "Nessuna notifica non letta", + "@notificationsEmpty": {}, + "noResponse": "Nessuna risposta dal server", + "@noResponse": {}, + "noResults": "Nessun risultato", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Numero non valido", + "@numberInvalid": {}, + "onOrder": "Ordinato", + "@onOrder": {}, + "onOrderDetails": "Articoli attualmente in ordine", + "@onOrderDetails": {}, + "orientation": "Orientamento dello schermo", + "@orientation": {}, + "orientationDetail": "Orientamento dello schermo (richiede riavvio)", + "@orientationDetail": {}, + "orientationLandscape": "Orizzontale", + "@orientationLandscape": {}, + "orientationPortrait": "Verticale", + "@orientationPortrait": {}, + "orientationSystem": "Sistema", + "@orientationSystem": {}, + "outstanding": "In Sospeso", + "@outstanding": {}, + "outstandingOrderDetail": "Mostra Ordini di Vendita inevasi", + "@outstandingOrderDetail": {}, + "overdue": "In ritardo", + "@overdue": {}, + "overdueDetail": "Mostra Ordini di Vendita in ritardo", + "@overdueDetail": {}, + "packaging": "Confezionamento", + "@packaging": {}, + "packageName": "Nome pacchetto", + "@packageName": {}, + "parameters": "Parametri", + "@parameters": {}, + "parametersSettingDetail": "Visualizza parametri dell'articolo", + "@parametersSettingDetail": {}, + "parent": "Superiore", + "@parent": {}, + "parentCategory": "Categoria Superiore", + "@parentCategory": {}, + "parentLocation": "Ubicazione principale", + "@parentLocation": {}, + "part": "Articolo", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nuovo Articolo", + "@partCreate": {}, + "partCreateDetail": "Crea nuovo prodotto in questa categoria", + "@partCreateDetail": {}, + "partEdited": "Articolo aggiornato", + "@partEdited": {}, + "parts": "Articoli", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Parte non contrassegnata come vendibile", + "@partNotSalable": {}, + "partsNone": "Nessun Articolo", + "@partsNone": {}, + "partNoResults": "Nessun articolo corrispondente alla ricerca", + "@partNoResults": {}, + "partPricing": "Prezzo Articolo", + "@partPricing": {}, + "partPricingSettingDetail": "Mostra prezzi dell'articolo", + "@pricingSettingDetail": {}, + "partSettings": "Impostazioni articolo", + "@partSettings": {}, + "partsStarred": "Articoli Sottoscritti", + "@partsStarred": {}, + "partsStarredNone": "Nessun articolo preferito disponibile", + "@partsStarredNone": {}, + "partSuppliers": "Fornitori articoli", + "@partSuppliers": {}, + "partCategory": "Categoria Articolo", + "@partCategory": {}, + "partCategoryTopLevel": "Categoria articolo di livello superiore", + "@partCategoryTopLevel": {}, + "partCategories": "Categorie Articolo", + "@partCategories": {}, + "partDetails": "Dettagli Articolo", + "@partDetails": {}, + "partNotes": "Note Articolo", + "@partNotes": {}, + "partStock": "Articolo Magazzino", + "@partStock": { + "description": "part stock" + }, + "password": "Password", + "@password": {}, + "passwordEmpty": "La password non può essere vuota", + "@passwordEmpty": {}, + "pending": "In sospeso", + "@pending": {}, + "permissionAccountDenied": "Non disponi dei permessi per eseguire l'azione", + "@permissionAccountDenied": {}, + "permissionRequired": "Autorizzazione necessaria", + "@permissionRequired": {}, + "phone": "Telefono", + "@phone": {}, + "printLabel": "Stampa Etichetta", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Stampante", + "@pluginPrinter": {}, + "pluginSupport": "Supporto Plugin Abilitato", + "@pluginSupport": {}, + "pluginSupportDetail": "Il server supporta plugin personalizzati", + "@pluginSupportDetail": {}, + "printLabelFailure": "Stampa etichette fallita", + "@printLabelFailure": {}, + "printLabelSuccess": "Etichetta inviata alla stampante", + "@printLabelSuccess": {}, + "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": {}, + "profileLogout": "Disconetti", + "@profileLogout": {}, + "profileName": "Nome Profilo", + "@profileName": {}, + "profileNone": "Nessun profilo disponibile", + "@profileNone": {}, + "profileNotSelected": "Nessun profilo selezionato", + "@profileNotSelected": {}, + "profileSelect": "Seleziona Server InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Seleziona il server o crea un nuovo profilo", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tocca per creare o selezionare un profilo", + "@profileTapToCreate": {}, + "projectCode": "Codice del progetto", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Conferma i Dati Scansionati", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Conferma i dettagli durante la scansione degli elementi", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Abilita gli ordini di acquisto", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Abilita funzionalità ordine d'acquisto", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Collegamento Fotocamera", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Abilita la scorciatoia per il caricamento delle immagini nella schermata ordini d'acquisto", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Ordine d'acquisto", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nuovo Ordine di Acquisto", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Modifica ordine d'acquisto", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Impostazioni ordini d'acquisto", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Ordini d'acquisto", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Ordine d'acquisto aggiornato", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Prezzo d'acquisto", + "@purchasePrice": {}, + "quantity": "Quantità", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantità Disponibile", + "@quantityAvailable": {}, + "quantityEmpty": "Quantità vuota", + "@quantityEmpty": {}, + "quantityInvalid": "La quantità non è valida", + "@quantityInvalid": {}, + "quantityPositive": "La quantità deve essere positiva", + "@quantityPositive": {}, + "queryEmpty": "Inserisci ricerca", + "@queryEmpty": {}, + "queryNoResults": "Nessun risultato per la tua ricerca", + "@queryNoResults": {}, + "received": "Ricevuto", + "@received": {}, + "receivedFilterDetail": "Visualizza elementi ricevuti", + "@receivedFilterDetail": {}, + "receiveItem": "Ricevi Articolo", + "@receiveItem": {}, + "receivedItem": "Elemento del magazzino ricevuto", + "@receivedItem": {}, + "reference": "Riferimento", + "@reference": {}, + "refresh": "Aggiorna", + "@refresh": {}, + "rotateClockwise": "Ruota di 90° in senso orario", + "@rotateClockwise": {}, + "refreshing": "In aggiornamento", + "@refreshing": {}, + "rejected": "Respinto", + "@rejected": {}, + "releaseNotes": "Note di Rilascio", + "@releaseNotes": {}, + "remove": "Rimuovi", + "@remove": { + "description": "remove" + }, + "removeStock": "Rimuovi giacenza", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Segnala un bug", + "@reportBug": {}, + "reportBugDescription": "Invia segnalazione bug (richiede account GitHub)", + "@reportBugDescription": {}, + "responsible": "Responsabile", + "@responsible": {}, + "results": "Risultati", + "@results": {}, + "request": "Richiesta", + "@request": {}, + "requestFailed": "Richiesta Fallita", + "@requestFailed": {}, + "requestSuccessful": "Richiesta Riuscita", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Ordini di Vendita", + "@salesOrder": {}, + "salesOrders": "Ordini di vendita", + "@salesOrders": {}, + "salesOrderEnable": "Attiva ordini di vendita", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Abilita funzionalità ordini di vendita", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Collegamento Fotocamera", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Abilita la scorciatoia per il caricamento delle immagini nella schermata ordini di vendita", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Impostazioni Ordini di Vendita", + "@salesOrderSettings": {}, + "salesOrderCreate": "Nuovo Ordine di Vendita", + "@saleOrderCreate": {}, + "salesOrderEdit": "Modifica Ordine di Vendita", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Ordine di vendita aggiornato", + "@salesOrderUpdated": {}, + "save": "Salva", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scansiona codice a barre", + "@scanBarcode": {}, + "scanSupplierPart": "Scansiona codice a barre del fornitore", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scansiona nell'ubicazione", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scansiona questo elemento nell'ubicazione", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Scanner esterno", + "@scannerExternal": {}, + "scannerExternalDetail": "Usa lo scanner esterno per leggere i codici a barre (modalità cuneo)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scansiona Parti Ricevute", + "@scanReceivedParts": {}, + "search": "Cerca", + "@search": { + "description": "search" + }, + "searching": "Ricerca in corso", + "@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", + "@searchStock": {}, + "select": "Seleziona", + "@select": {}, + "selectFile": "Seleziona file", + "@selectFile": {}, + "selectImage": "Seleziona un'immagine", + "@selectImage": {}, + "selectLocation": "Seleziona un'ubicazione", + "@selectLocation": {}, + "send": "Invia", + "@send": {}, + "serialNumber": "Numero seriale", + "@serialNumber": {}, + "serialNumbers": "Numeri di serie", + "@serialNumbers": {}, + "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": {}, + "serverNotSelected": "Server non selezionato", + "@serverNotSelected": {}, + "shipment": "Spedizione", + "@shipment": {}, + "shipments": "Spedizioni", + "@shipments": {}, + "shipmentsPending": "Spedizioni in sospeso", + "@shipmentsPending": {}, + "shipmentAdd": "Aggiungi Spedizione", + "@shipmentAdd": {}, + "shipmentCheck": "Controlla spedizione", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Segna questa spedizione come controllata", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Spedizione Controllata", + "@shipmentChecked": {}, + "shipmentDate": "Data di spedizione", + "@shipmentDate": {}, + "shipmentEdit": "Modifica spedizione", + "@shipmentEdit": {}, + "shipmentReference": "Riferimento della spedizione", + "@shipmentReference": {}, + "shipmentSend": "Invia Spedizione", + "@shipmentSend": {}, + "shipmentUncheck": "Deseleziona Spedizione", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Contrassegna questa spedizione come non controllata", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Spedizione Aggiornata", + "@shipmentUpdated": {}, + "shipped": "Spedito", + "@shipped": {}, + "sku": "Codice articolo", + "@sku": {}, + "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": {}, + "startDate": "Data inizio", + "@startDate": {}, + "status": "Stato", + "@status": {}, + "statusCode": "Codice di stato", + "@statusCode": {}, + "stock": "Magazzino", + "@stock": { + "description": "stock" + }, + "stockDetails": "Attuale Quantità di magazzino disponibile", + "@stockDetails": {}, + "stockItem": "Elemento in magazzino", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Elementi in magazzino", + "@stockItems": {}, + "stockItemCreate": "Nuovo elemento in magazzino", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Crea nuovo elemento di magazzino in questa ubicazione", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Cancella Elemento di Magazzino", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Sei sicuro di voler rimuovere questo elemento di magazzino?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Impossibile eliminare l'elemento di magazzino", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Elemento di magazzino cancellato", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Cronologia Magazzino", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Mostra le informazioni storiche di tracciamento delle scorte", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Elemento di magazzino trasferito", + "@stockItemTransferred": {}, + "stockItemUpdated": "Elemento stock aggiornato", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nessun elemento di magazzino disponibile", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Note elemento di magazzino", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Elemento di magazzino aggiornato", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Aggiornamento elemento di magazzino non riuscito", + "@stockItemUpdateFailure": {}, + "stockLocation": "Ubicazione Magazzino", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Ubicazioni Magazzino", + "@stockLocations": {}, + "stockTopLevel": "Ubicazione di livello superiore di magazzino", + "@stockTopLevel": {}, + "strictHttps": "Usa HTTPS Strict", + "@strictHttps": {}, + "strictHttpsDetails": "Forza il controllo rigoroso dei certificati HTTPs", + "@strictHttpsDetails": {}, + "subcategory": "Sottocategoria", + "@subcategory": {}, + "subcategories": "Sottocategorie", + "@subcategories": {}, + "sublocation": "Sottoallocazione", + "@sublocation": {}, + "sublocations": "Sottoallocazioni", + "@sublocations": {}, + "sublocationNone": "Nessuna Sottoallocazione", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nessuna sottoallocazione disponibile", + "@sublocationNoneDetail": {}, + "submitFeedback": "Invia feedback", + "@submitFeedback": {}, + "suppliedParts": "Articoli Fornitore", + "@suppliedParts": {}, + "supplier": "Fornitore", + "@supplier": {}, + "supplierPart": "Articolo Fornitore", + "@supplierPart": {}, + "supplierPartEdit": "Modifica Fornitore Articolo", + "@supplierPartEdit": {}, + "supplierPartNumber": "Codice articolo fornitore", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Articolo Fornitore Aggiornato", + "@supplierPartUpdated": {}, + "supplierParts": "Articoli Fornitore", + "@supplierParts": {}, + "suppliers": "Fornitori", + "@suppliers": {}, + "supplierReference": "Riferimento fornitore", + "@supplierReference": {}, + "switchCamera": "Cambia visuale", + "@switchCamera": {}, + "takePicture": "Scatta Foto", + "@takePicture": {}, + "targetDate": "Data dell'obiettivo", + "@targetDate": {}, + "templatePart": "Articolo Modello Principale", + "@templatePart": {}, + "testName": "Nome del test", + "@testName": {}, + "testPassedOrFailed": "Test superato o fallito", + "@testPassedOrFailed": {}, + "testsRequired": "Test Richiesti", + "@testsRequired": {}, + "testResults": "Risultati del test", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Visualizzazione dei risultati dei test sugli articoli in magazzino", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Torcia", + "@toggleTorch": {}, + "tokenError": "Errore Token", + "@tokenError": {}, + "tokenMissing": "Token Mancante", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token di accesso mancante dalla risposta", + "@tokenMissingFromResponse": {}, + "totalPrice": "Prezzo Totale", + "@totalPrice": {}, + "trackingNumber": "Numero Di Tracking", + "@trackingNumber": {}, + "transfer": "Trasferisci", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Trasferisci giacenza", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Trasferisci elemento in una ubicazione diversa", + "@transferStockDetail": {}, + "transferStockLocation": "Trasferisci Ubicazione Magazzino", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Trasferisci questa ubicazione di magazzino in un'altra", + "@transferStockLocationDetail": {}, + "translate": "Traduci", + "@translate": {}, + "translateHelp": "Aiuta a tradurre l'app InvenTree", + "@translateHelp": {}, + "unavailable": "Non disponibile", + "@unavailable": {}, + "unavailableDetail": "L'articolo non è disponibile", + "@unavailableDetail": {}, + "unitPrice": "Prezzo Unitario", + "@unitPrice": {}, + "units": "Unità", + "@units": {}, + "unknownResponse": "Risposta Sconosciuta", + "@unknownResponse": {}, + "upload": "Carica", + "@upload": {}, + "uploadFailed": "Caricamento di file non riuscito", + "@uploadFailed": {}, + "uploadSuccess": "File caricato", + "@uploadSuccess": {}, + "uploadImage": "Carica immagine", + "@uploadImage": {}, + "usedIn": "Viene utilizzato in", + "@usedIn": {}, + "usedInDetails": "Assemblaggi che richiedono questa parte", + "@usedInDetails": {}, + "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": {}, + "variants": "Varianti", + "@variants": {}, + "version": "Versione", + "@version": {}, + "viewSupplierPart": "Visualizza Fornitore", + "@viewSupplierPart": {}, + "website": "Sito Web", + "@website": {}, + "yes": "Si", + "@yes": {}, + "price": "Prezzo", + "@price": {}, + "priceRange": "Fascia di Prezzo", + "@priceRange": {}, + "priceOverrideMin": "Sovrascrivere Prezzo Minimo", + "@priceOverrideMin": {}, + "priceOverrideMax": "Sovrascrivi Prezzo Massimo", + "@priceOverrideMax": {}, + "salePrice": "Prezzo di Vendita", + "@salePrice": {}, + "saleHistory": "Storico vendite", + "@saleHistory": {}, + "supplierPricing": "Prezzo del Fornitore", + "@supplierPricing": {}, + "bomCost": "Costo BOM", + "@bomCost": {}, + "internalCost": "Costo Interno", + "@internalCost": {}, + "variantCost": "Costo Variante", + "@variantCost": {}, + "overallPricing": "Prezzi Complessivi", + "@overallPricing": {}, + "pricingOverrides": "Sovrascrittura Prezzi", + "@pricingOverrides": {}, + "currency": "Valuta", + "@currency": {}, + "priceBreaks": "Divergenze di prezzo", + "@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 new file mode 100644 index 0000000..baffd2c --- /dev/null +++ b/lib/l10n/ja_JP/app_ja_JP.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "ja", + "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": {}, + "allocated": "割り当て", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "在庫の割り当て", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "アプリのリリースノートを表示", + "@appReleaseNotes": {}, + "appSettings": "アプリ設定", + "@appSettings": {}, + "appSettingsDetails": "アプリ設定を構成します", + "@appSettingsDetails": {}, + "assignedToMe": "自分に割り当て済み", + "@assignedToMe": {}, + "assignedToMeDetail": "自分に割り当てられた注文を表示", + "@assignedToMeDetail": {}, + "attachments": "添付ファイル", + "@attachments": {}, + "attachImage": "画像を添付", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "添付ファイルが見つかりません。", + "@attachmentNone": {}, + "attachmentNoneDetail": "添付ファイルなし", + "@attachmentNoneDetail": {}, + "attachmentSelect": "添付ファイルを選択", + "@attachmentSelect": {}, + "attention": "注意", + "@attention": {}, + "available": "利用可", + "@available": {}, + "availableStock": "在庫あり", + "@availableStock": {}, + "barcodes": "バーコード", + "@barcodes": {}, + "barcodeSettings": "バーコード設定", + "@barcodeSettings": {}, + "barcodeAssign": "バーコードを割り当てる", + "@barcodeAssign": {}, + "barcodeAssignDetail": "カスタムバーコードをスキャンして割り当てる", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "バーコードが割り当てられました", + "@barcodeAssigned": {}, + "barcodeError": "バーコードのスキャンエラー", + "@barcodeError": {}, + "barcodeInUse": "バーコードは既に割り当てられています", + "@barcodeInUse": {}, + "barcodeMissingHash": "バーコードから応答にてハッシュデータが欠落しています", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "バーコードが一致しません", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "バーコードが割り当てられていません", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "部品バーコードをスキャン", + "@barcodeScanPart": {}, + "barcodeReceivePart": "部品を受け取るためにバーコードをスキャン", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "バーコードスキャンを一時停止中", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "スキャンしてバーコードを割り当てます", + "@barcodeScanAssign": {}, + "barcodeScanController": "スキャナー入力", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "バーコードスキャナの入力元を選択", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "バーコードスキャン遅延", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "バーコードスキャン間の遅延", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "InvenTree バーコードをスキャンする", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "在庫アイテムをスキャンしてこの場所に登録する", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "在庫場所をスキャン", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "シングルスキャンモード", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "各スキャン後にバーコードスキャナを一時停止する", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "スキャンされた在庫場所", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "スキャンされていないアイテム", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "在庫アイテムをスキャン", + "@barcodeScanItem": {}, + "barcodeTones": "バーコードのトーン", + "@barcodeTones": {}, + "barcodeUnassign": "バーコードの割り当てを解除", + "@barcodeUnassign": {}, + "barcodeUnknown": "バーコードが認識されません", + "@barcodeUnknown": {}, + "batchCode": "一括処理コード", + "@batchCode": {}, + "billOfMaterials": "部品表", + "@billOfMaterials": {}, + "bom": "部品表", + "@bom": {}, + "bomEnable": "部品表を表示", + "@bomEnable": {}, + "build": "ビルド", + "@build": {}, + "building": "ビルド", + "@building": {}, + "cameraCreationError": "カメラコントローラーを開けませんでした", + "@cameraCreationError": {}, + "cameraInternal": "内蔵カメラ", + "@cameraInternal": {}, + "cameraInternalDetail": "バーコードを読み取るために内部カメラを使用", + "@cameraInternalDetail": {}, + "cancel": "キャンセル", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "注文をキャンセル", + "@cancelOrder": {}, + "category": "カテゴリ", + "@category": {}, + "categoryCreate": "新規カテゴリ", + "@categoryCreate": {}, + "categoryCreateDetail": "新しい部品カテゴリを作成", + "@categoryCreateDetail": {}, + "categoryUpdated": "部品カテゴリを更新しました", + "@categoryUpdated": {}, + "company": "会社", + "@company": {}, + "companyAdd": "会社を追加", + "@companyAdd": {}, + "companyEdit": "会社を編集", + "@companyEdit": {}, + "companyNoResults": "検索条件に一致する会社はありません", + "@companyNoResults": {}, + "companyUpdated": "会社の詳細を更新しました", + "@companyUpdated": {}, + "companies": "会社", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "完了日", + "@completionDate": {}, + "configureServer": "サーバー設定", + "@configureServer": {}, + "confirmScan": "送金を確認", + "@confirmScan": {}, + "confirmScanDetail": "バーコードをスキャンする際に在庫移動の詳細を確認する", + "@confirmScanDetail": {}, + "connectionRefused": "接続を拒否しました", + "@connectionRefused": {}, + "count": "カウント", + "@count": { + "description": "Count" + }, + "countStock": "在庫数", + "@countStock": { + "description": "Count Stock" + }, + "credits": "謝辞", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "顧客", + "@customer": {}, + "customers": "顧客", + "@customers": {}, + "customerReference": "顧客参照", + "@customerReference": {}, + "damaged": "破損", + "@damaged": {}, + "colorScheme": "配色設定", + "@colorScheme": {}, + "colorSchemeDetail": "配色を選択", + "@colorSchemeDetail": {}, + "darkMode": "ダークモード", + "@darkMode": {}, + "darkModeEnable": "ダークモードを有効にする", + "@darkModeEnable": {}, + "delete": "削除", + "@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": {}, + "destroyed": "破壊", + "@destroyed": {}, + "details": "詳細", + "@details": { + "description": "details" + }, + "documentation": "ドキュメント", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "ファイルをダウンロード中", + "@downloading": {}, + "edit": "編集", + "@edit": { + "description": "edit" + }, + "editAttachment": "添付ファイルの編集", + "@editAttachment": {}, + "editCategory": "カテゴリの編集", + "@editCategory": {}, + "editLocation": "在庫場所を編集", + "@editLocation": {}, + "editNotes": "メモを編集", + "@editNotes": {}, + "editParameter": "パラメーターを編集", + "@editParameter": {}, + "editPart": "パートの編集", + "@editPart": { + "description": "edit part" + }, + "editItem": "在庫商品を編集", + "@editItem": {}, + "editLineItem": "ラインアイテムの編集", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "パスワードを入力してください", + "@enterPassword": {}, + "enterUsername": "ユーザー名を入力してください", + "@enterUsername": {}, + "error": "エラー", + "@error": { + "description": "Error" + }, + "errorCreate": "データベースの作成中にエラーが発生しました", + "@errorCreate": {}, + "errorDelete": "データベースの削除中にエラーが発生しました", + "@errorDelete": {}, + "errorDetails": "エラーの詳細", + "@errorDetails": {}, + "errorFetch": "サーバーからのデータ取得の際にエラーが発生しました", + "@errorFetch": {}, + "errorUserRoles": "サーバーからのユーザーロールの要求エラー", + "@errorUserRoles": {}, + "errorPluginInfo": "サーバーからのプラグインデータの要求エラー", + "@errorPluginInfo": {}, + "errorReporting": "エラー報告", + "@errorReporting": {}, + "errorReportUpload": "エラー報告をアップロード", + "@errorReportUpload": {}, + "errorReportUploadDetails": "匿名のエラー報告とクラッシュログをアップロード", + "@errorReportUploadDetails": {}, + "expiryDate": "有効期限", + "@expiryDate": {}, + "expiryExpired": "期限切れ", + "@expiryExpired": {}, + "expiryStale": "期限失効", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "シリアル化された在庫アイテムを表示", + "@filterSerializedDetail": {}, + "filterTemplate": "テンプレート", + "@filterTemplate": {}, + "filterTemplateDetail": "テンプレート部品を表示", + "@filterTemplateDetail": {}, + "filterTrackable": "追跡可能", + "@filterTrackable": {}, + "filterTrackableDetail": "追跡可能なアイテムの表示", + "@filterTrackableDetail": {}, + "filterVirtual": "仮想", + "@filterVirtual": {}, + "filterVirtualDetail": "仮想パーツを表示", + "@filterVirtualDetail": {}, + "filteringOptions": "フィルターオプション", + "@filteringOptions": {}, + "formatException": "フォーマットの例外エラー", + "@formatException": {}, + "formatExceptionJson": "JSONデータフォーマット例外エラー", + "@formatExceptionJson": {}, + "formError": "フォームエラー", + "@formError": {}, + "history": "履歴", + "@history": { + "description": "history" + }, + "home": "ホーム", + "@home": {}, + "homeScreen": "ホーム画面", + "@homeScreen": {}, + "homeScreenSettings": "ホーム画面の設定", + "@homeScreenSettings": {}, + "homeShowPo": "注文書を表示", + "@homeShowPo": {}, + "homeShowPoDescription": "注文ボタンをホーム画面に表示", + "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "注文を表示", + "@homeShowSo": {}, + "homeShowSoDescription": "ホーム画面に注文ボタンを表示", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "購読済みのパーツ", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "ホーム画面に購読している部品を表示", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "仕入先を表示", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "仕入先ボタンをホーム画面に表示", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "メーカーを表示", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "メーカーボタンをホーム画面に表示", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "顧客を表示", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "顧客ボタンをホーム画面に表示", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "画像のアップロードに失敗しました", + "@imageUploadFailure": {}, + "imageUploadSuccess": "アップロードされた画像", + "@imageUploadSuccess": {}, + "inactive": "無効", + "@inactive": {}, + "inactiveCompany": "この企業は非アクティブとしてマークされています", + "@inactiveCompany": {}, + "inactiveDetail": "この部品は無効としてマークされています", + "@inactiveDetail": {}, + "includeSubcategories": "サブカテゴリを含む", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "サブカテゴリからの結果を表示", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "サブ在庫場所を含める", + "@includeSublocations": {}, + "includeSublocationsDetail": "サブロケーションからの結果を表示", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完全なプロフィールの詳細", + "@incompleteDetails": {}, + "internalPartNumber": "内部パーツ番号", + "@internalPartNumber": {}, + "info": "情報", + "@info": {}, + "inProduction": "生産中", + "@inProduction": {}, + "inProductionDetail": "この在庫品は生産中です", + "@inProductionDetail": {}, + "internalPart": "内部部品", + "@internalPart": {}, + "invalidHost": "無効なホスト名", + "@invalidHost": {}, + "invalidHostDetails": "このホスト名は無効です。", + "@invalidHostDetails": {}, + "invalidPart": "無効なパーツ", + "@invalidPart": {}, + "invalidPartCategory": "無効なパーツカテゴリー", + "@invalidPartCategory": {}, + "invalidStockLocation": "無効な在庫場所", + "@invalidStockLocation": {}, + "invalidStockItem": "無効な在庫アイテム", + "@invalidStockItem": {}, + "invalidSupplierPart": "無効なサプライヤー部品", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "無効なユーザー名/パスワードの組み合わせです。", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "問題", + "@issue": {}, + "issueDate": "発行日", + "@issueDate": {}, + "issueOrder": "注文", + "@issueOrder": {}, + "itemInLocation": "アイテムは既に在庫場所にあります", + "@itemInLocation": {}, + "itemDeleted": "アイテムが削除されました", + "@itemDeleted": {}, + "itemUpdated": "アイテムが更新されました。", + "@itemUpdated": {}, + "keywords": "キーワード", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "ラベル印刷", + "@labelPrinting": {}, + "labelPrintingDetail": "ラベル印刷を有効化", + "@labelPrintingDetail": {}, + "labelTemplate": "ラベルテンプレート", + "@labelTemplate": {}, + "labelSelectTemplate": "ラベルテンプレートを選択", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "ラベルプリンタの選択", + "@labelSelectPrinter": {}, + "language": "言語設定", + "@language": {}, + "languageDefault": "システムのデフォルト言語", + "@languageDefault": {}, + "languageSelect": "言語の選択", + "@languageSelect": {}, + "lastStocktake": "最新のストックテイク", + "@lastStocktake": {}, + "lastUpdated": "最終更新", + "@lastUpdated": {}, + "level": "残量", + "@level": {}, + "lineItemAdd": "ラインアイテムを追加", + "@lineItemAdd": {}, + "lineItem": "ラインアイテム", + "@lineItem": {}, + "lineItems": "ラインアイテム", + "@lineItems": {}, + "lineItemUpdated": "ラインアイテムが更新されました", + "@lineItemUpdated": {}, + "locateItem": "在庫アイテムを探す", + "@locateItem": {}, + "locateLocation": "在庫位置を特定する", + "@locateLocation": {}, + "locationCreate": "新しい場所", + "@locationCreate": {}, + "locationCreateDetail": "新しい在庫場所を作成", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "在庫場所が指定されていません", + "@locationNotSet": {}, + "locationUpdated": "在庫場所を更新しました", + "@locationUpdated": {}, + "login": "ログイン", + "@login": {}, + "loginEnter": "ログイン詳細を入力", + "@loginEnter": {}, + "loginEnterDetails": "ユーザー名とパスワードはローカルに保存されていません", + "@loginEnterDetails": {}, + "link": "リンク", + "@link": {}, + "lost": "損失", + "@lost": {}, + "manufacturerPart": "メーカー部品", + "@manufacturerPart": {}, + "manufacturerPartEdit": "メーカー部品の編集", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "メーカー部品番号", + "@manufacturerPartNumber": {}, + "manufacturer": "製造元", + "@manufacturer": {}, + "manufacturers": "製造元", + "@manufacturers": {}, + "missingData": "データ消失", + "@missingData": {}, + "name": "名前", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "接続されていません", + "@notConnected": {}, + "notes": "メモ", + "@notes": { + "description": "Notes" + }, + "notifications": "通知", + "@notifications": {}, + "notificationsEmpty": "未読通知なし", + "@notificationsEmpty": {}, + "noResponse": "サーバーからの応答がありません", + "@noResponse": {}, + "noResults": "一致する結果なし", + "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, + "noSubcategories": "サブカテゴリはありません", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "利用可能なサブ在庫場所がありません", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "無効な値", + "@numberInvalid": {}, + "onOrder": "注文中", + "@onOrder": {}, + "onOrderDetails": "現在注文中のアイテム", + "@onOrderDetails": {}, + "orientation": "画面の向き", + "@orientation": {}, + "orientationDetail": "画面の向き(再起動が必要)", + "@orientationDetail": {}, + "orientationLandscape": "横向き", + "@orientationLandscape": {}, + "orientationPortrait": "縦向き", + "@orientationPortrait": {}, + "orientationSystem": "システム", + "@orientationSystem": {}, + "outstanding": "未処理", + "@outstanding": {}, + "outstandingOrderDetail": "未処理の注文を表示", + "@outstandingOrderDetail": {}, + "overdue": "期限を過ぎました", + "@overdue": {}, + "overdueDetail": "期日超過注文を表示", + "@overdueDetail": {}, + "packaging": "梱包中", + "@packaging": {}, + "packageName": "パッケージ名", + "@packageName": {}, + "parameters": "パラメーター", + "@parameters": {}, + "parametersSettingDetail": "部品パラメータを表示", + "@parametersSettingDetail": {}, + "parent": "親", + "@parent": {}, + "parentCategory": "親カテゴリ", + "@parentCategory": {}, + "parentLocation": "上位の場所", + "@parentLocation": {}, + "part": "パーツ", + "@part": { + "description": "Part (single)" + }, + "partCreate": "新規部品", + "@partCreate": {}, + "partCreateDetail": "このカテゴリに新しいパーツを作成", + "@partCreateDetail": {}, + "partEdited": "部品が更新されました", + "@partEdited": {}, + "parts": "パーツ", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "販売可能としてマークされていない部品", + "@partNotSalable": {}, + "partsNone": "パーツがありません", + "@partsNone": {}, + "partNoResults": "クエリに一致する部品がありません", + "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "partSettings": "部品設定", + "@partSettings": {}, + "partsStarred": "購読済み部品", + "@partsStarred": {}, + "partsStarredNone": "お気に入りのパーツはありません", + "@partsStarredNone": {}, + "partSuppliers": "部品サプライヤー", + "@partSuppliers": {}, + "partCategory": "パーツカテゴリー", + "@partCategory": {}, + "partCategoryTopLevel": "トップレベルのパーツカテゴリ", + "@partCategoryTopLevel": {}, + "partCategories": "パーツカテゴリー", + "@partCategories": {}, + "partDetails": "パーツ詳細", + "@partDetails": {}, + "partNotes": "パーツメモ", + "@partNotes": {}, + "partStock": "パーツ在庫:", + "@partStock": { + "description": "part stock" + }, + "password": "パスワード", + "@password": {}, + "passwordEmpty": "パスワードは空欄にできません。", + "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "操作を行う権限がありません", + "@permissionAccountDenied": {}, + "permissionRequired": "権限が必要です", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "スキャンデータの確認", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "アイテムのスキャン時に詳細を確認する", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "注文書を有効にする", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "注文機能を有効にする", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "カメラのショートカット", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "注文書画面で画像のアップロードショートカットを有効にする", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "発注書", + "@purchaseOrder": {}, + "purchaseOrderCreate": "新規注文書", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "発注書の更新", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "注文書の設定", + "@purchaseOrderSettings": {}, + "purchaseOrders": "発注書", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "発注書が更新されました", + "@purchaseOrderUpdated": {}, + "purchasePrice": "購入金額", + "@purchasePrice": {}, + "quantity": "数量", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "在庫数", + "@quantityAvailable": {}, + "quantityEmpty": "数量が空です", + "@quantityEmpty": {}, + "quantityInvalid": "数量が無効です", + "@quantityInvalid": {}, + "quantityPositive": "数量は1以上", + "@quantityPositive": {}, + "queryEmpty": "検索クエリを入力", + "@queryEmpty": {}, + "queryNoResults": "検索結果はありません", + "@queryNoResults": {}, + "received": "受信済", + "@received": {}, + "receivedFilterDetail": "受け取ったアイテムを表示", + "@receivedFilterDetail": {}, + "receiveItem": "アイテムを受け取る", + "@receiveItem": {}, + "receivedItem": "受け取った在庫アイテム", + "@receivedItem": {}, + "reference": " 参照", + "@reference": {}, + "refresh": "更新", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "更新中", + "@refreshing": {}, + "rejected": "却下済み", + "@rejected": {}, + "releaseNotes": "リリースノート", + "@releaseNotes": {}, + "remove": "削除", + "@remove": { + "description": "remove" + }, + "removeStock": "在庫を削除", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "不具合の報告", + "@reportBug": {}, + "reportBugDescription": "バグレポートを送信 (GitHub アカウントが必要)", + "@reportBugDescription": {}, + "responsible": "担当者", + "@responsible": {}, + "results": "結果", + "@results": {}, + "request": "リクエスト", + "@request": {}, + "requestFailed": "リクエストに失敗しました", + "@requestFailed": {}, + "requestSuccessful": "リクエストが成功しました", + "@requestSuccessful": {}, + "requestingData": "データをリクエスト中", + "@requestingData": {}, + "required": "必須", + "@required": { + "description": "This field is required" + }, + "response400": "不正なリクエスト", + "@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": "不明な応答コード", + "@responseUnknown": {}, + "result": "結果", + "@result": { + "description": "" + }, + "returned": "返品済", + "@returned": {}, + "salesOrder": "注文", + "@salesOrder": {}, + "salesOrders": "注文", + "@salesOrders": {}, + "salesOrderEnable": "注文を有効にする", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "注文機能を有効にする", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "カメラショートカット", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "販売注文画面で画像アップロードのショートカットを有効にする", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "注文設定", + "@salesOrderSettings": {}, + "salesOrderCreate": "新規注文", + "@saleOrderCreate": {}, + "salesOrderEdit": "注文の編集", + "@salesOrderEdit": {}, + "salesOrderUpdated": "注文が更新されました", + "@salesOrderUpdated": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "バーコードをスキャン", + "@scanBarcode": {}, + "scanSupplierPart": "サプライヤ部品バーコードをスキャン", + "@scanSupplierPart": {}, + "scanIntoLocation": "スキャンされた在庫場所", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "このアイテムをスキャンして場所を確認する", + "@scanIntoLocationDetail": {}, + "scannerExternal": "外部スキャナー", + "@scannerExternal": {}, + "scannerExternalDetail": "バーコードの読み取りに外部スキャナを使用(ウェッジモード)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "受け取った部品をスキャン", + "@scanReceivedParts": {}, + "search": "検索", + "@search": { + "description": "search" + }, + "searching": "検索中", + "@searching": {}, + "searchLocation": "在庫場所を検索", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "パーツの検索", + "@searchParts": {}, + "searchStock": "在庫を検索", + "@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": "サーバへ接続しました\n", + "@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": {}, + "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", + "@sku": {}, + "sounds": "サウンド", + "@sounds": {}, + "soundOnBarcodeAction": "バーコード動作で音を鳴らす", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "サーバーのエラー時に音を鳴らす", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "ステータス", + "@status": {}, + "statusCode": "ステータスコード", + "@statusCode": {}, + "stock": "在庫", + "@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": "在庫アイテムが更新されました", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "在庫アイテムの更新に失敗しました", + "@stockItemUpdateFailure": {}, + "stockLocation": "在庫場所", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "在庫場所", + "@stockLocations": {}, + "stockTopLevel": "トップレベルの在庫場所", + "@stockTopLevel": {}, + "strictHttps": "厳格なHTTPSを使用", + "@strictHttps": {}, + "strictHttpsDetails": "HTTP 証明書の厳格なチェックを行う", + "@strictHttpsDetails": {}, + "subcategory": "サブカテゴリー", + "@subcategory": {}, + "subcategories": "サブカテゴリー", + "@subcategories": {}, + "sublocation": "サブ在庫場所", + "@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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "トークンエラー", + "@tokenError": {}, + "tokenMissing": "トークンがありません", + "@tokenMissing": {}, + "tokenMissingFromResponse": "アクセストークンが見つかりませんでした", + "@tokenMissingFromResponse": {}, + "totalPrice": "合計金額", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "転送", + "@transfer": { + "description": "transfer" + }, + "transferStock": "在庫の転送", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "アイテムを別の場所に転送する", + "@transferStockDetail": {}, + "transferStockLocation": "在庫の保管場所を移動", + "@transferStockLocation": {}, + "transferStockLocationDetail": "この在庫を他の場所に移動する", + "@transferStockLocationDetail": {}, + "translate": "翻訳", + "@translate": {}, + "translateHelp": "InvenTree アプリの翻訳に協力する", + "@translateHelp": {}, + "unavailable": "利用できません", + "@unavailable": {}, + "unavailableDetail": "アイテムが利用できません", + "@unavailableDetail": {}, + "unitPrice": "単価", + "@unitPrice": {}, + "units": "単位", + "@units": {}, + "unknownResponse": "不明な応答", + "@unknownResponse": {}, + "upload": "アップロード", + "@upload": {}, + "uploadFailed": "ファイルのアップロードに失敗しました。", + "@uploadFailed": {}, + "uploadSuccess": "アップロードされたファイル", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "使用先", + "@usedIn": {}, + "usedInDetails": "この部品を必要とするアセンブリ。", + "@usedInDetails": {}, + "username": "ユーザー名", + "@username": {}, + "usernameEmpty": "ユーザー名は空にできません。", + "@usernameEmpty": {}, + "value": "設定値", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "値を空にすることはできません。", + "@valueCannotBeEmpty": {}, + "valueRequired": "値が必要です", + "@valueRequired": {}, + "variants": "類似品", + "@variants": {}, + "version": "バージョン", + "@version": {}, + "viewSupplierPart": "サプライヤー部品を表示", + "@viewSupplierPart": {}, + "website": "Webサイト", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..f1e2e9b --- /dev/null +++ b/lib/l10n/ko_KR/app_ko_KR.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "ko", + "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": "Additional app credits", + "@appCredits": {}, + "appDetails": "App Details", + "@appDetails": {}, + "allocated": "Allocated", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "정사각형 (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "앱 릴리즈 노트 표시", + "@appReleaseNotes": {}, + "appSettings": "앱 설정", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "assignedToMe": "나에게 할당됨", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "첨부", + "@attachments": {}, + "attachImage": "사진 첨부", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "첨부 파일이 없음", + "@attachmentNone": {}, + "attachmentNoneDetail": "첨부 파일이 없음", + "@attachmentNoneDetail": {}, + "attachmentSelect": "첨부파일 선택", + "@attachmentSelect": {}, + "attention": "Attention", + "@attention": {}, + "available": "사용가능", + "@available": {}, + "availableStock": "Available Stock", + "@availableStock": {}, + "barcodes": "바코드", + "@barcodes": {}, + "barcodeSettings": "바코드 설정", + "@barcodeSettings": {}, + "barcodeAssign": "바코드 할당", + "@barcodeAssign": {}, + "barcodeAssignDetail": "커스텀 바코드 할당", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "바코드 할당됨", + "@barcodeAssigned": {}, + "barcodeError": "바코드 스캔 오류", + "@barcodeError": {}, + "barcodeInUse": "이미 바코드가 할당됨", + "@barcodeInUse": {}, + "barcodeMissingHash": "바코드 해시 데이터 응답 없음", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "바코드가 일치하지 않음", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "바코드가 할당되지 않음", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "스캔 파트 바코드", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scanning paused", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "회사 수정", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "수량", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "자르기", + "@crop": {}, + "cropImage": "이미지 자르기", + "@cropImage": {}, + "customer": "고객", + "@customer": {}, + "customers": "고객", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "다크 모드", + "@darkMode": {}, + "darkModeEnable": "다크 모드 활성화", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "키워드", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "귀하의 계정은 이 작업에 필요한 권한이 없습니다", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": "서버 주소", + "@serverAddress": {}, + "serverApiRequired": "필요한 API 버전", + "@serverApiRequired": {}, + "serverApiVersion": "서버 API 버전", + "@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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "토큰 오류", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..ecdf8de --- /dev/null +++ b/lib/l10n/lt_LT/app_lt_LT.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..7a792ed --- /dev/null +++ b/lib/l10n/lv_LV/app_lv_LV.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "lv", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Par lietotni", + "@about": {}, + "accountDetails": "Konta informācija", + "@accountDetails": {}, + "actions": "Darbības", + "@actions": { + "description": "" + }, + "actionsNone": "Nav pieejamu darbību", + "@actionsNone": {}, + "add": "Pievienot", + "@add": { + "description": "add" + }, + "addStock": "Add Stock", + "@addStock": { + "description": "add stock" + }, + "address": "Adrese", + "@address": {}, + "appAbout": "About InvenTree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "Lietotnes informācija", + "@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": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "Lietotnes iestatījumi", + "@appSettings": {}, + "appSettingsDetails": "Configure InvenTree app settings", + "@appSettingsDetails": {}, + "assignedToMe": "Piešķirts man", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "Pielikumi", + "@attachments": {}, + "attachImage": "Pievienot attēlu", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Pielikums netika atrasts", + "@attachmentNone": {}, + "attachmentNoneDetail": "Pielikums netika atrasts", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Izvēlieties pielikumu", + "@attachmentSelect": {}, + "attention": "Uzmanību", + "@attention": {}, + "available": "Pieejams", + "@available": {}, + "availableStock": "Pieejamais krājums", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": "Uzņēmums", + "@company": {}, + "companyAdd": "Pievienot uzņēmumu", + "@companyAdd": {}, + "companyEdit": "Rediģēt uzņēmumu", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Uzņēmumi", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Apstiprināt pārskaitījumu", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Savienojums noraidīts", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Klients", + "@customer": {}, + "customers": "Klienti", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Bojāts", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Tumšais režīms", + "@darkMode": {}, + "darkModeEnable": "Iespējot tumšo izskatu", + "@darkModeEnable": {}, + "delete": "Dzēst", + "@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", + "@destination": {}, + "destroyed": "Destroyed", + "@destroyed": {}, + "details": "Sīkāka informācija", + "@details": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Lejupielādēt failu", + "@downloading": {}, + "edit": "Rediģēt", + "@edit": { + "description": "edit" + }, + "editAttachment": "Rediģēt pielikumu", + "@editAttachment": {}, + "editCategory": "Rediģēt kategoriju", + "@editCategory": {}, + "editLocation": "Labot atrašanās vietu", + "@editLocation": {}, + "editNotes": "Rediģēt piezīmes", + "@editNotes": {}, + "editParameter": "Edit Parameter", + "@editParameter": {}, + "editPart": "Edit Part", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edit Stock Item", + "@editItem": {}, + "editLineItem": "Edit Line Item", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Ievadiet paroli", + "@enterPassword": {}, + "enterUsername": "Ievadiet lietotājvārdu", + "@enterUsername": {}, + "error": "Kļūda", + "@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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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": "Virtuāls", + "@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": "Vēsture", + "@history": { + "description": "history" + }, + "home": "Sākums", + "@home": {}, + "homeScreen": "Galvenā Izvēlne", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": "Attēla augšupielāde neizdevās", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Attēls augšupielādēts", + "@imageUploadSuccess": {}, + "inactive": "Neaktīvs", + "@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": "Informācija", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..bc9c2c9 --- /dev/null +++ b/lib/l10n/nl_NL/app_nl_NL.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "nl", + "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": {}, + "allocated": "Toegewezen", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Vierkant (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Voorraad Toewijzen", + "@allocateStock": {}, + "allocatedStock": "Toegewezen voorraad", + "@allocatedStock": {}, + "appReleaseNotes": "App release notities weergeven", + "@appReleaseNotes": {}, + "appSettings": "App Instellingen", + "@appSettings": {}, + "appSettingsDetails": "Configureer InvenTree app instellingen", + "@appSettingsDetails": {}, + "assignedToMe": "Toegewezen aan mij", + "@assignedToMe": {}, + "assignedToMeDetail": "Laat orders zien die aan mij zijn toegewezen", + "@assignedToMeDetail": {}, + "attachments": "Bijlagen", + "@attachments": {}, + "attachImage": "Voeg afbeelding toe", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Geen bijlagen gevonden", + "@attachmentNone": {}, + "attachmentNoneDetail": "Geen bijlage gevonden", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Bijlage selecteren", + "@attachmentSelect": {}, + "attention": "Let op", + "@attention": {}, + "available": "Beschikbaar", + "@available": {}, + "availableStock": "Beschikbare Voorraad", + "@availableStock": {}, + "barcodes": "Barcodes", + "@barcodes": {}, + "barcodeSettings": "Barcode instellingen", + "@barcodeSettings": {}, + "barcodeAssign": "Streepjescode toewijzen", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan aangepaste streepjescode om toe te wijzen", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Scan barcode van onderdeel", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan streepjescode om deel te ontvangen", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barcode scannen gepauzeerd", + "@barodeScanPaused": {}, + "barcodeScanPause": "Klik om scannen te pauzeren", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scan om streepjescode toe te wijzen", + "@barcodeScanAssign": {}, + "barcodeScanController": "Scanner Input", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Selecteer de invoerbron voor barcodescanner", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barcode Scan vertraging", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Vertraging tussen barcode scannen", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scan een InvenTree streepjescode", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scan voorraadartikelen naar deze locatie", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scan voorraadlocatie", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Enkele scan modus", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pauzeer de barcodescanner na elke scan", + "@barcodeScanSingleDetail": {}, + "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": {}, + "bomEnable": "Toon materialen lijst", + "@bomEnable": {}, + "build": "Productie", + "@build": {}, + "building": "Produceren", + "@building": {}, + "cameraCreationError": "Kan de camera controller niet openen", + "@cameraCreationError": {}, + "cameraInternal": "Interne Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Gebruik interne camera om barcodes te lezen", + "@cameraInternalDetail": {}, + "cancel": "Annuleer", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Bestelling annuleren", + "@cancelOrder": {}, + "category": "Categorie", + "@category": {}, + "categoryCreate": "Nieuwe Categorie", + "@categoryCreate": {}, + "categoryCreateDetail": "Creëer nieuw onderdeelcategorie", + "@categoryCreateDetail": {}, + "categoryUpdated": "Onderdeelcategorie bijgewerkt", + "@categoryUpdated": {}, + "company": "Bedrijf", + "@company": {}, + "companyAdd": "Bedrijf toevoegen", + "@companyAdd": {}, + "companyEdit": "Bedrijf bewerken", + "@companyEdit": {}, + "companyNoResults": "Geen enkel bedrijf voldoet aan de zoekopdracht", + "@companyNoResults": {}, + "companyUpdated": "Bedrijfsinstellingen bijgewerkt", + "@companyUpdated": {}, + "companies": "Bedrijven", + "@companies": {}, + "complete": "Gereed", + "@complete": {}, + "completeOrder": "Order Voltooien", + "@completeOrder": {}, + "completionDate": "Datum van afronding", + "@completionDate": {}, + "configureServer": "Configureer server instellingen", + "@configureServer": {}, + "confirmScan": "Bevestig Overdracht", + "@confirmScan": {}, + "confirmScanDetail": "Bevestig voorraadoverdrachtsgegevens bij het scannen van streepjescodes", + "@confirmScanDetail": {}, + "connectionRefused": "Verbinding geweigerd", + "@connectionRefused": {}, + "count": "Tellen", + "@count": { + "description": "Count" + }, + "countStock": "Voorraad tellen", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Bijsnijden", + "@crop": {}, + "cropImage": "Afbeelding bijsnijden", + "@cropImage": {}, + "customer": "Klant", + "@customer": {}, + "customers": "Klanten", + "@customers": {}, + "customerReference": "Klant referentie", + "@customerReference": {}, + "damaged": "Beschadigd", + "@damaged": {}, + "colorScheme": "Kleurenschema", + "@colorScheme": {}, + "colorSchemeDetail": "Selecteer kleurschema", + "@colorSchemeDetail": {}, + "darkMode": "Donkere Modus", + "@darkMode": {}, + "darkModeEnable": "Donkere modus inschakelen", + "@darkModeEnable": {}, + "delete": "Verwijderen", + "@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": "Leveringsdatum", + "@deliveryDate": {}, + "description": "Omschrijving", + "@description": {}, + "destination": "Bestemming:", + "@destination": {}, + "destroyed": "Vernietigd", + "@destroyed": {}, + "details": "Details", + "@details": { + "description": "details" + }, + "documentation": "Documentatie", + "@documentation": {}, + "downloadComplete": "Download voltooid", + "@downloadComplete": {}, + "downloadError": "Fout bij downloaden afbeelding", + "@downloadError": {}, + "downloading": "Bestand wordt gedownload", + "@downloading": {}, + "edit": "Bewerken", + "@edit": { + "description": "edit" + }, + "editAttachment": "Bijlage wijzigen", + "@editAttachment": {}, + "editCategory": "Bewerk Categorie", + "@editCategory": {}, + "editLocation": "Bewerk Locatie", + "@editLocation": {}, + "editNotes": "Bewerk Notities", + "@editNotes": {}, + "editParameter": "Parameter bewerken", + "@editParameter": {}, + "editPart": "Bewerk onderdeel", + "@editPart": { + "description": "edit part" + }, + "editItem": "Bewerk Voorraadartikel", + "@editItem": {}, + "editLineItem": "Voorraadartikel bewerken", + "@editLineItem": {}, + "email": "E-mailadres", + "@email": {}, + "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": {}, + "errorUserRoles": "Fout bij het aanvragen van de gebruikersrollen op de server", + "@errorUserRoles": {}, + "errorPluginInfo": "Fout bij het aanvragen van plug-in gegevens van de server", + "@errorPluginInfo": {}, + "errorReporting": "Fout bij Rapportage", + "@errorReporting": {}, + "errorReportUpload": "Foutrapporten Uploaden", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Upload anonieme foutrapporten en crashlogs", + "@errorReportUploadDetails": {}, + "expiryDate": "Geldig t/m", + "@expiryDate": {}, + "expiryExpired": "Verlopen", + "@expiryExpired": {}, + "expiryStale": "Verouderd", + "@expiryStale": {}, + "extraLineItem": "Extra regelitem", + "@extraLineItem": {}, + "extraLineItems": "Extra regelitems", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Fout bij indienen feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback verzonden", + "@feedbackSuccess": {}, + "filterActive": "Actief", + "@filterActive": {}, + "filterActiveDetail": "Toon actieve onderdelen", + "@filterActiveDetail": {}, + "filterAssembly": "Samengesteld", + "@filterAssembly": {}, + "filterAssemblyDetail": "Toon samengestelde onderdelen", + "@filterAssemblyDetail": {}, + "filterComponent": "Component", + "@filterComponent": {}, + "filterComponentDetail": "Componentonderdelen weergeven", + "@filterComponentDetail": {}, + "filterExternal": "Extern", + "@filterExternal": {}, + "filterExternalDetail": "Voorraad op externe locaties tonen", + "@filterExternalDetail": {}, + "filterInStock": "Op voorraad", + "@filterInStock": {}, + "filterInStockDetail": "Toon onderdelen op voorraad", + "@filterInStockDetail": {}, + "filterSerialized": "Geserialiseerde producten", + "@filterSerialized": {}, + "filterSerializedDetail": "Toon geserialiseerde voorraad items", + "@filterSerializedDetail": {}, + "filterTemplate": "Sjabloon", + "@filterTemplate": {}, + "filterTemplateDetail": "Sjabloononderdelen weergeven", + "@filterTemplateDetail": {}, + "filterTrackable": "Traceerbaar", + "@filterTrackable": {}, + "filterTrackableDetail": "Traceerbare onderdelen weergeven", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtueel", + "@filterVirtual": {}, + "filterVirtualDetail": "Toon virtuele onderdelen", + "@filterVirtualDetail": {}, + "filteringOptions": "Filteropties", + "@filteringOptions": {}, + "formatException": "Formaat fout", + "@formatException": {}, + "formatExceptionJson": "JSON gegevensformaat exceptie", + "@formatExceptionJson": {}, + "formError": "Fout in formulier", + "@formError": {}, + "history": "Geschiedenis", + "@history": { + "description": "history" + }, + "home": "Home", + "@home": {}, + "homeScreen": "Startscherm", + "@homeScreen": {}, + "homeScreenSettings": "Configureer Startscherminstellingen", + "@homeScreenSettings": {}, + "homeShowPo": "Inkooporders tonen", + "@homeShowPo": {}, + "homeShowPoDescription": "Inkooporder knop op startscherm weergeven", + "@homeShowPoDescription": {}, + "homeShowShipments": "Verzending weergeven", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Toon Leveringen in afwachting op het startscherm", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Toon Verkooporders", + "@homeShowSo": {}, + "homeShowSoDescription": "Toon verkooporder knop op startscherm", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Geabonneerde Onderdelen", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Geabonneerde Onderdelen weergeven op startscherm", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Dit bedrijf is gemarkeerd als inactief", + "@inactiveCompany": {}, + "inactiveDetail": "Dit onderdeel is gemarkeerd als inactief", + "@inactiveDetail": {}, + "includeSubcategories": "Inclusief subcategorieën", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Toon resultaten van subcategorieën", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inclusief Sublocaties", + "@includeSublocations": {}, + "includeSublocationsDetail": "Toon resultaten van sub locaties", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Onvolledige profieldetails", + "@incompleteDetails": {}, + "internalPartNumber": "Intern Onderdeelnummer", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "In Productie", + "@inProduction": {}, + "inProductionDetail": "Dit voorraadartikel is in productie", + "@inProductionDetail": {}, + "internalPart": "Intern onderdeel", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Ongeldig Leveranciersonderdeel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Ongeldige gebruikersnaam / wachtwoord combinatie", + "@invalidUsernamePassword": {}, + "invoice": "Factuur", + "@invoice": {}, + "invoiceNumber": "Factuur nummer", + "@invoiceNumber": {}, + "issue": "Probleem", + "@issue": {}, + "issueDate": "Uitgiftedatum", + "@issueDate": {}, + "issueOrder": "Plaats bestelling", + "@issueOrder": {}, + "itemInLocation": "Artikel al op locatie", + "@itemInLocation": {}, + "itemDeleted": "Item is verwijderd", + "@itemDeleted": {}, + "itemUpdated": "Item bijgewerkt", + "@itemUpdated": {}, + "keywords": "Trefwoorden", + "@keywords": {}, + "labelDriver": "Label printer", + "@labelDriver": {}, + "labelSelectDriver": "Selecteer Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label afdrukken", + "@labelPrinting": {}, + "labelPrintingDetail": "Label afdrukken inschakelen", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Labelsjabloon selecteren", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Selecteer Labelprinter", + "@labelSelectPrinter": {}, + "language": "Taal", + "@language": {}, + "languageDefault": "Standaard systeemtaal", + "@languageDefault": {}, + "languageSelect": "Taal selecteren", + "@languageSelect": {}, + "lastStocktake": "Laatste Voorraadcontrole", + "@lastStocktake": {}, + "lastUpdated": "Laatst Bijgewerkt", + "@lastUpdated": {}, + "level": "Niveau", + "@level": {}, + "lineItemAdd": "Regel item toevoegen", + "@lineItemAdd": {}, + "lineItem": "Regelartikel", + "@lineItem": {}, + "lineItems": "Regelartikelen", + "@lineItems": {}, + "lineItemUpdated": "Voorraadartikel bijgewerkt", + "@lineItemUpdated": {}, + "locateItem": "Zoek voorraad item", + "@locateItem": {}, + "locateLocation": "Zoek voorraad locatie", + "@locateLocation": {}, + "locationCreate": "Nieuwe Locatie", + "@locationCreate": {}, + "locationCreateDetail": "Creëer nieuwe voorraadlocatie", + "@locationCreateDetail": {}, + "locationDefault": "Standaard locatie", + "@locationDefault": {}, + "locationNotSet": "Geen locatie opgegeven", + "@locationNotSet": {}, + "locationUpdated": "Voorraadlocatie bijgewerkt", + "@locationUpdated": {}, + "login": "Inloggen", + "@login": {}, + "loginEnter": "Inloggegevens invoeren", + "@loginEnter": {}, + "loginEnterDetails": "Gebruikersnaam en wachtwoord worden niet lokaal opgeslagen", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Verloren", + "@lost": {}, + "manufacturerPart": "Geproduceerde onderdelen", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Fabrikant onderdeel bewerken", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Onderdeelnummer fabrikant", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabrikant", + "@manufacturer": {}, + "manufacturers": "Fabrikanten", + "@manufacturers": {}, + "missingData": "Ontbrekende gegevens", + "@missingData": {}, + "name": "Naam", + "@name": {}, + "no": "Nee", + "@no": {}, + "notApplicable": "N.v.t. ", + "@notApplicable": {}, + "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": {}, + "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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ongeldig nummer", + "@numberInvalid": {}, + "onOrder": "In bestelling", + "@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": "Toon openstaande bestellingen", + "@outstandingOrderDetail": {}, + "overdue": "Achterstallig", + "@overdue": {}, + "overdueDetail": "Toon achterstallige bestellingen", + "@overdueDetail": {}, + "packaging": "Verpakkingen", + "@packaging": {}, + "packageName": "Pakketnaam", + "@packageName": {}, + "parameters": "Parameters", + "@parameters": {}, + "parametersSettingDetail": "Onderdeel parameters weergeven", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Onderdeel niet gemarkeerd als verkoopbaar", + "@partNotSalable": {}, + "partsNone": "Geen onderdelen", + "@partsNone": {}, + "partNoResults": "Geen onderdelen gevonden voor zoekopdracht", + "@partNoResults": {}, + "partPricing": "Prijzen onderdeel", + "@partPricing": {}, + "partPricingSettingDetail": "Toon prijsinformatie onderdeel", + "@pricingSettingDetail": {}, + "partSettings": "Onderdeel instellingen", + "@partSettings": {}, + "partsStarred": "Geabonneerde Onderdelen", + "@partsStarred": {}, + "partsStarredNone": "Geen delen met ster beschikbaar", + "@partsStarredNone": {}, + "partSuppliers": "Onderdeel Leveranciers", + "@partSuppliers": {}, + "partCategory": "Onderdeel Categorie", + "@partCategory": {}, + "partCategoryTopLevel": "Hoogste onderdeel categorie", + "@partCategoryTopLevel": {}, + "partCategories": "Onderdeel Categorieën", + "@partCategories": {}, + "partDetails": "Details Onderdeel", + "@partDetails": {}, + "partNotes": "Notities voor onderdelen", + "@partNotes": {}, + "partStock": "Voorraad Onderdeel", + "@partStock": { + "description": "part stock" + }, + "password": "Wachtwoord", + "@password": {}, + "passwordEmpty": "Wachtwoord mag niet leeg zijn", + "@passwordEmpty": {}, + "pending": "In behandeling", + "@pending": {}, + "permissionAccountDenied": "U heeft niet de vereiste rechten om deze actie uit te voeren", + "@permissionAccountDenied": {}, + "permissionRequired": "Toestemming Vereist", + "@permissionRequired": {}, + "phone": "Telefoon", + "@phone": {}, + "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": {}, + "profileLogout": "Profiel uitloggen", + "@profileLogout": {}, + "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": {}, + "projectCode": "Project Code", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Scan gegevens bevestigen", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Bevestig details bij het scannen van items", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Inkooporders Inschakelen", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Inkooporder functionaliteit inschakelen", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Camera snelkoppeling", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Snelkoppeling voor afbeelding uploaden op aankooporder scherm inschakelen", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Inkooporder", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Nieuwe Inkooporder", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Bewerk Inkooporder", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Inkooporder instellingen", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Inkooporders", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Inkooporder bijgewerkt", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Inkoopprijs", + "@purchasePrice": {}, + "quantity": "Aantal", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Hoeveelheid beschikbaar", + "@quantityAvailable": {}, + "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": {}, + "receivedFilterDetail": "Toon ontvangen artikelen", + "@receivedFilterDetail": {}, + "receiveItem": "Ontvang Artikel", + "@receiveItem": {}, + "receivedItem": "Ontvangen Voorraad Artikelen", + "@receivedItem": {}, + "reference": "Referentie", + "@reference": {}, + "refresh": "Vernieuwen", + "@refresh": {}, + "rotateClockwise": "90° rechtsom draaien", + "@rotateClockwise": {}, + "refreshing": "Verversen…", + "@refreshing": {}, + "rejected": "Geweigerd", + "@rejected": {}, + "releaseNotes": "Release Notes", + "@releaseNotes": {}, + "remove": "Verwijderen", + "@remove": { + "description": "remove" + }, + "removeStock": "Uit Voorraad Verwijderen", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Fout melden", + "@reportBug": {}, + "reportBugDescription": "Verstuur bugrapport (GitHub account vereist)", + "@reportBugDescription": {}, + "responsible": "Verantwoordelijke", + "@responsible": {}, + "results": "Resultaten", + "@results": {}, + "request": "Verzoek", + "@request": {}, + "requestFailed": "Verzoek mislukt", + "@requestFailed": {}, + "requestSuccessful": "Verzoek successvol", + "@requestSuccessful": {}, + "requestingData": "Gegevens Opvragen", + "@requestingData": {}, + "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": {}, + "responseData": "Responsgegevens", + "@responseData": {}, + "responseInvalid": "Ongeldige reactie", + "@responseInvalid": {}, + "responseUnknown": "Onbekende Reactie", + "@responseUnknown": {}, + "result": "Resultaat", + "@result": { + "description": "" + }, + "returned": "Teruggestuurd", + "@returned": {}, + "salesOrder": "Verkooporder", + "@salesOrder": {}, + "salesOrders": "Verkooporders", + "@salesOrders": {}, + "salesOrderEnable": "Verkooporders inschakelen", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Schakel verkooporder functionaliteit in", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Camera snelkoppeling", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Snelkoppeling voor afbeeldingen uploaden op verkooporderscherm inschakelen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Verkooporder Instellingen", + "@salesOrderSettings": {}, + "salesOrderCreate": "Nieuwe verkooporder", + "@saleOrderCreate": {}, + "salesOrderEdit": "Verkooporder bewerken", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Verkooporder bijgewerkt", + "@salesOrderUpdated": {}, + "save": "Bewaren", + "@save": { + "description": "Save" + }, + "scanBarcode": "Streepjescode Scannen", + "@scanBarcode": {}, + "scanSupplierPart": "Scan barcode leveranciersdeel", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan Naar Locatie", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan dit item naar een locatie", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Externe scanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Gebruik externe scanner om barcodes te lezen (wig modus)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan ontvangen onderdelen", + "@scanReceivedParts": {}, + "search": "Zoeken", + "@search": { + "description": "search" + }, + "searching": "Zoeken...", + "@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", + "@searchStock": {}, + "select": "Selecteer", + "@select": {}, + "selectFile": "Selecteer Bestand", + "@selectFile": {}, + "selectImage": "Selecteer afbeelding", + "@selectImage": {}, + "selectLocation": "Selecteer een locatie", + "@selectLocation": {}, + "send": "Verzenden", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "serialNumbers": "Serienummers", + "@serialNumbers": {}, + "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": {}, + "serverMissingData": "Server reactie ontbreekt vereiste velden", + "@serverMissingData": {}, + "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": {}, + "serverNotSelected": "Server niet geselecteerd", + "@serverNotSelected": {}, + "shipment": "Levering", + "@shipment": {}, + "shipments": "Verzendingen", + "@shipments": {}, + "shipmentsPending": "Leveringen in behandeling", + "@shipmentsPending": {}, + "shipmentAdd": "Verzending toevoegen", + "@shipmentAdd": {}, + "shipmentCheck": "Controleer Levering", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Markeer deze levering als gecontroleerd", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Levering gecontroleerd", + "@shipmentChecked": {}, + "shipmentDate": "Leverings Datum", + "@shipmentDate": {}, + "shipmentEdit": "Wijzig levering", + "@shipmentEdit": {}, + "shipmentReference": "Referentie verzending", + "@shipmentReference": {}, + "shipmentSend": "Verzending versturen", + "@shipmentSend": {}, + "shipmentUncheck": "Verzending uitvinken", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Markeer deze levering als niet gecontroleerd", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Verzending bijgewerkt", + "@shipmentUpdated": {}, + "shipped": "Verzonden", + "@shipped": {}, + "sku": "Artikelnummer", + "@sku": {}, + "sounds": "Geluid", + "@sounds": {}, + "soundOnBarcodeAction": "Speel hoorbare toon bij streepjescode actie", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Speel hoorbare toon af bij serverfout", + "@soundOnServerError": {}, + "startDate": "Begindatum", + "@startDate": {}, + "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": {}, + "stockItemUpdateSuccess": "Voorraadartikel bijgewerkt", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Voorraadartikel bijwerken mislukt", + "@stockItemUpdateFailure": {}, + "stockLocation": "Voorraadlocatie", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Voorraadlocaties", + "@stockLocations": {}, + "stockTopLevel": "Hoogste niveau voorraadlocatie", + "@stockTopLevel": {}, + "strictHttps": "Gebruik Strict HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Forceer een strikte controle van HTTPS certificaat", + "@strictHttpsDetails": {}, + "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": {}, + "supplierPart": "Leveranciersonderdeel", + "@supplierPart": {}, + "supplierPartEdit": "Bewerk Leveranciersonderdeel", + "@supplierPartEdit": {}, + "supplierPartNumber": "Onderdeelnummer leverancier", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Leveranciersonderdeel bijgewerkt", + "@supplierPartUpdated": {}, + "supplierParts": "Leveranciersonderdeel", + "@supplierParts": {}, + "suppliers": "Leveranciers", + "@suppliers": {}, + "supplierReference": "Leveranciers Referentie", + "@supplierReference": {}, + "switchCamera": "Camera wisselen", + "@switchCamera": {}, + "takePicture": "Neem een Foto", + "@takePicture": {}, + "targetDate": "Streefdatum", + "@targetDate": {}, + "templatePart": "Bovenliggend sjabloon onderdeel", + "@templatePart": {}, + "testName": "Test Naam", + "@testName": {}, + "testPassedOrFailed": "Test geslaagd of mislukt", + "@testPassedOrFailed": {}, + "testsRequired": "Vereiste Tests", + "@testsRequired": {}, + "testResults": "Testresultaten", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Toon voorraadartikel test resultaat", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Zaklamp aan/uit", + "@toggleTorch": {}, + "tokenError": "Token Fout", + "@tokenError": {}, + "tokenMissing": "Ontbrekende Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Toegang token ontbreekt in antwoord", + "@tokenMissingFromResponse": {}, + "totalPrice": "Totaalprijs", + "@totalPrice": {}, + "trackingNumber": "Traceernummer", + "@trackingNumber": {}, + "transfer": "Verplaats", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Voorraad Verplaatsen", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Item verplaatsen naar een andere locatie", + "@transferStockDetail": {}, + "transferStockLocation": "Voorraad locatie overdragen", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Verplaats deze voorraadlocatie naar een andere locatie", + "@transferStockLocationDetail": {}, + "translate": "Vertalen", + "@translate": {}, + "translateHelp": "Help de InvenTree app te vertalen", + "@translateHelp": {}, + "unavailable": "Niet beschikbaar", + "@unavailable": {}, + "unavailableDetail": "Artikel is niet beschikbaar", + "@unavailableDetail": {}, + "unitPrice": "Stukprijs", + "@unitPrice": {}, + "units": "Eenheden", + "@units": {}, + "unknownResponse": "Onbekende Reactie", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "Bestand uploaden mislukt", + "@uploadFailed": {}, + "uploadSuccess": "Bestand geüpload", + "@uploadSuccess": {}, + "uploadImage": "Afbeelding Uploaden", + "@uploadImage": {}, + "usedIn": "Wordt Gebruikt In", + "@usedIn": {}, + "usedInDetails": "Dit product heeft het volgende onderdeel nodig", + "@usedInDetails": {}, + "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": {}, + "variants": "Varianten", + "@variants": {}, + "version": "Versie", + "@version": {}, + "viewSupplierPart": "Bekijk Leverancier van Onderdeel", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {}, + "yes": "Ja", + "@yes": {}, + "price": "Prijs", + "@price": {}, + "priceRange": "Prijs bereik", + "@priceRange": {}, + "priceOverrideMin": "Minimale prijs overschrijving", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximale prijs overschrijving", + "@priceOverrideMax": {}, + "salePrice": "Verkoop prijs", + "@salePrice": {}, + "saleHistory": "Verkoop geschiedenis", + "@saleHistory": {}, + "supplierPricing": "Leverancier prijzen", + "@supplierPricing": {}, + "bomCost": "BOM Kosten", + "@bomCost": {}, + "internalCost": "Interne kosten", + "@internalCost": {}, + "variantCost": "Variant kosten", + "@variantCost": {}, + "overallPricing": "Algemene prijzen", + "@overallPricing": {}, + "pricingOverrides": "Prijzen overschrijvingen", + "@pricingOverrides": {}, + "currency": "Munteenheid", + "@currency": {}, + "priceBreaks": "Prijsverschillen", + "@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 new file mode 100644 index 0000000..68a6db4 --- /dev/null +++ b/lib/l10n/no_NO/app_no_NO.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Tildelt", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Tildel lagerbeholdning", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Vis appens utgivelsesnotater", + "@appReleaseNotes": {}, + "appSettings": "Appinnstillinger", + "@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", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Ingen vedlegg funnet", + "@attachmentNone": {}, + "attachmentNoneDetail": "Ingen vedlegg funnet", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Velg vedlegg", + "@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", + "@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": {}, + "barcodeScanPart": "Skann del-strekkode", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Skann strekkode for å motta del", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Skanning satt på pause", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@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", + "@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": {}, + "build": "Produksjon", + "@build": {}, + "building": "Produserer", + "@building": {}, + "cameraCreationError": "Kan ikke åpne kamerakontroller", + "@cameraCreationError": {}, + "cameraInternal": "Internt kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Bruk internt kamera til å lese strekkoder", + "@cameraInternalDetail": {}, + "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": "Firma", + "@company": {}, + "companyAdd": "Legg til firma", + "@companyAdd": {}, + "companyEdit": "Rediger Firma", + "@companyEdit": {}, + "companyNoResults": "Ingen firma samsvarer med søket", + "@companyNoResults": {}, + "companyUpdated": "Firmadetaljer oppdatert", + "@companyUpdated": {}, + "companies": "Firma", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Fullført dato", + "@completionDate": {}, + "configureServer": "Konfigurer serverinnstillinger", + "@configureServer": {}, + "confirmScan": "Bekreft overføring", + "@confirmScan": {}, + "confirmScanDetail": "Bekreft lageroverføringsdetaljer når du skanner strekkoder", + "@confirmScanDetail": {}, + "connectionRefused": "Tilkobling avvist", + "@connectionRefused": {}, + "count": "Antall", + "@count": { + "description": "Count" + }, + "countStock": "Tell beholdning", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Krediteringer", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Kunde", + "@customer": {}, + "customers": "Kunder", + "@customers": {}, + "customerReference": "Kundereferanse", + "@customerReference": {}, + "damaged": "Skadet", + "@damaged": {}, + "colorScheme": "Fargetema", + "@colorScheme": {}, + "colorSchemeDetail": "Velg fargeoppsett", + "@colorSchemeDetail": {}, + "darkMode": "Mørk Modus", + "@darkMode": {}, + "darkModeEnable": "Aktiver mørk modus", + "@darkModeEnable": {}, + "delete": "Slett", + "@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", + "@destination": {}, + "destroyed": "Ødelagt", + "@destroyed": {}, + "details": "Detaljer", + "@details": { + "description": "details" + }, + "documentation": "Dokumentasjon", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Laster ned fil", + "@downloading": {}, + "edit": "Rediger", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "Rediger kategori", + "@editCategory": {}, + "editLocation": "Rediger plassering", + "@editLocation": {}, + "editNotes": "Rediger notater", + "@editNotes": {}, + "editParameter": "Rediger Parameter", + "@editParameter": {}, + "editPart": "Rediger del", + "@editPart": { + "description": "edit part" + }, + "editItem": "Rediger lagervare", + "@editItem": {}, + "editLineItem": "Rediger ordrelinje", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Utløpsdato", + "@expiryDate": {}, + "expiryExpired": "Utløpt", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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": {}, + "filterExternal": "Ekstern", + "@filterExternal": {}, + "filterExternalDetail": "Vis lagerbeholdning ved eksterne plasseringer", + "@filterExternalDetail": {}, + "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": "Filtreringsvalg", + "@filteringOptions": {}, + "formatException": "Formatunntak", + "@formatException": {}, + "formatExceptionJson": "JSON-data formatunntak", + "@formatExceptionJson": {}, + "formError": "Skjemafeil", + "@formError": {}, + "history": "Historikk", + "@history": { + "description": "history" + }, + "home": "Hjem", + "@home": {}, + "homeScreen": "Startside", + "@homeScreen": {}, + "homeScreenSettings": "Konfigurer innstillinger for startside", + "@homeScreenSettings": {}, + "homeShowPo": "Vis innkjøpsordrer", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Abonnerte deler", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Vis abonnerte deler på startside", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Dette firmaet er markert som inaktivt", + "@inactiveCompany": {}, + "inactiveDetail": "Denne delen er merket som inaktiv", + "@inactiveDetail": {}, + "includeSubcategories": "Inkluder underkategorier", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Vis resultater fra underkategorier", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inkluder underplasseringer", + "@includeSublocations": {}, + "includeSublocationsDetail": "Vis resulateter fra underplasseringer", + "@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 lagerplassering", + "@invalidStockLocation": {}, + "invalidStockItem": "Ugyldig lagervare", + "@invalidStockItem": {}, + "invalidSupplierPart": "Ugyldig leverandørdel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Ugyldig brukernavn- / passordkombinasjon", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Send", + "@issue": {}, + "issueDate": "Sendt dato", + "@issueDate": {}, + "issueOrder": "Send ordre", + "@issueOrder": {}, + "itemInLocation": "Artikkelen er allerede i plasseringen", + "@itemInLocation": {}, + "itemDeleted": "Elementet har blitt fjernet", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Nøkkelord", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Etikettutskrift", + "@labelPrinting": {}, + "labelPrintingDetail": "Aktiver etikettutskrift", + "@labelPrintingDetail": {}, + "labelTemplate": "Etikettmal", + "@labelTemplate": {}, + "labelSelectTemplate": "Velg etikett mal", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Velg etikett skriver", + "@labelSelectPrinter": {}, + "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": {}, + "lineItemAdd": "Legg til linjeelement", + "@lineItemAdd": {}, + "lineItem": "Ordrelinje", + "@lineItem": {}, + "lineItems": "Ordrelinjer", + "@lineItems": {}, + "lineItemUpdated": "Ordrelinje oppdatert", + "@lineItemUpdated": {}, + "locateItem": "Finn lagervare", + "@locateItem": {}, + "locateLocation": "Finn lagerplassering", + "@locateLocation": {}, + "locationCreate": "Ny plassering", + "@locationCreate": {}, + "locationCreateDetail": "Opprett ny lagerplassering", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "Ingen plassering spesifisert", + "@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", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Produsentens varenummer", + "@manufacturerPartNumber": {}, + "manufacturer": "Produsent", + "@manufacturer": {}, + "manufacturers": "Produsenter", + "@manufacturers": {}, + "missingData": "Manglende data", + "@missingData": {}, + "name": "Navn", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ugyldig tall", + "@numberInvalid": {}, + "onOrder": "I bestilling", + "@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", + "@packageName": {}, + "parameters": "Parametere", + "@parameters": {}, + "parametersSettingDetail": "Vis parametere for del", + "@parametersSettingDetail": {}, + "parent": "Overordnet", + "@parent": {}, + "parentCategory": "Overordnet kategori", + "@parentCategory": {}, + "parentLocation": "Overordnet plassering", + "@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)" + }, + "partNotSalable": "Delen er ikke markert som salgbar", + "@partNotSalable": {}, + "partsNone": "Ingen deler", + "@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", + "@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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Kontoen din har ikke tillatelse til å utføre denne handlingen", + "@permissionAccountDenied": {}, + "permissionRequired": "Tillatelse kreves", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "printLabel": "Skriv ut etikett", + "@printLabel": {}, + "plugin": "Utvidelse", + "@plugin": {}, + "pluginPrinter": "Skriver", + "@pluginPrinter": {}, + "pluginSupport": "Utvidelsesstøtte aktivert", + "@pluginSupport": {}, + "pluginSupportDetail": "Serveren 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": {}, + "profileLogout": "Logg ut profil", + "@profileLogout": {}, + "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": {}, + "projectCode": "Prosjektkode", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Bekreft Skann data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Enable Purchase Orders", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Enable purchase order functionality", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Kamera snarvei", + "@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", + "@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": {}, + "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", + "@receivedItem": {}, + "reference": "Referanse", + "@reference": {}, + "refresh": "Oppdater", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Ansvarlig", + "@responsible": {}, + "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": {}, + "salesOrder": "Salgsordre", + "@salesOrder": {}, + "salesOrders": "Salgsordre", + "@salesOrders": {}, + "salesOrderEnable": "Enable Sales Orders", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Enable sales order functionality", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Kamera snarvei", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Sales order settings", + "@salesOrderSettings": {}, + "salesOrderCreate": "Ny salgsordre", + "@saleOrderCreate": {}, + "salesOrderEdit": "Rediger salgsordre", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Salgsordre oppdatert", + "@salesOrderUpdated": {}, + "save": "Lagre", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skann strekkode", + "@scanBarcode": {}, + "scanSupplierPart": "Skann leverandørdel-strekkode", + "@scanSupplierPart": {}, + "scanIntoLocation": "Skann til plassering", + "@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" + }, + "searching": "Søker", + "@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", + "@searchStock": {}, + "select": "Velg", + "@select": {}, + "selectFile": "Velg fil", + "@selectFile": {}, + "selectImage": "Velg bilde", + "@selectImage": {}, + "selectLocation": "Velg en plassering", + "@selectLocation": {}, + "send": "Send", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "serialNumbers": "Serienummer", + "@serialNumbers": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Lyder", + "@sounds": {}, + "soundOnBarcodeAction": "Spill hørbar tone ved strekkodehandling", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Spill hørbar tone ved serverfeil", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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 plasseringen", + "@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": "Lagerplassering", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerplasseringer", + "@stockLocations": {}, + "stockTopLevel": "Toppnivå-lagerplassering", + "@stockTopLevel": {}, + "strictHttps": "Bruk streng HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Tving streng HTTPS-sertifikatsjekk", + "@strictHttpsDetails": {}, + "subcategory": "Underkategori", + "@subcategory": {}, + "subcategories": "Underkategorier", + "@subcategories": {}, + "sublocation": "Underplassering", + "@sublocation": {}, + "sublocations": "Underplasseringer", + "@sublocations": {}, + "sublocationNone": "Ingen underplasseringer", + "@sublocationNone": {}, + "sublocationNoneDetail": "Ingen underplasseringer 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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "testResultsDetail": "Vis testresultater for lagervare", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token-feil", + "@tokenError": {}, + "tokenMissing": "Manglende token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Adgangstoken mangler i respons", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total pris", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Overfør", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Overfør lagerbeholdning", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Overfør artikkelen til en annen plassering", + "@transferStockDetail": {}, + "transferStockLocation": "Overfør lagerplassering", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Overfør denne lagerplasseringen til en annen", + "@transferStockLocationDetail": {}, + "translate": "Oversett", + "@translate": {}, + "translateHelp": "Hjelp til med å oversette InvenTree-appen", + "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Enhetspris", + "@unitPrice": {}, + "units": "Enheter", + "@units": {}, + "unknownResponse": "Ukjent svar", + "@unknownResponse": {}, + "upload": "Last opp", + "@upload": {}, + "uploadFailed": "Filopplasting mislyktes", + "@uploadFailed": {}, + "uploadSuccess": "Fil lastet opp", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..af85d05 --- /dev/null +++ b/lib/l10n/pl_PL/app_pl_PL.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Przydzielono", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Kwadrat (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Przydziel zapasy", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Wyświetl informacje o historii aktualizacji", + "@appReleaseNotes": {}, + "appSettings": "Ustawienia aplikacji", + "@appSettings": {}, + "appSettingsDetails": "Konfiguruj ustawienia aplikacji InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Przypisane do mnie", + "@assignedToMe": {}, + "assignedToMeDetail": "Pokaż zlecenia, które zostały do mnie przypisane", + "@assignedToMeDetail": {}, + "attachments": "Załączniki", + "@attachments": {}, + "attachImage": "Dodaj zdjęcie", + "@attachImage": { + "description": "Attach an image" + }, + "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": {}, + "barcodeAssignDetail": "Zeskanuj własny kod kreskowy, aby przypisać", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Zeskanuj kod kreskowy części", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Zeskanuj kod kreskowy, aby otrzymać część", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Skanowanie kodów kreskowych wstrzymane", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Zeskanuj aby przypisać kod kreskowy", + "@barcodeScanAssign": {}, + "barcodeScanController": "Wejście skanera", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Wybierz źródło danych skanera kodów kreskowych", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Opóźnienie skanowania kodu kreskowego", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Opóźnienie między skanowaniem kodów kreskowych", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Zeskanuj kod kreskowy InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Zeskanuj przedmioty do tej lokalizacji", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skanuj lokalizację zapasów", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Tryb pojedynczego skanowania", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Wstrzymaj skaner kodów kreskowych po każdym skanowaniu", + "@barcodeScanSingleDetail": {}, + "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": {}, + "bomEnable": "Wyświetl listę materiałów", + "@bomEnable": {}, + "build": "Budowa", + "@build": {}, + "building": "Budowanie", + "@building": {}, + "cameraCreationError": "Nie można otworzyć kamery", + "@cameraCreationError": {}, + "cameraInternal": "Kamera wewnętrzna", + "@cameraInternal": {}, + "cameraInternalDetail": "Użyj wewnętrznej kamery do odczytu kodów kreskowych", + "@cameraInternalDetail": {}, + "cancel": "Anuluj", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Anuluj zamówienie", + "@cancelOrder": {}, + "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": {}, + "companyAdd": "Dodaj firmę", + "@companyAdd": {}, + "companyEdit": "Edytuj Firmę", + "@companyEdit": {}, + "companyNoResults": "Brak firm pasujących do zapytania", + "@companyNoResults": {}, + "companyUpdated": "Szczegóły firmy zostały zaktualizowane", + "@companyUpdated": {}, + "companies": "Firmy", + "@companies": {}, + "complete": "Zakończono", + "@complete": {}, + "completeOrder": "Zakończ zamówienie", + "@completeOrder": {}, + "completionDate": "Data ukończenia", + "@completionDate": {}, + "configureServer": "Konfiguruj ustawienia serwera", + "@configureServer": {}, + "confirmScan": "Potwierdź transfer", + "@confirmScan": {}, + "confirmScanDetail": "Potwierdź szczegóły transferu zapasów podczas skanowania kodów kreskowych", + "@confirmScanDetail": {}, + "connectionRefused": "Połączenie odrzucone", + "@connectionRefused": {}, + "count": "Ilość", + "@count": { + "description": "Count" + }, + "countStock": "Przelicz stan", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Podziękowania", + "@credits": {}, + "crop": "Wytnij", + "@crop": {}, + "cropImage": "Przytnij obraz", + "@cropImage": {}, + "customer": "Klient", + "@customer": {}, + "customers": "Klienci", + "@customers": {}, + "customerReference": "Numer referencyjny klienta", + "@customerReference": {}, + "damaged": "Uszkodzone", + "@damaged": {}, + "colorScheme": "Schemat kolorów", + "@colorScheme": {}, + "colorSchemeDetail": "Wybierz schemat kolorów", + "@colorSchemeDetail": {}, + "darkMode": "Tryb ciemny", + "@darkMode": {}, + "darkModeEnable": "Włącz tryb ciemny", + "@darkModeEnable": {}, + "delete": "Usuń", + "@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:", + "@destination": {}, + "destroyed": "Zniszczony", + "@destroyed": {}, + "details": "Szczegóły", + "@details": { + "description": "details" + }, + "documentation": "Dokumentacja", + "@documentation": {}, + "downloadComplete": "Pobieranie ukończone", + "@downloadComplete": {}, + "downloadError": "Błąd podczas pobierania obrazu", + "@downloadError": {}, + "downloading": "Pobieranie Pliku", + "@downloading": {}, + "edit": "Edytuj", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edytuj załącznik", + "@editAttachment": {}, + "editCategory": "Edytuj kategorię", + "@editCategory": {}, + "editLocation": "Edytuj lokację", + "@editLocation": {}, + "editNotes": "Edytuj Notatki", + "@editNotes": {}, + "editParameter": "Edytuj Parametr", + "@editParameter": {}, + "editPart": "Edytuj część", + "@editPart": { + "description": "edit part" + }, + "editItem": "Edytuj Pozycję Magazynową", + "@editItem": {}, + "editLineItem": "Edytuj element", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "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": {}, + "errorUserRoles": "Błąd podczas wczytywania ról użytkownika z serwera", + "@errorUserRoles": {}, + "errorPluginInfo": "Błąd podczas żądania danych wtyczki z serwera", + "@errorPluginInfo": {}, + "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": {}, + "expiryDate": "Data ważności", + "@expiryDate": {}, + "expiryExpired": "Termin minął", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "Opinie", + "@feedback": {}, + "feedbackError": "Błąd dodawania opinii", + "@feedbackError": {}, + "feedbackSuccess": "Opinia przesłana", + "@feedbackSuccess": {}, + "filterActive": "Aktywny", + "@filterActive": {}, + "filterActiveDetail": "Pokaż aktywne części", + "@filterActiveDetail": {}, + "filterAssembly": "Złożone", + "@filterAssembly": {}, + "filterAssemblyDetail": "Pokaż złożone części", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponent", + "@filterComponent": {}, + "filterComponentDetail": "Pokaż części składowe", + "@filterComponentDetail": {}, + "filterExternal": "Zewnętrzne", + "@filterExternal": {}, + "filterExternalDetail": "Pokaż zapasy w zewnętrznych lokalizacjach", + "@filterExternalDetail": {}, + "filterInStock": "Na stanie", + "@filterInStock": {}, + "filterInStockDetail": "Pokaż części, które są na stanie", + "@filterInStockDetail": {}, + "filterSerialized": "Serializowane", + "@filterSerialized": {}, + "filterSerializedDetail": "Pokaż serializowane elementy magazynowe", + "@filterSerializedDetail": {}, + "filterTemplate": "Szablon", + "@filterTemplate": {}, + "filterTemplateDetail": "Pokaż części szablonu", + "@filterTemplateDetail": {}, + "filterTrackable": "Możliwość śledzenia", + "@filterTrackable": {}, + "filterTrackableDetail": "Pokaż aktywne części", + "@filterTrackableDetail": {}, + "filterVirtual": "Wirtualny", + "@filterVirtual": {}, + "filterVirtualDetail": "Pokaż części wirtualne", + "@filterVirtualDetail": {}, + "filteringOptions": "Opcje filtrowania", + "@filteringOptions": {}, + "formatException": "Wyjątek formatowania", + "@formatException": {}, + "formatExceptionJson": "Wyjątek formatu danych JSON", + "@formatExceptionJson": {}, + "formError": "Błąd Formularza", + "@formError": {}, + "history": "Historia", + "@history": { + "description": "history" + }, + "home": "Strona główna", + "@home": {}, + "homeScreen": "Ekran główny", + "@homeScreen": {}, + "homeScreenSettings": "Konfiguruj ustawienia ekranu głównego", + "@homeScreenSettings": {}, + "homeShowPo": "Pokaż zamówienia zakupu", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Obserwowane części", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Pokaż obserwowane elementy na stronie głównej", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Ta firma jest oznaczona jako nieaktywna", + "@inactiveCompany": {}, + "inactiveDetail": "Ta część jest oznaczona jako nieaktywna", + "@inactiveDetail": {}, + "includeSubcategories": "Zawieraj podkategorie", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Pokaż wyniki z podkategorii", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Zawieraj sublokacje", + "@includeSublocations": {}, + "includeSublocationsDetail": "Pokaż wyniki z sublokacji", + "@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": "Część wewnętrzna", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Nieprawidłowy element dostawcy", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Nieprawidłowy login lub hasło", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Problem", + "@issue": {}, + "issueDate": "Data Wystawienia", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Część jest już w lokacji", + "@itemInLocation": {}, + "itemDeleted": "Element został usunięty", + "@itemDeleted": {}, + "itemUpdated": "Element został zaktualizowany.", + "@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", + "@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", + "@languageDefault": {}, + "languageSelect": "Wybierz język", + "@languageSelect": {}, + "lastStocktake": "Ostatnia inwentaryzacja", + "@lastStocktake": {}, + "lastUpdated": "Ostatnia aktualizacja", + "@lastUpdated": {}, + "level": "Poziom", + "@level": {}, + "lineItemAdd": "Dodaj element pozycji", + "@lineItemAdd": {}, + "lineItem": "Pozycja", + "@lineItem": {}, + "lineItems": "Pozycje", + "@lineItems": {}, + "lineItemUpdated": "Pozycja zaktualizowana", + "@lineItemUpdated": {}, + "locateItem": "Zlokalizuj element magazynowy", + "@locateItem": {}, + "locateLocation": "Zlokalizuj lokalizację zapasów", + "@locateLocation": {}, + "locationCreate": "Nowa Lokalizacja", + "@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", + "@locationUpdated": {}, + "login": "Zaloguj się", + "@login": {}, + "loginEnter": "Wprowadź dane logowania", + "@loginEnter": {}, + "loginEnterDetails": "Nazwa użytkownika i hasło nie są przechowywane lokalnie", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Zagubiono", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Numer Części Producenta (MPN)", + "@manufacturerPartNumber": {}, + "manufacturer": "Producent", + "@manufacturer": {}, + "manufacturers": "Producenci", + "@manufacturers": {}, + "missingData": "Brakujące dane", + "@missingData": {}, + "name": "Nazwa", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Nie połączony", + "@notConnected": {}, + "notes": "Notatki", + "@notes": { + "description": "Notes" + }, + "notifications": "Powiadomienia", + "@notifications": {}, + "notificationsEmpty": "Brak nowych powiadomień", + "@notificationsEmpty": {}, + "noResponse": "Brak odpowiedzi od serwera", + "@noResponse": {}, + "noResults": "Brak wyników", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Błędny numer", + "@numberInvalid": {}, + "onOrder": "W Zamówieniu", + "@onOrder": {}, + "onOrderDetails": "Pozycje obecnie w zamówieniu", + "@onOrderDetails": {}, + "orientation": "Orientacja ekranu", + "@orientation": {}, + "orientationDetail": "Orientacja ekranu (wymaga ponownego uruchomienia)", + "@orientationDetail": {}, + "orientationLandscape": "Poziomo", + "@orientationLandscape": {}, + "orientationPortrait": "Portret", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Zaległe", + "@outstanding": {}, + "outstandingOrderDetail": "Pokaż oczekujące zamówienia", + "@outstandingOrderDetail": {}, + "overdue": "Zaległe", + "@overdue": {}, + "overdueDetail": "Pokaż zaległe zamówienia", + "@overdueDetail": {}, + "packaging": "Opakowanie", + "@packaging": {}, + "packageName": "Nazwa pakietu", + "@packageName": {}, + "parameters": "Parametry", + "@parameters": {}, + "parametersSettingDetail": "Wyświetl parametry części", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Część nie oznaczona jako sprzedawalna", + "@partNotSalable": {}, + "partsNone": "Brak części", + "@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", + "@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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Nie masz wystarczających uprawnień do wykonania tej czynności", + "@permissionAccountDenied": {}, + "permissionRequired": "Wymagane uprawnienia", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "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", + "@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": {}, + "profileLogout": "Wyloguj się", + "@profileLogout": {}, + "profileName": "Nazwa Profilu", + "@profileName": {}, + "profileNone": "Brak dostępnych profili", + "@profileNone": {}, + "profileNotSelected": "Nie wybrano profilu", + "@profileNotSelected": {}, + "profileSelect": "Wybierz serwer InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Wybierz serwer lub utwórz nowy profil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Dotknij, aby utworzyć lub wybrać profil", + "@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", + "@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", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Cena Zakupu", + "@purchasePrice": {}, + "quantity": "Ilość", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Dostępna ilość", + "@quantityAvailable": {}, + "quantityEmpty": "Ilość jest pusta", + "@quantityEmpty": {}, + "quantityInvalid": "Ilość jest nieprawidłowa", + "@quantityInvalid": {}, + "quantityPositive": "Ilość musi być dodatnia", + "@quantityPositive": {}, + "queryEmpty": "Wpisz szukaną frazę", + "@queryEmpty": {}, + "queryNoResults": "Nie znaleziono wyników dla zapytania", + "@queryNoResults": {}, + "received": "Odebrane", + "@received": {}, + "receivedFilterDetail": "Pokaż otrzymane elementy", + "@receivedFilterDetail": {}, + "receiveItem": "Przyjmij artykuły", + "@receiveItem": {}, + "receivedItem": "Przyjęta Pozycja Magazynowa", + "@receivedItem": {}, + "reference": "Odwołanie", + "@reference": {}, + "refresh": "Odśwież", + "@refresh": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Odpowiedzialny", + "@responsible": {}, + "results": "Wyniki", + "@results": {}, + "request": "Żądanie", + "@request": {}, + "requestFailed": "Żądanie nie powiodło się", + "@requestFailed": {}, + "requestSuccessful": "Żądanie zakończone sukcesem", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Zlecenie sprzedaży", + "@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", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Zlecenie sprzedaży zaktualizowane", + "@salesOrderUpdated": {}, + "save": "Zapisz", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skanuj kod kreskowy", + "@scanBarcode": {}, + "scanSupplierPart": "Zeskanuj kod kreskowy dostawcy", + "@scanSupplierPart": {}, + "scanIntoLocation": "Skanuj do lokacji", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Zeskanuj ten przedmiot w lokalizację", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Zewnętrzny skaner", + "@scannerExternal": {}, + "scannerExternalDetail": "Użyj zewnętrznego skanera do odczytu kodów kreskowych (tryb klina)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Skanuj otrzymane części", + "@scanReceivedParts": {}, + "search": "Szukaj", + "@search": { + "description": "search" + }, + "searching": "Wyszukiwanie", + "@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", + "@searchStock": {}, + "select": "Wybierz", + "@select": {}, + "selectFile": "Wybierz Plik", + "@selectFile": {}, + "selectImage": "Wybierz obraz", + "@selectImage": {}, + "selectLocation": "Wybierz lokację", + "@selectLocation": {}, + "send": "Wyślij", + "@send": {}, + "serialNumber": "Numer seryjny", + "@serialNumber": {}, + "serialNumbers": "Numery seryjne", + "@serialNumbers": {}, + "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": {}, + "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", + "@sku": {}, + "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": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "Status", + "@status": {}, + "statusCode": "Kod statusu", + "@statusCode": {}, + "stock": "Stan", + "@stock": { + "description": "stock" + }, + "stockDetails": "Aktualna dostępna ilość zapasów", + "@stockDetails": {}, + "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": {}, + "supplierPart": "Część dostawcy", + "@supplierPart": {}, + "supplierPartEdit": "Edytuj część dostawcy", + "@supplierPartEdit": {}, + "supplierPartNumber": "Numer częsci dostawcy", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Komponenty dostawcy zaktualizowane", + "@supplierPartUpdated": {}, + "supplierParts": "Komponenty dostawcy", + "@supplierParts": {}, + "suppliers": "Dostawcy", + "@suppliers": {}, + "supplierReference": "Identyfikator Dostawcy", + "@supplierReference": {}, + "switchCamera": "Przełącz aparat", + "@switchCamera": {}, + "takePicture": "Zrób zdjęcie", + "@takePicture": {}, + "targetDate": "Data Docelowa", + "@targetDate": {}, + "templatePart": "Część szablonu nadrzędnego", + "@templatePart": {}, + "testName": "Nazwa testu", + "@testName": {}, + "testPassedOrFailed": "Test zaliczony lub nieudany", + "@testPassedOrFailed": {}, + "testsRequired": "Wymagane testy", + "@testsRequired": {}, + "testResults": "Wyniki testu", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Wyświetl wyniki testu elementu magazynowego", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Błąd tokenu", + "@tokenError": {}, + "tokenMissing": "Brakujący token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Brak tokenu dostępu w odpowiedzi", + "@tokenMissingFromResponse": {}, + "totalPrice": "Cena całkowita", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Przenieś", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Przenieś stan", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Przenieś element do innej lokalizacji", + "@transferStockDetail": {}, + "transferStockLocation": "Przenieś lokalizację zapasów", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Przenieś tę lokalizację zapasów do innego", + "@transferStockLocationDetail": {}, + "translate": "Przetłumacz", + "@translate": {}, + "translateHelp": "Pomóż przetłumaczyć aplikację InvenTree", + "@translateHelp": {}, + "unavailable": "Niedostępny", + "@unavailable": {}, + "unavailableDetail": "Produkt nie jest dostępny", + "@unavailableDetail": {}, + "unitPrice": "Cena jednostkowa", + "@unitPrice": {}, + "units": "Jednostki", + "@units": {}, + "unknownResponse": "Nieznana odpowiedź", + "@unknownResponse": {}, + "upload": "Wyślij", + "@upload": {}, + "uploadFailed": "Błąd wysyłania pliku", + "@uploadFailed": {}, + "uploadSuccess": "Plik przesłany", + "@uploadSuccess": {}, + "uploadImage": "Załaduj obraz", + "@uploadImage": {}, + "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": {}, + "variants": "Warianty", + "@variants": {}, + "version": "Wersja", + "@version": {}, + "viewSupplierPart": "Zobacz Dostawcę Części", + "@viewSupplierPart": {}, + "website": "Strona WWW", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "price": "Cena", + "@price": {}, + "priceRange": "Zakres cen", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Cena sprzedaży", + "@salePrice": {}, + "saleHistory": "Historia cen", + "@saleHistory": {}, + "supplierPricing": "Supplier Pricing", + "@supplierPricing": {}, + "bomCost": "Koszt BOM", + "@bomCost": {}, + "internalCost": "Koszt wewnętrzny", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Waluta", + "@currency": {}, + "priceBreaks": "Widełki cenowe", + "@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 new file mode 100644 index 0000000..85866f9 --- /dev/null +++ b/lib/l10n/pt_BR/app_pt_BR.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "pt-BR", + "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 estoque", + "@addStock": { + "description": "add stock" + }, + "address": "Endereço", + "@address": {}, + "appAbout": "Sobre InvenTree", + "@appAbout": {}, + "appCredits": "Outros créditos do aplicativo", + "@appCredits": {}, + "appDetails": "Detalhes do aplicativo", + "@appDetails": {}, + "allocated": "Alocar", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Quadrado (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Estoque alocado", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Exibir notas de versão do aplicativo", + "@appReleaseNotes": {}, + "appSettings": "Configurações do App", + "@appSettings": {}, + "appSettingsDetails": "Configurar os parâmetros do App do InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Atribuído a mim", + "@assignedToMe": {}, + "assignedToMeDetail": "Mostrar pedidos atribuídos a mim", + "@assignedToMeDetail": {}, + "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": "Atenção", + "@attention": {}, + "available": "Disponível", + "@available": {}, + "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", + "@barcodeAssignDetail": {}, + "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": "Nenhum código de barras correspondente", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Código de barras não atribuído", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Escanear código de barras de peça", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Digitalize o código de barras para receber a parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Escaneamento de código de barras pausado", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@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", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Busca de itens de estoque para este local", + "@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", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Escanear item em estoque", + "@barcodeScanItem": {}, + "barcodeTones": "Tons de código de barras", + "@barcodeTones": {}, + "barcodeUnassign": "Desatribuir Código de Barras", + "@barcodeUnassign": {}, + "barcodeUnknown": "Código de barras não reconhecido", + "@barcodeUnknown": {}, + "batchCode": "Código do lote", + "@batchCode": {}, + "billOfMaterials": "Lista de Materiais", + "@billOfMaterials": {}, + "bom": "LDM", + "@bom": {}, + "bomEnable": "Mostrar Lista de Materiais", + "@bomEnable": {}, + "build": "Produzir", + "@build": {}, + "building": "Produzindo", + "@building": {}, + "cameraCreationError": "Não foi possível abrir o controle da câmera", + "@cameraCreationError": {}, + "cameraInternal": "Câmera Interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Usar câmera interna para ler códigos de barras", + "@cameraInternalDetail": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancelar Pedido", + "@cancelOrder": {}, + "category": "Categoria", + "@category": {}, + "categoryCreate": "Nova categoria", + "@categoryCreate": {}, + "categoryCreateDetail": "Criar categoria de produtos", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categoria de produtos atualizada", + "@categoryUpdated": {}, + "company": "Companhia", + "@company": {}, + "companyAdd": "Adicionar Empresa", + "@companyAdd": {}, + "companyEdit": "Editar Empresa", + "@companyEdit": {}, + "companyNoResults": "Nenhuma empresa corresponde a essa consulta", + "@companyNoResults": {}, + "companyUpdated": "Dados da empresa atualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "complete": "Concluído", + "@complete": {}, + "completeOrder": "Finalizar pedido", + "@completeOrder": {}, + "completionDate": "Data de conclusão", + "@completionDate": {}, + "configureServer": "Definir as configurações do servidor", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Contar estoque", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "crop": "Recortar", + "@crop": {}, + "cropImage": "Cortar Imagem", + "@cropImage": {}, + "customer": "Cliente", + "@customer": {}, + "customers": "Clientes", + "@customers": {}, + "customerReference": "Referência do Cliente", + "@customerReference": {}, + "damaged": "Danificado", + "@damaged": {}, + "colorScheme": "Esquema de cores", + "@colorScheme": {}, + "colorSchemeDetail": "Selecionar esquema de cores", + "@colorSchemeDetail": {}, + "darkMode": "Modo Escuro", + "@darkMode": {}, + "darkModeEnable": "Habilitar o modo escuro", + "@darkModeEnable": {}, + "delete": "Deletar", + "@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", + "@destination": {}, + "destroyed": "Destruído", + "@destroyed": {}, + "details": "Detalhes", + "@details": { + "description": "details" + }, + "documentation": "Documentação", + "@documentation": {}, + "downloadComplete": "Download concluído", + "@downloadComplete": {}, + "downloadError": "Erro ao baixar a imagem", + "@downloadError": {}, + "downloading": "Baixando arquivo", + "@downloading": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editAttachment": "Editar Anexo", + "@editAttachment": {}, + "editCategory": "Editar categoria", + "@editCategory": {}, + "editLocation": "Editar Local", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editParameter": "Editar Parâmetro", + "@editParameter": {}, + "editPart": "Editar a peça", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar Item do Estoque", + "@editItem": {}, + "editLineItem": "Editar Item de Linha", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "enterPassword": "Digite a senha", + "@enterPassword": {}, + "enterUsername": "Informe o usuário", + "@enterUsername": {}, + "error": "Erro", + "@error": { + "description": "Error" + }, + "errorCreate": "Erro ao criar entrada no banco de dados", + "@errorCreate": {}, + "errorDelete": "Erro ao deletar entrada no banco de dados", + "@errorDelete": {}, + "errorDetails": "Detalhes do erro", + "@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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Enviar relatórios de erros anônimos e logs de falhas", + "@errorReportUploadDetails": {}, + "expiryDate": "Data de validade", + "@expiryDate": {}, + "expiryExpired": "Vencido", + "@expiryExpired": {}, + "expiryStale": "Inativo", + "@expiryStale": {}, + "extraLineItem": "Item de Linha extra", + "@extraLineItem": {}, + "extraLineItems": "Itens de linha extra", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Erro ao enviar o feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback enviado", + "@feedbackSuccess": {}, + "filterActive": "Ativo", + "@filterActive": {}, + "filterActiveDetail": "Exibir peças ativas", + "@filterActiveDetail": {}, + "filterAssembly": "Montado", + "@filterAssembly": {}, + "filterAssemblyDetail": "Exibir peças montadas", + "@filterAssemblyDetail": {}, + "filterComponent": "Componente", + "@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", + "@filterInStockDetail": {}, + "filterSerialized": "Serializado", + "@filterSerialized": {}, + "filterSerializedDetail": "Mostrar itens de estoque serializados", + "@filterSerializedDetail": {}, + "filterTemplate": "Modelo", + "@filterTemplate": {}, + "filterTemplateDetail": "Mostrar modelo de peças", + "@filterTemplateDetail": {}, + "filterTrackable": "Rastreável", + "@filterTrackable": {}, + "filterTrackableDetail": "Mostrar peças rastreáveis", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Mostrar peças virtuais", + "@filterVirtualDetail": {}, + "filteringOptions": "Opções de filtros", + "@filteringOptions": {}, + "formatException": "Exceção de Formato", + "@formatException": {}, + "formatExceptionJson": "Exceção de formato de dados JSON", + "@formatExceptionJson": {}, + "formError": "Erro no formulário", + "@formError": {}, + "history": "Histórico", + "@history": { + "description": "history" + }, + "home": "Início", + "@home": {}, + "homeScreen": "Tela inicial", + "@homeScreen": {}, + "homeScreenSettings": "Definir as configurações da tela inicial", + "@homeScreenSettings": {}, + "homeShowPo": "Mostrar pedidos de compra", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Peças subscritas", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostrar peças subscritas na tela inicial", + "@homeShowSubscsribedDescription": {}, + "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": {}, + "inactiveCompany": "Esta empresa está marcada como inativa", + "@inactiveCompany": {}, + "inactiveDetail": "Este produto esta marcado como inativo", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir sub-categorias", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar resultados das subcategorias", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incuir Sub-Locacoes", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar resultados de sublocais", + "@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": {}, + "internalPart": "Peça Interna", + "@internalPart": {}, + "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": {}, + "invalidSupplierPart": "Fornecedor da Peça Inválido", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Usuario ou senha invalidos", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Emitir", + "@issue": {}, + "issueDate": "Data de emissao", + "@issueDate": {}, + "issueOrder": "Emitir Pedido", + "@issueOrder": {}, + "itemInLocation": "Item ja na localizacao", + "@itemInLocation": {}, + "itemDeleted": "O item foi removido", + "@itemDeleted": {}, + "itemUpdated": "Item atualizado", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Modelo de descricao", + "@labelTemplate": {}, + "labelSelectTemplate": "Selecione o Modelo de Etiqueta", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Selecione a impressora de etiqueta", + "@labelSelectPrinter": {}, + "language": "Idioma", + "@language": {}, + "languageDefault": "Idioma padrão do sistema", + "@languageDefault": {}, + "languageSelect": "Selecionar Idioma", + "@languageSelect": {}, + "lastStocktake": "Ultimo dado de estoque", + "@lastStocktake": {}, + "lastUpdated": "Ultima atualizacao", + "@lastUpdated": {}, + "level": "Nível", + "@level": {}, + "lineItemAdd": "Adicionar item de linha", + "@lineItemAdd": {}, + "lineItem": "Linha do item", + "@lineItem": {}, + "lineItems": "Linhas do item", + "@lineItems": {}, + "lineItemUpdated": "Item de linha atualizado", + "@lineItemUpdated": {}, + "locateItem": "Localizar produto no estoque", + "@locateItem": {}, + "locateLocation": "Localizar no estoque", + "@locateLocation": {}, + "locationCreate": "Nova localizacao", + "@locationCreate": {}, + "locationCreateDetail": "Criar nova localizacao no estoque", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "Nenhuma localizacao especificada", + "@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", + "@lost": {}, + "manufacturerPart": "Fabricante da peça", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Editar Fabricante de Peça", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Número de Peça do Fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "missingData": "Dados indisponiveis", + "@missingData": {}, + "name": "Nome", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Nao conectado", + "@notConnected": {}, + "notes": "Notas", + "@notes": { + "description": "Notes" + }, + "notifications": "Notificacoes", + "@notifications": {}, + "notificationsEmpty": "Nenhuma notificao pendente", + "@notificationsEmpty": {}, + "noResponse": "Sem resposta do servidor", + "@noResponse": {}, + "noResults": "Nenhum Resultado", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Número inválido", + "@numberInvalid": {}, + "onOrder": "No pedido", + "@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 pedidos pendentes", + "@outstandingOrderDetail": {}, + "overdue": "Em atraso", + "@overdue": {}, + "overdueDetail": "Mostrar pedidos atrasados", + "@overdueDetail": {}, + "packaging": "Embalagem", + "@packaging": {}, + "packageName": "Nome do pacote", + "@packageName": {}, + "parameters": "Parâmetros", + "@parameters": {}, + "parametersSettingDetail": "Mostrar Parâmetros da Peça", + "@parametersSettingDetail": {}, + "parent": "Parental", + "@parent": {}, + "parentCategory": "Categoria Parental", + "@parentCategory": {}, + "parentLocation": "Localização Parental", + "@parentLocation": {}, + "part": "Peça", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Nova Peça", + "@partCreate": {}, + "partCreateDetail": "Criar uma peça nesta categoria", + "@partCreateDetail": {}, + "partEdited": "Peça atualizada", + "@partEdited": {}, + "parts": "Peças", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Peça não marcada como vendível", + "@partNotSalable": {}, + "partsNone": "Sem peças", + "@partsNone": {}, + "partNoResults": "Nenhuma peça corresponde a consulta", + "@partNoResults": {}, + "partPricing": "Preço de Peça", + "@partPricing": {}, + "partPricingSettingDetail": "Exibir informações de preço de parte", + "@pricingSettingDetail": {}, + "partSettings": "Configurações de Peça", + "@partSettings": {}, + "partsStarred": "Peças subscritas", + "@partsStarred": {}, + "partsStarredNone": "Nenhuma peça com estrela disponível", + "@partsStarredNone": {}, + "partSuppliers": "Fornecedores de peças", + "@partSuppliers": {}, + "partCategory": "Categoria da peça", + "@partCategory": {}, + "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", + "@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", + "@permissionRequired": {}, + "phone": "Telefone", + "@phone": {}, + "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": {}, + "profileLogout": "Desconectar Perfil", + "@profileLogout": {}, + "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": {}, + "projectCode": "Código do projeto", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirmar dados de varredura", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirmar detalhes ao escanear itens", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Habilitar Pedidos de Compra", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Habilitar funcionalidade de pedido de compra", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Atalho da Câmera", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Habilitar atalho para upload de imagem na tela de ordem de compra", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Ordem de Compra", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Novo Pedido de Compra", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Editar ordem de compra", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Configurações do Pedido de Compra", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Ordens de compras", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Ordem de compra atualizada", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Preco de compra", + "@purchasePrice": {}, + "quantity": "Quantidade", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Quantidade Disponível", + "@quantityAvailable": {}, + "quantityEmpty": "Quantidade esta em branco", + "@quantityEmpty": {}, + "quantityInvalid": "Quantidade invalida", + "@quantityInvalid": {}, + "quantityPositive": "Quantidade precisa ser positiva", + "@quantityPositive": {}, + "queryEmpty": "Entre dados para busca", + "@queryEmpty": {}, + "queryNoResults": "Nenhuma resultado para busca", + "@queryNoResults": {}, + "received": "Recebido", + "@received": {}, + "receivedFilterDetail": "Mostrar itens recebidos", + "@receivedFilterDetail": {}, + "receiveItem": "Item recebido", + "@receiveItem": {}, + "receivedItem": "Item de estoque recebido", + "@receivedItem": {}, + "reference": "Referência", + "@reference": {}, + "refresh": "Atualizar", + "@refresh": {}, + "rotateClockwise": "Girar 90° no sentido horário", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsável", + "@responsible": {}, + "results": "Resultado", + "@results": {}, + "request": "Pedido", + "@request": {}, + "requestFailed": "Ops! Falha na solicitação", + "@requestFailed": {}, + "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": {}, + "salesOrder": "Pedido de Venda", + "@salesOrder": {}, + "salesOrders": "Pedido de vendas", + "@salesOrders": {}, + "salesOrderEnable": "Habilitar Pedidos de Vendas", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Habilitar funcionalidade de ordem de venda", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Atalho da Câmera", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Habilitar atalho para upload de imagem na tela de ordem de venda", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Configurações do Pedido de Venda", + "@salesOrderSettings": {}, + "salesOrderCreate": "Novo Pedido de Venda", + "@saleOrderCreate": {}, + "salesOrderEdit": "Editar Pedidos de Venda", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Pedido de venda atualizado", + "@salesOrderUpdated": {}, + "save": "Salvar", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanear Cod Bar", + "@scanBarcode": {}, + "scanSupplierPart": "Escanear código de barras de peça de fornecedor", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scan para localizacao", + "@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" + }, + "searching": "Buscando", + "@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", + "@searchStock": {}, + "select": "Selecionar", + "@select": {}, + "selectFile": "Selecionar Arquivo", + "@selectFile": {}, + "selectImage": "Selecionar Imagem", + "@selectImage": {}, + "selectLocation": "Selecionar um local", + "@selectLocation": {}, + "send": "Enviar", + "@send": {}, + "serialNumber": "Número de Série", + "@serialNumber": {}, + "serialNumbers": "Números de Série", + "@serialNumbers": {}, + "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", + "@serverDetails": {}, + "serverMissingData": "Faltam campos obrigatórios para resposta do servidor", + "@serverMissingData": {}, + "serverOld": "Versão antiga do servidor", + "@serverOld": {}, + "serverSettings": "Configurações do servidor", + "@serverSettings": {}, + "serverStart": "Servidor deve iniciar com http[s]", + "@serverStart": {}, + "settings": "Configurações", + "@settings": {}, + "serverInstance": "Instância do servidor", + "@serverInstance": {}, + "serverNotConnected": "Servidor não conectado", + "@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)", + "@sku": {}, + "sounds": "Sons", + "@sounds": {}, + "soundOnBarcodeAction": "Tocar tom audível na ação do código de barras", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Tocar tom audível no erro do servidor", + "@soundOnServerError": {}, + "startDate": "Data Inicial", + "@startDate": {}, + "status": "Estado", + "@status": {}, + "statusCode": "Código do Estado", + "@statusCode": {}, + "stock": "Estoque", + "@stock": { + "description": "stock" + }, + "stockDetails": "Atual quantidade de estoque disponível", + "@stockDetails": {}, + "stockItem": "Item de estoque", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Itens de Estoque", + "@stockItems": {}, + "stockItemCreate": "Novo item de estoque", + "@stockItemCreate": {}, + "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": {}, + "stockItemDeleteFailure": "Não foi possível excluir o item de estoque", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Item de estoque excluído", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Histórico de estoque", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Exibir informações históricas de rastreamento de estoque", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Item de estoque transferido", + "@stockItemTransferred": {}, + "stockItemUpdated": "Item de estoque atualizado", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nenhum item de estoque disponível", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Notas de Item em Estoque", + "@stockItemNotes": {}, + "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": {}, + "supplierPart": "Fornecedor da Peça", + "@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", + "@supplierParts": {}, + "suppliers": "Fornecedores", + "@suppliers": {}, + "supplierReference": "Referencia do fornecedor", + "@supplierReference": {}, + "switchCamera": "Mudar Câmera", + "@switchCamera": {}, + "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": "" + }, + "testResultsDetail": "Mostrar resultados do teste de item de estoque", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Lig/Desl. lanterna", + "@toggleTorch": {}, + "tokenError": "Error de token", + "@tokenError": {}, + "tokenMissing": "Token indisponivel", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token indisponivel na resposta", + "@tokenMissingFromResponse": {}, + "totalPrice": "Preço Total", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "Transferir", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transferir estoque", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transferir item para um local diferente", + "@transferStockDetail": {}, + "transferStockLocation": "Transferir Localização do Estoque", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transferir este local de estoque para outro", + "@transferStockLocationDetail": {}, + "translate": "Traduzir", + "@translate": {}, + "translateHelp": "Ajude a traduzir", + "@translateHelp": {}, + "unavailable": "Indisponível", + "@unavailable": {}, + "unavailableDetail": "Item não está disponível", + "@unavailableDetail": {}, + "unitPrice": "Preço unitário", + "@unitPrice": {}, + "units": "Unidades", + "@units": {}, + "unknownResponse": "Reposta invalida", + "@unknownResponse": {}, + "upload": "Subir", + "@upload": {}, + "uploadFailed": "Upload de arquivo falhou", + "@uploadFailed": {}, + "uploadSuccess": "Arquivo adicionado com sucesso", + "@uploadSuccess": {}, + "uploadImage": "Enviar imagem", + "@uploadImage": {}, + "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": {}, + "variants": "Variantes", + "@variants": {}, + "version": "Versão", + "@version": {}, + "viewSupplierPart": "Ver peça do fornecedor", + "@viewSupplierPart": {}, + "website": "Página Web", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "price": "Preço", + "@price": {}, + "priceRange": "Faixa de Preço", + "@priceRange": {}, + "priceOverrideMin": "Substituição de preço mínimo", + "@priceOverrideMin": {}, + "priceOverrideMax": "Substituição de preço máximo", + "@priceOverrideMax": {}, + "salePrice": "Preço de Venda", + "@salePrice": {}, + "saleHistory": "Histórico de Vendas", + "@saleHistory": {}, + "supplierPricing": "Preço do fornecedor", + "@supplierPricing": {}, + "bomCost": "Custo de LDM", + "@bomCost": {}, + "internalCost": "Custo Interno", + "@internalCost": {}, + "variantCost": "Custo Variante", + "@variantCost": {}, + "overallPricing": "Precificação Geral", + "@overallPricing": {}, + "pricingOverrides": "Sobrescrever Preço", + "@pricingOverrides": {}, + "currency": "Moeda", + "@currency": {}, + "priceBreaks": "Quebra de Preço", + "@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 new file mode 100644 index 0000000..87997d3 --- /dev/null +++ b/lib/l10n/pt_PT/app_pt_PT.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "pt-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": {}, + "allocated": "Alocado", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Quadrado (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Alocar estoque", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Exibir notas de versão do aplicativo", + "@appReleaseNotes": {}, + "appSettings": "Configurações do App", + "@appSettings": {}, + "appSettingsDetails": "Configurar os parâmetros do InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Atribuído a Mim", + "@assignedToMe": {}, + "assignedToMeDetail": "Mostrar pedidos atribuídos a mim", + "@assignedToMeDetail": {}, + "attachments": "Anexos", + "@attachments": {}, + "attachImage": "Anexar Imagem", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Não foram encontrados quaisquer anexos", + "@attachmentNone": {}, + "attachmentNoneDetail": "Não foram encontrados anexos", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Selecionar anexo", + "@attachmentSelect": {}, + "attention": "Aviso", + "@attention": {}, + "available": "Disponível", + "@available": {}, + "availableStock": "Stock 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", + "@barcodeAssignDetail": {}, + "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": {}, + "barcodeScanPart": "Digitalizar o código de barras da parte", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Digitalize o código de barras para receber a parte", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Verificação do código de barras pausada", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Escaneie para atribuir código de barras", + "@barcodeScanAssign": {}, + "barcodeScanController": "Entrada do Scanner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Selecionar fonte de entrada do leitor de códigos de barras", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Atraso na entrada do código de barras", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Atraso entre digitalizações de código de barras", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Escaneie um código de barras do InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Buscar itens de estoque neste local", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Escanear Localização", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Modo de varredura única", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pausar leitor de código de barras após cada verificação", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Escaneado no local", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "O item não foi digitalizado em", + "@barcodeScanIntoLocationFailure": {}, + "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": {}, + "bomEnable": "Mostrar Lista de Materiais", + "@bomEnable": {}, + "build": "Compilar", + "@build": {}, + "building": "Compilando", + "@building": {}, + "cameraCreationError": "Não foi possível aceder ao controlo da câmara", + "@cameraCreationError": {}, + "cameraInternal": "Câmera Interna", + "@cameraInternal": {}, + "cameraInternalDetail": "Usar a câmera interna para ler códigos de barras", + "@cameraInternalDetail": {}, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Cancelar pedido", + "@cancelOrder": {}, + "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": {}, + "companyAdd": "Adicionar Empresa", + "@companyAdd": {}, + "companyEdit": "Editar empresa", + "@companyEdit": {}, + "companyNoResults": "Nenhuma empresa corresponde a consulta", + "@companyNoResults": {}, + "companyUpdated": "Dados da empresa atualizados", + "@companyUpdated": {}, + "companies": "Empresas", + "@companies": {}, + "complete": "Finalizar", + "@complete": {}, + "completeOrder": "Finalizar Encomenda", + "@completeOrder": {}, + "completionDate": "Data de conclusão", + "@completionDate": {}, + "configureServer": "Configurar os parâmetros do servidor de email", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Contagem de Estoque", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Créditos", + "@credits": {}, + "crop": "Cortar", + "@crop": {}, + "cropImage": "Recortar Imagem", + "@cropImage": {}, + "customer": "Cliente", + "@customer": {}, + "customers": "Clientes", + "@customers": {}, + "customerReference": "Referência do Cliente", + "@customerReference": {}, + "damaged": "Danificado", + "@damaged": {}, + "colorScheme": "Esquema de cores", + "@colorScheme": {}, + "colorSchemeDetail": "Seleccione o esquema de cores", + "@colorSchemeDetail": {}, + "darkMode": "Modo Noturno", + "@darkMode": {}, + "darkModeEnable": "Ativar modo noturno", + "@darkModeEnable": {}, + "delete": "Excluir", + "@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", + "@destination": {}, + "destroyed": "Destruído", + "@destroyed": {}, + "details": "Detalhes", + "@details": { + "description": "details" + }, + "documentation": "Documentação", + "@documentation": {}, + "downloadComplete": "Transferência concluída", + "@downloadComplete": {}, + "downloadError": "Erro ao transferir imagem", + "@downloadError": {}, + "downloading": "Baixando arquivo", + "@downloading": {}, + "edit": "Editar", + "@edit": { + "description": "edit" + }, + "editAttachment": "Editar Anexo", + "@editAttachment": {}, + "editCategory": "Editar categoria", + "@editCategory": {}, + "editLocation": "Editar Localização", + "@editLocation": {}, + "editNotes": "Editar notas", + "@editNotes": {}, + "editParameter": "Editar Parâmetro", + "@editParameter": {}, + "editPart": "Editar a peça", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editar Item do Estoque", + "@editItem": {}, + "editLineItem": "Editar item de linha", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "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": {}, + "errorDetails": "Detalhes do erro", + "@errorDetails": {}, + "errorFetch": "Erro ao recolher dados do servidor", + "@errorFetch": {}, + "errorUserRoles": "Erro ao solicitar funções de usuário do servidor", + "@errorUserRoles": {}, + "errorPluginInfo": "Erro ao solicitar dados do plugin do servidor", + "@errorPluginInfo": {}, + "errorReporting": "Comunicação de Erros", + "@errorReporting": {}, + "errorReportUpload": "Enviar relatórios de erro", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Enviar relatórios de erros e registos anónimos", + "@errorReportUploadDetails": {}, + "expiryDate": "Data de Validade", + "@expiryDate": {}, + "expiryExpired": "Expirado", + "@expiryExpired": {}, + "expiryStale": "Inativo", + "@expiryStale": {}, + "extraLineItem": "Adicionar Linha de Artigos Extra", + "@extraLineItem": {}, + "extraLineItems": "Adicionar Linhas de Artigos Extra", + "@extraLineItems": {}, + "feedback": "Comentários", + "@feedback": {}, + "feedbackError": "Erro ao enviar comentário", + "@feedbackError": {}, + "feedbackSuccess": "Comentário enviado", + "@feedbackSuccess": {}, + "filterActive": "Ativo", + "@filterActive": {}, + "filterActiveDetail": "Mostrar partes ativas", + "@filterActiveDetail": {}, + "filterAssembly": "Montado", + "@filterAssembly": {}, + "filterAssemblyDetail": "Mostrar partes montadas", + "@filterAssemblyDetail": {}, + "filterComponent": "Componente", + "@filterComponent": {}, + "filterComponentDetail": "Exibir partes do componente", + "@filterComponentDetail": {}, + "filterExternal": "Externo", + "@filterExternal": {}, + "filterExternalDetail": "Mostrar estoque em locais externos", + "@filterExternalDetail": {}, + "filterInStock": "Em Estoque", + "@filterInStock": {}, + "filterInStockDetail": "Mostrar peças que têm estoque", + "@filterInStockDetail": {}, + "filterSerialized": "Serializado", + "@filterSerialized": {}, + "filterSerializedDetail": "Mostrar itens de estoque serializados", + "@filterSerializedDetail": {}, + "filterTemplate": "Modelo", + "@filterTemplate": {}, + "filterTemplateDetail": "Mostrar partes do modelo", + "@filterTemplateDetail": {}, + "filterTrackable": "Rastreável", + "@filterTrackable": {}, + "filterTrackableDetail": "Mostrar partes rastreáveis", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Mostrar peças virtuais", + "@filterVirtualDetail": {}, + "filteringOptions": "Opções de filtro", + "@filteringOptions": {}, + "formatException": "Formatar erro", + "@formatException": {}, + "formatExceptionJson": "Erro de formatação de data JSON", + "@formatExceptionJson": {}, + "formError": "Erro de formulário", + "@formError": {}, + "history": "Histórico", + "@history": { + "description": "history" + }, + "home": "Início", + "@home": {}, + "homeScreen": "Ecrã inicial", + "@homeScreen": {}, + "homeScreenSettings": "Definir as configurações da tela inicial", + "@homeScreenSettings": {}, + "homeShowPo": "Mostrar Pedido de Compras", + "@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", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Peças Subscritas", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Mostrar partes subscritas na tela inicial", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Mostrar Fornecedores", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Mostrar botão de fornecedores na tela inicial", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Mostrar Fabricantes", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Mostrar botão de fabricantes na tela inicial", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Mostrar Clientes", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Mostrar botão de clientes na tela inicial", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Erro no envio da imagem", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Imagem enviada", + "@imageUploadSuccess": {}, + "inactive": "Inativo", + "@inactive": {}, + "inactiveCompany": "Esta empresa está marcada como inativa", + "@inactiveCompany": {}, + "inactiveDetail": "Este produto está marcado como inativo", + "@inactiveDetail": {}, + "includeSubcategories": "Incluir Subcategorias", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Mostrar resultados de subcategorias", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Incluir sub-região", + "@includeSublocations": {}, + "includeSublocationsDetail": "Mostrar resultados das sub-regiões", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Detalhes de perfil incompletos", + "@incompleteDetails": {}, + "internalPartNumber": "Número interno do produto", + "@internalPartNumber": {}, + "info": "Informações", + "@info": {}, + "inProduction": "Em Produção", + "@inProduction": {}, + "inProductionDetail": "Este item de estoque está em produção", + "@inProductionDetail": {}, + "internalPart": "Produto Interno", + "@internalPart": {}, + "invalidHost": "Hostname inválido", + "@invalidHost": {}, + "invalidHostDetails": "O hostname fornecido é inválido", + "@invalidHostDetails": {}, + "invalidPart": "Peça Inválida", + "@invalidPart": {}, + "invalidPartCategory": "Categoria de Peças Inválida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Localização de Estoque Inválida", + "@invalidStockLocation": {}, + "invalidStockItem": "Artigo de Estoque Inválido", + "@invalidStockItem": {}, + "invalidSupplierPart": "Peça de fornecedor inválida", + "@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", + "@issueDate": {}, + "issueOrder": "Emitir encomenda", + "@issueOrder": {}, + "itemInLocation": "O artigo já está no local", + "@itemInLocation": {}, + "itemDeleted": "O artigo foi removido", + "@itemDeleted": {}, + "itemUpdated": "O artigo foi atualizado", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Modelo de Etiqueta", + "@labelTemplate": {}, + "labelSelectTemplate": "Selecione o modelo de etiqueta", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Selecionar impressora de etiqueta", + "@labelSelectPrinter": {}, + "language": "Idioma", + "@language": {}, + "languageDefault": "Idioma de sistema predefinido", + "@languageDefault": {}, + "languageSelect": "Selecionar Idioma", + "@languageSelect": {}, + "lastStocktake": "Último Balanço de Estoque", + "@lastStocktake": {}, + "lastUpdated": "Ultima atualização", + "@lastUpdated": {}, + "level": "Nível", + "@level": {}, + "lineItemAdd": "Adicionar linha", + "@lineItemAdd": {}, + "lineItem": "Linha", + "@lineItem": {}, + "lineItems": "Itens de linha", + "@lineItems": {}, + "lineItemUpdated": "Linha atualizada", + "@lineItemUpdated": {}, + "locateItem": "Locate stock item", + "@locateItem": {}, + "locateLocation": "Locate stock location", + "@locateLocation": {}, + "locationCreate": "New Location", + "@locationCreate": {}, + "locationCreateDetail": "Create new stock location", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "No location specified", + "@locationNotSet": {}, + "locationUpdated": "Stock location updated", + "@locationUpdated": {}, + "login": "Entrar", + "@login": {}, + "loginEnter": "Introduza os seus credenciais", + "@loginEnter": {}, + "loginEnterDetails": "Nome de utilizador e palavra-passe não são armazenados localmente", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Perdido", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Número da Peça do Fabricante", + "@manufacturerPartNumber": {}, + "manufacturer": "Fabricante", + "@manufacturer": {}, + "manufacturers": "Fabricantes", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": "Sistema", + "@orientationSystem": {}, + "outstanding": "Pendente", + "@outstanding": {}, + "outstandingOrderDetail": "Mostrar pedidos pendentes", + "@outstandingOrderDetail": {}, + "overdue": "Em atraso", + "@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": "Categoria Principal", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": "Categorias de Peça", + "@partCategories": {}, + "partDetails": "Detalhes da Peça", + "@partDetails": {}, + "partNotes": "Notas da Peça", + "@partNotes": {}, + "partStock": "Estoque da Peça", + "@partStock": { + "description": "part stock" + }, + "password": "Palavra-passe", + "@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", + "@permissionRequired": {}, + "phone": "Telefone", + "@phone": {}, + "printLabel": "Imprimir Etiqueta", + "@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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..2753c0c --- /dev/null +++ b/lib/l10n/ro_RO/app_ro_RO.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "ro", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "OK", + "@ok": { + "description": "OK" + }, + "about": "Despre", + "@about": {}, + "accountDetails": "Detalii Cont", + "@accountDetails": {}, + "actions": "Acțiuni", + "@actions": { + "description": "" + }, + "actionsNone": "Acțiuni indisponibile", + "@actionsNone": {}, + "add": "Adaugă", + "@add": { + "description": "add" + }, + "addStock": "Adaugă Stoc", + "@addStock": { + "description": "add stock" + }, + "address": "Adresă", + "@address": {}, + "appAbout": "Despre InvenTree", + "@appAbout": {}, + "appCredits": "Credite Adiționale", + "@appCredits": {}, + "appDetails": "Detalii Aplicație", + "@appDetails": {}, + "allocated": "Alocat", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Pătrat (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Alocare Stoc", + "@allocateStock": {}, + "allocatedStock": "Stocuri alocate", + "@allocatedStock": {}, + "appReleaseNotes": "Afișează notele de lansare a aplicației", + "@appReleaseNotes": {}, + "appSettings": "Setări Aplicație", + "@appSettings": {}, + "appSettingsDetails": "Configurare setări aplicație InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Alocate mie", + "@assignedToMe": {}, + "assignedToMeDetail": "Arată comenzile care îmi sunt atribuite", + "@assignedToMeDetail": {}, + "attachments": "Atașamente", + "@attachments": {}, + "attachImage": "Atașare imagine", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nici un atașament găsit", + "@attachmentNone": {}, + "attachmentNoneDetail": "Nici un atașament găsit", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Selectare atașament", + "@attachmentSelect": {}, + "attention": "Atenție", + "@attention": {}, + "available": "Disponibil", + "@available": {}, + "availableStock": "Stoc disponibil", + "@availableStock": {}, + "barcodes": "Coduri de bare", + "@barcodes": {}, + "barcodeSettings": "Setări cod de bare", + "@barcodeSettings": {}, + "barcodeAssign": "Atribuie codul de bare", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scanează si atribuie cod de bare custom", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Cod de bare atribuit", + "@barcodeAssigned": {}, + "barcodeError": "Eroare scanare cod de bare", + "@barcodeError": {}, + "barcodeInUse": "Cod de bare deja atribuit", + "@barcodeInUse": {}, + "barcodeMissingHash": "Datele hash din codul de bare lipsesc din răspuns", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Cod de bare negăsit", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Cod de bare neatribuit", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Scanează cod de bare piesa", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scanează codul de bare pentru a primi piesa", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Scanare cod de bare întreruptă", + "@barodeScanPaused": {}, + "barcodeScanPause": "Atingeți pentru a întrerupe scanarea", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Scanează pentru a atribui cod de bare", + "@barcodeScanAssign": {}, + "barcodeScanController": "Input Scanner", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Selectați sursa de introducere a codului de bare", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Scanare cod de bare - Pauza", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Pauza intre scanarea codurilor de bare", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Scanează un cod de bare InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Scanează si Introdu stoc in locație", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Scanează locație stoc", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Mod Scanare simplă", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Întrerupeți scanerul de coduri de bare după fiecare scanare", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Introdus In locație", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Element neintrodus", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Scanare articol stoc", + "@barcodeScanItem": {}, + "barcodeTones": "Sunet Scanner cod Bare", + "@barcodeTones": {}, + "barcodeUnassign": "Designează codul de bare", + "@barcodeUnassign": {}, + "barcodeUnknown": "Codul de bare nu este recunoscut", + "@barcodeUnknown": {}, + "batchCode": "Cod lot", + "@batchCode": {}, + "billOfMaterials": "Listă de materiale", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Afișează lista de materiale", + "@bomEnable": {}, + "build": "Asamblare", + "@build": {}, + "building": "Asamblează", + "@building": {}, + "cameraCreationError": "Nu s-a putut deschide controler-ul camerei", + "@cameraCreationError": {}, + "cameraInternal": "Cameră internă", + "@cameraInternal": {}, + "cameraInternalDetail": "Folosește camera internă pentru a citi codurile de bare", + "@cameraInternalDetail": {}, + "cancel": "Anulare", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Anulează comanda", + "@cancelOrder": {}, + "category": "Categorie", + "@category": {}, + "categoryCreate": "Categorie nouă", + "@categoryCreate": {}, + "categoryCreateDetail": "Creare categorie nouă de piese", + "@categoryCreateDetail": {}, + "categoryUpdated": "Categorie piesa actualizată", + "@categoryUpdated": {}, + "company": "Companie", + "@company": {}, + "companyAdd": "Adăugare companie", + "@companyAdd": {}, + "companyEdit": "Editare companie", + "@companyEdit": {}, + "companyNoResults": "Nu există companii ce corespund", + "@companyNoResults": {}, + "companyUpdated": "Detalii companie actualizate", + "@companyUpdated": {}, + "companies": "Companii", + "@companies": {}, + "complete": "Finalizare", + "@complete": {}, + "completeOrder": "Comandă completă", + "@completeOrder": {}, + "completionDate": "Data completării", + "@completionDate": {}, + "configureServer": "Configurare setări server", + "@configureServer": {}, + "confirmScan": "Confirmă transferul", + "@confirmScan": {}, + "confirmScanDetail": "Confirmă detaliile transferului de stoc la scanarea codurilor de bare", + "@confirmScanDetail": {}, + "connectionRefused": "Conexiune refuzată", + "@connectionRefused": {}, + "count": "Număr", + "@count": { + "description": "Count" + }, + "countStock": "Numără Stoc", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credite", + "@credits": {}, + "crop": "Decupați", + "@crop": {}, + "cropImage": "Decupare imagine", + "@cropImage": {}, + "customer": "Client", + "@customer": {}, + "customers": "Clienți", + "@customers": {}, + "customerReference": "Referință client", + "@customerReference": {}, + "damaged": "Deteriorat", + "@damaged": {}, + "colorScheme": "Paletă de culori", + "@colorScheme": {}, + "colorSchemeDetail": "Selectează schema de culori", + "@colorSchemeDetail": {}, + "darkMode": "Mod Întunecat", + "@darkMode": {}, + "darkModeEnable": "Activează modul întunecat", + "@darkModeEnable": {}, + "delete": "Șterge", + "@delete": {}, + "deleteFailed": "Operațiune de ștergere eșuată", + "@deleteFailed": {}, + "deleteImageConfirmation": "Sunteți sigur că doriți să ștergeți această imagine?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Șterge imaginea", + "@deleteImageTooltip": {}, + "deleteImage": "Șterge imaginea", + "@deleteImage": {}, + "deletePart": "Șterge Piesa", + "@deletePart": {}, + "deletePartDetail": "Elimină această piesă din baza de date", + "@deletePartDetail": {}, + "deleteSuccess": "Operație de ștergere reușită", + "@deleteSuccess": {}, + "deliveryDate": "Data livrării", + "@deliveryDate": {}, + "description": "Descriere", + "@description": {}, + "destination": "Destinație", + "@destination": {}, + "destroyed": "Distrus", + "@destroyed": {}, + "details": "Detalii", + "@details": { + "description": "details" + }, + "documentation": "Documentație", + "@documentation": {}, + "downloadComplete": "Descărcare completă", + "@downloadComplete": {}, + "downloadError": "Eroare la descărcarea imaginii", + "@downloadError": {}, + "downloading": "Se descarcă fișierul", + "@downloading": {}, + "edit": "Editare", + "@edit": { + "description": "edit" + }, + "editAttachment": "Editare Anexă", + "@editAttachment": {}, + "editCategory": "Editează Categoria", + "@editCategory": {}, + "editLocation": "Editare locație", + "@editLocation": {}, + "editNotes": "Editează notițele", + "@editNotes": {}, + "editParameter": "Editare Parametru", + "@editParameter": {}, + "editPart": "Editează piesa", + "@editPart": { + "description": "edit part" + }, + "editItem": "Editează Element Stoc", + "@editItem": {}, + "editLineItem": "Editare element rând", + "@editLineItem": {}, + "email": "E-mail", + "@email": {}, + "enterPassword": "Introdu parola", + "@enterPassword": {}, + "enterUsername": "Introdu numele de utilizator", + "@enterUsername": {}, + "error": "Eroare", + "@error": { + "description": "Error" + }, + "errorCreate": "Eroare la crearea intrării in baza de date", + "@errorCreate": {}, + "errorDelete": "Eroare la ștergerea intrării in baza de date", + "@errorDelete": {}, + "errorDetails": "Detalii eroare", + "@errorDetails": {}, + "errorFetch": "Eroare la preluarea datelor de pe server", + "@errorFetch": {}, + "errorUserRoles": "Eroare la solicitarea rolurilor utilizatorilor de pe server", + "@errorUserRoles": {}, + "errorPluginInfo": "Eroare la solicitarea datelor plugin de pe server", + "@errorPluginInfo": {}, + "errorReporting": "Eroare la raportare", + "@errorReporting": {}, + "errorReportUpload": "Încarcă rapoarte de eroare", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Încarcă rapoarte anonime de erori și jurnale de eroare", + "@errorReportUploadDetails": {}, + "expiryDate": "Data expirării", + "@expiryDate": {}, + "expiryExpired": "Expirat", + "@expiryExpired": {}, + "expiryStale": "", + "@expiryStale": {}, + "extraLineItem": "Elemente suplimentare", + "@extraLineItem": {}, + "extraLineItems": "Elemente suplimentare", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Eroare la trimiterea feedback-ului", + "@feedbackError": {}, + "feedbackSuccess": "Feedback Submis", + "@feedbackSuccess": {}, + "filterActive": "Activ", + "@filterActive": {}, + "filterActiveDetail": "Arată piesele active", + "@filterActiveDetail": {}, + "filterAssembly": "Asamblate", + "@filterAssembly": {}, + "filterAssemblyDetail": "Arată piesele asamblate", + "@filterAssemblyDetail": {}, + "filterComponent": "Componenta", + "@filterComponent": {}, + "filterComponentDetail": "Afișare părți componente", + "@filterComponentDetail": {}, + "filterExternal": "Extern", + "@filterExternal": {}, + "filterExternalDetail": "Afișare stoc în locații externe", + "@filterExternalDetail": {}, + "filterInStock": "În Stoc", + "@filterInStock": {}, + "filterInStockDetail": "Arată piesele care au stoc", + "@filterInStockDetail": {}, + "filterSerialized": "Serializat", + "@filterSerialized": {}, + "filterSerializedDetail": "Arată elementele serializate din stoc", + "@filterSerializedDetail": {}, + "filterTemplate": "Șablon", + "@filterTemplate": {}, + "filterTemplateDetail": "Afișare piese șablon", + "@filterTemplateDetail": {}, + "filterTrackable": "Urmăribil", + "@filterTrackable": {}, + "filterTrackableDetail": "Arată piesele urmaribile", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtual", + "@filterVirtual": {}, + "filterVirtualDetail": "Arată piesele virtuale", + "@filterVirtualDetail": {}, + "filteringOptions": "Opțiuni filtrare", + "@filteringOptions": {}, + "formatException": "Excepție format", + "@formatException": {}, + "formatExceptionJson": "Excepție format JSON", + "@formatExceptionJson": {}, + "formError": "Eroare Formular", + "@formError": {}, + "history": "Istoric", + "@history": { + "description": "history" + }, + "home": "Acasă", + "@home": {}, + "homeScreen": "Ecran principal", + "@homeScreen": {}, + "homeScreenSettings": "Configurați setările ecranului principal", + "@homeScreenSettings": {}, + "homeShowPo": "Arată Comenzile de Achiziție", + "@homeShowPo": {}, + "homeShowPoDescription": "Afișați butonul de achiziții pe ecranul principal", + "@homeShowPoDescription": {}, + "homeShowShipments": "Afișare livrări", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Arată transporturile în așteptare pe ecranul principal", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Arată Comenzile de Vânzări", + "@homeShowSo": {}, + "homeShowSoDescription": "Afișare buton vânzări pe ecranul principal", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Piese Abonate", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Afișează piesele abonate pe ecranul principal", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Afișează Furnizorii", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Arată butonul furnizorilor pe ecranul principal", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Afișare producători", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Arată butonul producători pe ecranul principal", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Afișare Clienți", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Arată butonul Clienților pe ecranul principal", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Încărcarea imaginii a eșuat", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Imagine încărcată", + "@imageUploadSuccess": {}, + "inactive": "Inactiv", + "@inactive": {}, + "inactiveCompany": "Această companie este marcată ca inactivă", + "@inactiveCompany": {}, + "inactiveDetail": "Aceasta piesa este marcata ca inactiva", + "@inactiveDetail": {}, + "includeSubcategories": "Include subcategoriile", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Arată rezultatele din subcategorii", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Include Sublocatii", + "@includeSublocations": {}, + "includeSublocationsDetail": "Afișare rezultate din sublocații", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Detalii de profil incomplete", + "@incompleteDetails": {}, + "internalPartNumber": "Cod piesa intern", + "@internalPartNumber": {}, + "info": "Info", + "@info": {}, + "inProduction": "În Producţie", + "@inProduction": {}, + "inProductionDetail": "Acest articol din stoc este în producție", + "@inProductionDetail": {}, + "internalPart": "Articol intern", + "@internalPart": {}, + "invalidHost": "Hostname invalid", + "@invalidHost": {}, + "invalidHostDetails": "Hostname-ul furnizat este invalid", + "@invalidHostDetails": {}, + "invalidPart": "Piesa Invalida", + "@invalidPart": {}, + "invalidPartCategory": "Categorie Piesa Invalida", + "@invalidPartCategory": {}, + "invalidStockLocation": "Locație de stoc invalidă", + "@invalidStockLocation": {}, + "invalidStockItem": "Articol de stoc invalid", + "@invalidStockItem": {}, + "invalidSupplierPart": "Articol Furnizor Invalid", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Combinație de nume utilizator / parolă invalida", + "@invalidUsernamePassword": {}, + "invoice": "Factură", + "@invoice": {}, + "invoiceNumber": "Număr factură", + "@invoiceNumber": {}, + "issue": "Problemă", + "@issue": {}, + "issueDate": "Data emiterii", + "@issueDate": {}, + "issueOrder": "Emite", + "@issueOrder": {}, + "itemInLocation": "Articol deja in locație", + "@itemInLocation": {}, + "itemDeleted": "Articolul a fost eliminat", + "@itemDeleted": {}, + "itemUpdated": "Obiect updatat", + "@itemUpdated": {}, + "keywords": "Cuvinte cheie", + "@keywords": {}, + "labelDriver": "Etichetează șofer", + "@labelDriver": {}, + "labelSelectDriver": "Selectați șofer de imprimante etichetă", + "@labelSelectDriver": {}, + "labelPrinting": "Printare etichete", + "@labelPrinting": {}, + "labelPrintingDetail": "Permite tipărirea etichetei", + "@labelPrintingDetail": {}, + "labelTemplate": "Sablon eticheta", + "@labelTemplate": {}, + "labelSelectTemplate": "Selectați șablon de etichetă", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Selectați imprimanta de etichete", + "@labelSelectPrinter": {}, + "language": "Limba", + "@language": {}, + "languageDefault": "Limba de sistem implicită", + "@languageDefault": {}, + "languageSelect": "Selectează limba", + "@languageSelect": {}, + "lastStocktake": "Ultima verificare de inventar", + "@lastStocktake": {}, + "lastUpdated": "Ultima actualizare", + "@lastUpdated": {}, + "level": "Nivel", + "@level": {}, + "lineItemAdd": "Adăugare element rând", + "@lineItemAdd": {}, + "lineItem": "Articol Linie", + "@lineItem": {}, + "lineItems": "Articole linie", + "@lineItems": {}, + "lineItemUpdated": "Articol linie actualizat", + "@lineItemUpdated": {}, + "locateItem": "Localizare articol stoc", + "@locateItem": {}, + "locateLocation": "Localizare locație stoc", + "@locateLocation": {}, + "locationCreate": "Locație nouă", + "@locationCreate": {}, + "locationCreateDetail": "Creează o nouă locație de stoc", + "@locationCreateDetail": {}, + "locationDefault": "Locație implicită", + "@locationDefault": {}, + "locationNotSet": "Nici o locaţie specificată", + "@locationNotSet": {}, + "locationUpdated": "Locație stoc actualizată", + "@locationUpdated": {}, + "login": "Autentificare", + "@login": {}, + "loginEnter": "Introduceți detaliile de autentificare", + "@loginEnter": {}, + "loginEnterDetails": "Numele de utilizator și parola nu sunt stocate local", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Pierdut", + "@lost": {}, + "manufacturerPart": "", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Editați piesa producătorului", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Număr Serie Producător", + "@manufacturerPartNumber": {}, + "manufacturer": "Producător", + "@manufacturer": {}, + "manufacturers": "Producători", + "@manufacturers": {}, + "missingData": "Date lipsă", + "@missingData": {}, + "name": "Nume", + "@name": {}, + "no": "Nu", + "@no": {}, + "notApplicable": "Indisponibil", + "@notApplicable": {}, + "notConnected": "Neconectat", + "@notConnected": {}, + "notes": "Notițe", + "@notes": { + "description": "Notes" + }, + "notifications": "Notificări", + "@notifications": {}, + "notificationsEmpty": "Nicio notificare necitită", + "@notificationsEmpty": {}, + "noResponse": "Nici un răspuns de la server", + "@noResponse": {}, + "noResults": "Niciun rezultat", + "@noResults": {}, + "noImageAvailable": "Nici o imagine disponibilă", + "@noImageAvailable": {}, + "noPricingAvailable": "Nu există prețuri disponibile", + "@noPricingAvailable": {}, + "noPricingDataFound": "Nu au fost găsite date despre prețuri pentru această piesă", + "@noPricingDataFound": {}, + "noSubcategories": "Nu există subcategorii", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Nicio subcategorie disponibilă", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Număr invalid", + "@numberInvalid": {}, + "onOrder": "Pe comandă", + "@onOrder": {}, + "onOrderDetails": "Piese în prezent pe comandă", + "@onOrderDetails": {}, + "orientation": "Orientare ecran", + "@orientation": {}, + "orientationDetail": "Orientarea ecranului (necesită repornire)", + "@orientationDetail": {}, + "orientationLandscape": "Orizontală", + "@orientationLandscape": {}, + "orientationPortrait": "Verticală", + "@orientationPortrait": {}, + "orientationSystem": "Sistem", + "@orientationSystem": {}, + "outstanding": "Restant", + "@outstanding": {}, + "outstandingOrderDetail": "Afișează comenzile neîmplinite", + "@outstandingOrderDetail": {}, + "overdue": "Restant", + "@overdue": {}, + "overdueDetail": "Arată comenzile restante", + "@overdueDetail": {}, + "packaging": "Ambalaj", + "@packaging": {}, + "packageName": "Nume Ambalaj", + "@packageName": {}, + "parameters": "Parametri", + "@parameters": {}, + "parametersSettingDetail": "Afișează parametrii piesei", + "@parametersSettingDetail": {}, + "parent": "Părinte", + "@parent": {}, + "parentCategory": "Categorie Părinte", + "@parentCategory": {}, + "parentLocation": "Locație părinte", + "@parentLocation": {}, + "part": "Piesa", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Piesa Noua", + "@partCreate": {}, + "partCreateDetail": "Creează o nouă piesa în această categorie", + "@partCreateDetail": {}, + "partEdited": "Piesa actualizata", + "@partEdited": {}, + "parts": "Piese", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Piesa nemarcata ca fiind vânduta", + "@partNotSalable": {}, + "partsNone": "Nicio Piesa", + "@partsNone": {}, + "partNoResults": "Nicio piesă care se potrivește", + "@partNoResults": {}, + "partPricing": "Preț piesă", + "@partPricing": {}, + "partPricingSettingDetail": "Afișați informații despre preț", + "@pricingSettingDetail": {}, + "partSettings": "Setări Piesa", + "@partSettings": {}, + "partsStarred": "Piese Abonate", + "@partsStarred": {}, + "partsStarredNone": "Nu există piese cu stea disponibile", + "@partsStarredNone": {}, + "partSuppliers": "Furnizori de piese", + "@partSuppliers": {}, + "partCategory": "Categorie Piesă", + "@partCategory": {}, + "partCategoryTopLevel": "Nivelul superior Categorie Piesă", + "@partCategoryTopLevel": {}, + "partCategories": "Categorii Piese", + "@partCategories": {}, + "partDetails": "Detalii piesă", + "@partDetails": {}, + "partNotes": "Notite Piesa", + "@partNotes": {}, + "partStock": "Stoc Piesa", + "@partStock": { + "description": "part stock" + }, + "password": "Parola", + "@password": {}, + "passwordEmpty": "Câmpul pentru Parola nu poate fi gol", + "@passwordEmpty": {}, + "pending": "În așteptare", + "@pending": {}, + "permissionAccountDenied": "Contul dvs. nu are permisiunile necesare pentru a efectua această acțiune", + "@permissionAccountDenied": {}, + "permissionRequired": "Permisiune necesară", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "printLabel": "Printati Eticheta", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Imprimantă", + "@pluginPrinter": {}, + "pluginSupport": "Suport Plugin activat", + "@pluginSupport": {}, + "pluginSupportDetail": "Serverul acceptă plugin-uri personalizate", + "@pluginSupportDetail": {}, + "printLabelFailure": "Printarea etichetei a eșuat", + "@printLabelFailure": {}, + "printLabelSuccess": "Eticheta trimis la imprimanta", + "@printLabelSuccess": {}, + "profile": "Profiluri", + "@profile": {}, + "profileAdd": "Adaugă Profil Server", + "@profileAdd": {}, + "profileConnect": "Conectare la server", + "@profileConnect": {}, + "profileEdit": "Editează Profilul Serverului", + "@profileEdit": {}, + "profileDelete": "Ștergere profil server", + "@profileDelete": {}, + "profileLogout": "Deconectare profil", + "@profileLogout": {}, + "profileName": "Nume profil", + "@profileName": {}, + "profileNone": "Nici un profil disponibil", + "@profileNone": {}, + "profileNotSelected": "Nici un profil selectat", + "@profileNotSelected": {}, + "profileSelect": "Selectați serverul InvenTree", + "@profileSelect": {}, + "profileSelectOrCreate": "Selectează server sau creează un profil nou", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Atingeți pentru a crea sau a selecta un profil", + "@profileTapToCreate": {}, + "projectCode": "Cod proiect", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Confirmați datele scanate", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirmați detaliile la scanarea articolelor", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Activați comenzile de achiziție", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Activează funcționalitatea comenzii de achiziție", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Scurtătura Cameră", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Activează comanda rapidă pentru încărcarea imaginilor pe ecranul comenzii de achiziție", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Comandă de achiziție", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Comandă nouă de achiziție", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Editați comanda de achiziție", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Setări comandă de achiziție", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Comandă de achiziție", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Comandă de achiziție actualizată", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Preț achiziție", + "@purchasePrice": {}, + "quantity": "Cantitate", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Cantitate disponibilă", + "@quantityAvailable": {}, + "quantityEmpty": "Cantitatea este goală", + "@quantityEmpty": {}, + "quantityInvalid": "Cantitate invalida", + "@quantityInvalid": {}, + "quantityPositive": "Cantitatea trebuie să fie pozitivă", + "@quantityPositive": {}, + "queryEmpty": "Introdu text căutat", + "@queryEmpty": {}, + "queryNoResults": "Nici un rezultat pentru cautare", + "@queryNoResults": {}, + "received": "Recepţionat", + "@received": {}, + "receivedFilterDetail": "Afișare articole primite", + "@receivedFilterDetail": {}, + "receiveItem": "Articole primite", + "@receiveItem": {}, + "receivedItem": "Articol primit în stoc", + "@receivedItem": {}, + "reference": "Referinţă", + "@reference": {}, + "refresh": "Actualizare", + "@refresh": {}, + "rotateClockwise": "Rotire la 90° în sens orar", + "@rotateClockwise": {}, + "refreshing": "Actualizare", + "@refreshing": {}, + "rejected": "Respins", + "@rejected": {}, + "releaseNotes": "Informații & versiune", + "@releaseNotes": {}, + "remove": "Șterge", + "@remove": { + "description": "remove" + }, + "removeStock": "Retragere stoc", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Raportează o eroare", + "@reportBug": {}, + "reportBugDescription": "Trimite raportul de eroare (necesită cont GitHub)", + "@reportBugDescription": {}, + "responsible": "Responsabil", + "@responsible": {}, + "results": "Rezultate", + "@results": {}, + "request": "Solicitare", + "@request": {}, + "requestFailed": "Cerere eșuată", + "@requestFailed": {}, + "requestSuccessful": "", + "@requestSuccessful": {}, + "requestingData": "Solicitare date", + "@requestingData": {}, + "required": "Obligatoriu", + "@required": { + "description": "This field is required" + }, + "response400": "Cerere greşită", + "@response400": {}, + "response401": "Neautorizat", + "@response401": {}, + "response403": "Acces interzis", + "@response403": {}, + "response404": "Resursa nu a fost găsită", + "@response404": {}, + "response405": "Metoda nu este permisă", + "@response405": {}, + "response429": "Prea multe solicitări", + "@response429": {}, + "response500": "Eroare internă server", + "@response500": {}, + "response501": "Nu este implementat", + "@response501": {}, + "response502": "Gateway greșit", + "@response502": {}, + "response503": "Serviciu indisponibil", + "@response503": {}, + "response504": "Timeout gateway", + "@response504": {}, + "response505": "Versiunea HTTP nu este suportată", + "@response505": {}, + "responseData": "Date Răspuns", + "@responseData": {}, + "responseInvalid": "Cod de răspuns nevalid", + "@responseInvalid": {}, + "responseUnknown": "Răspuns necunoscut", + "@responseUnknown": {}, + "result": "Rezultat", + "@result": { + "description": "" + }, + "returned": "Returnat", + "@returned": {}, + "salesOrder": "Comenzi de Vânzare", + "@salesOrder": {}, + "salesOrders": "Comenzi de Vânzare", + "@salesOrders": {}, + "salesOrderEnable": "Activează Comenzile de Vânzări", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Activați funcționalitatea comenzilor de vânzare", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Scurtătura Cameră", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Activează scurtătura de încărcare a imaginilor pe ecranul comenzii de vânzare", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Setările comenzii de vânzare", + "@salesOrderSettings": {}, + "salesOrderCreate": "Comandă de vânzări nouă", + "@saleOrderCreate": {}, + "salesOrderEdit": "Editează Comanda de Vânzare", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Comanda de vanzare actualizată", + "@salesOrderUpdated": {}, + "save": "Salvaţi", + "@save": { + "description": "Save" + }, + "scanBarcode": "Scanați codul de bare", + "@scanBarcode": {}, + "scanSupplierPart": "Scanare cod de bare furnizor", + "@scanSupplierPart": {}, + "scanIntoLocation": "Scanare în locație", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scanează acest articol în locație", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Scanner extern", + "@scannerExternal": {}, + "scannerExternalDetail": "Utilizează scanerul extern pentru a citi codurile de bare (modul wedge)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scanați capitolele primite", + "@scanReceivedParts": {}, + "search": "Caută", + "@search": { + "description": "search" + }, + "searching": "Căutare", + "@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", + "@searchStock": {}, + "select": "Selectează", + "@select": {}, + "selectFile": "Selectează fișier", + "@selectFile": {}, + "selectImage": "Selectează imagine", + "@selectImage": {}, + "selectLocation": "Selectați o locație", + "@selectLocation": {}, + "send": "Trimite", + "@send": {}, + "serialNumber": "Număr de serie", + "@serialNumber": {}, + "serialNumbers": "Număr de serie", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Adresă server", + "@serverAddress": {}, + "serverApiRequired": "Versiunea API necesară", + "@serverApiRequired": {}, + "serverApiVersion": "Versiune API server", + "@serverApiVersion": {}, + "serverAuthenticationError": "Eroare autentificare", + "@serverAuthenticationError": {}, + "serverCertificateError": "Cerficate Error", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Certificatul HTTPS al serverului nu este valid", + "@serverCertificateInvalid": {}, + "serverConnected": "Conectare la server", + "@serverConnected": {}, + "serverConnecting": "Se conecteaza la server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Nu s-a putut conecta la server", + "@serverCouldNotConnect": {}, + "serverEmpty": "Serverul nu poate fi gol", + "@serverEmpty": {}, + "serverError": "Eroare de server", + "@serverError": {}, + "serverDetails": "Detalii despre server", + "@serverDetails": {}, + "serverMissingData": "Răspuns server lipsă câmpuri obligatorii", + "@serverMissingData": {}, + "serverOld": "Versiunea veche a serverului", + "@serverOld": {}, + "serverSettings": "Setări server", + "@serverSettings": {}, + "serverStart": "Serverul trebuie să înceapă cu http[s]", + "@serverStart": {}, + "settings": "Setări", + "@settings": {}, + "serverInstance": "Instanță server", + "@serverInstance": {}, + "serverNotConnected": "Serverul nu este conectat", + "@serverNotConnected": {}, + "serverNotSelected": "Serverul nu este selectat", + "@serverNotSelected": {}, + "shipment": "Expediere", + "@shipment": {}, + "shipments": "Livrări", + "@shipments": {}, + "shipmentsPending": "Livrări în așteptare", + "@shipmentsPending": {}, + "shipmentAdd": "Adaugă livrare", + "@shipmentAdd": {}, + "shipmentCheck": "Verifica livrare", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Marchează livrarea ca verificată", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Livrare verificată", + "@shipmentChecked": {}, + "shipmentDate": "Data livrării", + "@shipmentDate": {}, + "shipmentEdit": "Editare livrare", + "@shipmentEdit": {}, + "shipmentReference": "Referință livrare", + "@shipmentReference": {}, + "shipmentSend": "Livrare Trimisa", + "@shipmentSend": {}, + "shipmentUncheck": "Debifează livrare", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Marchează livrarea ca nebifat", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Livrare actualizată", + "@shipmentUpdated": {}, + "shipped": "Livrat", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sunete", + "@sounds": {}, + "soundOnBarcodeAction": "Redă ton sonor la acțiunea codului de bare", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Redă sunetul sonor la eroarea serverului", + "@soundOnServerError": {}, + "startDate": "Data inceput", + "@startDate": {}, + "status": "Status", + "@status": {}, + "statusCode": "Status Code", + "@statusCode": {}, + "stock": "Stoc", + "@stock": { + "description": "stock" + }, + "stockDetails": "Stoc disponibil curent", + "@stockDetails": {}, + "stockItem": "Articol Stoc", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Articol Stoc", + "@stockItems": {}, + "stockItemCreate": "Element nou în stoc", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Crează element nou în stoc în această locație", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Şterge elementul din stoc", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Sunteţi sigur că doriţi să ştergeţi acest articol din stoc?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Nu s-a putut șterge articolul din stoc", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Articol șters", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Istoric Stoc", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Afişează informaţii istorice de urmărire stoc", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Articol stoc transferat", + "@stockItemTransferred": {}, + "stockItemUpdated": "Articol stoc actualizat", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Nu sunt articole disponibile în stoc", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Note element de stoc", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Articol stoc actualizat", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Actualizarea articolului stoc a eșuat", + "@stockItemUpdateFailure": {}, + "stockLocation": "Locația stocului", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Locația stocului", + "@stockLocations": {}, + "stockTopLevel": "Locație stoc nivel superior", + "@stockTopLevel": {}, + "strictHttps": "Folosește HTTPS Strict", + "@strictHttps": {}, + "strictHttpsDetails": "Impune controlul strict al certificatelor HTTP", + "@strictHttpsDetails": {}, + "subcategory": "Subcategorie", + "@subcategory": {}, + "subcategories": "Subcategorii", + "@subcategories": {}, + "sublocation": "Sublocare", + "@sublocation": {}, + "sublocations": "Sublocare", + "@sublocations": {}, + "sublocationNone": "Fără sublocări", + "@sublocationNone": {}, + "sublocationNoneDetail": "Nu există sublocații disponibile", + "@sublocationNoneDetail": {}, + "submitFeedback": "Trimiteți feedback", + "@submitFeedback": {}, + "suppliedParts": "Piese furnizate", + "@suppliedParts": {}, + "supplier": "Furnizor", + "@supplier": {}, + "supplierPart": "Piesă Furnizor", + "@supplierPart": {}, + "supplierPartEdit": "Editați articol furnizorului", + "@supplierPartEdit": {}, + "supplierPartNumber": "Cod furnizor", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Cod furnizor actualizat", + "@supplierPartUpdated": {}, + "supplierParts": "Piese Furnizor", + "@supplierParts": {}, + "suppliers": "Furnizori", + "@suppliers": {}, + "supplierReference": "Cod furnizor", + "@supplierReference": {}, + "switchCamera": "Comutați Camera", + "@switchCamera": {}, + "takePicture": "Faceți o fotografie", + "@takePicture": {}, + "targetDate": "Data țintă", + "@targetDate": {}, + "templatePart": "Capitol șablon părinte", + "@templatePart": {}, + "testName": "Nume test", + "@testName": {}, + "testPassedOrFailed": "Testul a trecut sau a eșuat", + "@testPassedOrFailed": {}, + "testsRequired": "Teste necesare", + "@testsRequired": {}, + "testResults": "Rezultatele testului", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Afișează rezultatele testului produsului în stoc", + "@testResultsDetail": {}, + "testResultAdd": "Adăugare rezultat test", + "@testResultAdd": {}, + "testResultNone": "Niciun rezultat de test", + "@testResultNone": {}, + "testResultNoneDetail": "Nici un rezultat de test disponibil", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Eroare încărcare rezultat test", + "@testResultUploadFail": {}, + "testResultUploadPass": "Rezultat test încărcat", + "@testResultUploadPass": {}, + "timeout": "Timeout", + "@timeout": { + "description": "" + }, + "toggleTorch": "Comutare lanternă", + "@toggleTorch": {}, + "tokenError": "Eroare token", + "@tokenError": {}, + "tokenMissing": "Token lipsă", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Token-ul de acces lipsește din răspuns", + "@tokenMissingFromResponse": {}, + "totalPrice": "Preț total", + "@totalPrice": {}, + "trackingNumber": "Număr de urmărire", + "@trackingNumber": {}, + "transfer": "Transfer", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Transfera stoc", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Transferați articolul într-o locație diferită", + "@transferStockDetail": {}, + "transferStockLocation": "Transfer locație stoc", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Transferați această locație a stocului în alta", + "@transferStockLocationDetail": {}, + "translate": "Traduceți", + "@translate": {}, + "translateHelp": "Ajută la traducerea aplicației InvenTree", + "@translateHelp": {}, + "unavailable": "Indisponibil", + "@unavailable": {}, + "unavailableDetail": "Articolul nu este disponibil", + "@unavailableDetail": {}, + "unitPrice": "Preţ Unitar", + "@unitPrice": {}, + "units": "Unități", + "@units": {}, + "unknownResponse": "Răspuns necunoscut", + "@unknownResponse": {}, + "upload": "Încărcaţi", + "@upload": {}, + "uploadFailed": "Încărcare fișier eșuată", + "@uploadFailed": {}, + "uploadSuccess": "Fişier încărcat", + "@uploadSuccess": {}, + "uploadImage": "Încărcare imagine", + "@uploadImage": {}, + "usedIn": "Folosite în", + "@usedIn": {}, + "usedInDetails": "Ansambluri care necesită aceast articol", + "@usedInDetails": {}, + "username": "Nume utilizator", + "@username": {}, + "usernameEmpty": "Numele de utilizator nu poate fi gol", + "@usernameEmpty": {}, + "value": "Valoare", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Valoarea nu poate fi goală", + "@valueCannotBeEmpty": {}, + "valueRequired": "Valoarea este obligatorie", + "@valueRequired": {}, + "variants": "Variante", + "@variants": {}, + "version": "Verisune", + "@version": {}, + "viewSupplierPart": "Vezi capitol furnizor", + "@viewSupplierPart": {}, + "website": "Website", + "@website": {}, + "yes": "Da", + "@yes": {}, + "price": "Preț", + "@price": {}, + "priceRange": "Interval de preț", + "@priceRange": {}, + "priceOverrideMin": "Suprascriere Preț Minim", + "@priceOverrideMin": {}, + "priceOverrideMax": "Suprascriere de preț maximă", + "@priceOverrideMax": {}, + "salePrice": "Preț de vânzare", + "@salePrice": {}, + "saleHistory": "Istoric vanzari", + "@saleHistory": {}, + "supplierPricing": "Prețurile furnizorului", + "@supplierPricing": {}, + "bomCost": "Cost BOM", + "@bomCost": {}, + "internalCost": "Cost intern", + "@internalCost": {}, + "variantCost": "Cost variantă", + "@variantCost": {}, + "overallPricing": "Preț general", + "@overallPricing": {}, + "pricingOverrides": "Suprascrieri preturi", + "@pricingOverrides": {}, + "currency": "Monedă", + "@currency": {}, + "priceBreaks": "Reduceri de preț", + "@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 new file mode 100644 index 0000000..b22d092 --- /dev/null +++ b/lib/l10n/ru_RU/app_ru_RU.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "Выделено", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Квадрат (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Выделить запас", + "@allocateStock": {}, + "allocatedStock": "Зарезервированные остатки", + "@allocatedStock": {}, + "appReleaseNotes": "Показать заметки о выпуске приложения", + "@appReleaseNotes": {}, + "appSettings": "Настройки приложения", + "@appSettings": {}, + "appSettingsDetails": "Изменить настройки приложения InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Назначенные мне", + "@assignedToMe": {}, + "assignedToMeDetail": "Показать заказы, назначенные мне", + "@assignedToMeDetail": {}, + "attachments": "Вложения", + "@attachments": {}, + "attachImage": "Прикрепить изображение", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Вложений не найдено", + "@attachmentNone": {}, + "attachmentNoneDetail": "Вложений не найдено", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Выбрать вложение", + "@attachmentSelect": {}, + "attention": "Внимание", + "@attention": {}, + "available": "Доступно", + "@available": {}, + "availableStock": "Доступный запас", + "@availableStock": {}, + "barcodes": "Штрих-коды", + "@barcodes": {}, + "barcodeSettings": "Настройки штрих-кодов", + "@barcodeSettings": {}, + "barcodeAssign": "Назначить штрих-код", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Просканировать пользовательский штрих-код для назначения", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Штрих-код назначен", + "@barcodeAssigned": {}, + "barcodeError": "Ошибка сканирования штрих-кода", + "@barcodeError": {}, + "barcodeInUse": "Штрих-код уже назначен", + "@barcodeInUse": {}, + "barcodeMissingHash": "Данные хэша штрих-кода отсутствуют в ответе", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Нет совпадений для штрих-кода", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Штрих-код не назначен", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Сканировать штрих-код", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Отсканируйте штрих-код для получения детали", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Сканирование штрих-кода приостановлено", + "@barodeScanPaused": {}, + "barcodeScanPause": "Нажмите, чтобы приостановить сканирование", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Сканировать для присвоения штрих-кода", + "@barcodeScanAssign": {}, + "barcodeScanController": "Источник сканера", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Выберите источник сканера штрих-кода", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Задержка сканирования штрих-кода", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Задержка между сканированием штрих-кодов", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Сканировать штрих-код InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Сканировать товары на складе в это место", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Сканировать местоположение склада", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Режим одиночного сканирования", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Приостановить сканер штрих-кода после каждого сканирования", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Сканирование на место", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Элемент не просканирован в", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Сканировать складскую позицию", + "@barcodeScanItem": {}, + "barcodeTones": "Сигналы штрих-кода", + "@barcodeTones": {}, + "barcodeUnassign": "Отменить назначение штрих-кода", + "@barcodeUnassign": {}, + "barcodeUnknown": "Штрих-код не распознан", + "@barcodeUnknown": {}, + "batchCode": "Код партии", + "@batchCode": {}, + "billOfMaterials": "Спецификации материалов", + "@billOfMaterials": {}, + "bom": "Спецификация", + "@bom": {}, + "bomEnable": "Отображать спецификации материалов", + "@bomEnable": {}, + "build": "Сборка", + "@build": {}, + "building": "Построение", + "@building": {}, + "cameraCreationError": "Не удалось открыть контроллер камеры", + "@cameraCreationError": {}, + "cameraInternal": "Внутренняя камера", + "@cameraInternal": {}, + "cameraInternalDetail": "Использовать внутреннюю камеру для чтения штрих-кодов", + "@cameraInternalDetail": {}, + "cancel": "Отменить", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Отменить заказ", + "@cancelOrder": {}, + "category": "Категория", + "@category": {}, + "categoryCreate": "Новая категория", + "@categoryCreate": {}, + "categoryCreateDetail": "Создать новую категорию деталей", + "@categoryCreateDetail": {}, + "categoryUpdated": "Категория деталей обновлена", + "@categoryUpdated": {}, + "company": "Компания", + "@company": {}, + "companyAdd": "Добавить компанию", + "@companyAdd": {}, + "companyEdit": "Редактировать компанию", + "@companyEdit": {}, + "companyNoResults": "Нет организаций, соответствующих запросу", + "@companyNoResults": {}, + "companyUpdated": "Информация о компании обновлена", + "@companyUpdated": {}, + "companies": "Компании", + "@companies": {}, + "complete": "Завершить", + "@complete": {}, + "completeOrder": "Завершить заказ", + "@completeOrder": {}, + "completionDate": "Дата завершения", + "@completionDate": {}, + "configureServer": "Изменить параметры сервера", + "@configureServer": {}, + "confirmScan": "Подтвердить перенос", + "@confirmScan": {}, + "confirmScanDetail": "Подтвердите детали перевода по складу при сканировании штрих-кодов", + "@confirmScanDetail": {}, + "connectionRefused": "Отказано в подключении", + "@connectionRefused": {}, + "count": "Количество", + "@count": { + "description": "Count" + }, + "countStock": "Количество в наличии", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Авторы", + "@credits": {}, + "crop": "Обрезать", + "@crop": {}, + "cropImage": "Обрезать изображение", + "@cropImage": {}, + "customer": "Клиент", + "@customer": {}, + "customers": "Покупатели", + "@customers": {}, + "customerReference": "Артикул клиента", + "@customerReference": {}, + "damaged": "Поврежденный", + "@damaged": {}, + "colorScheme": "Цветовая схема", + "@colorScheme": {}, + "colorSchemeDetail": "Выберите цветовую схему", + "@colorSchemeDetail": {}, + "darkMode": "Тёмная тема", + "@darkMode": {}, + "darkModeEnable": "Включить тёмную тему", + "@darkModeEnable": {}, + "delete": "Удалить", + "@delete": {}, + "deleteFailed": "Ошибка удаления", + "@deleteFailed": {}, + "deleteImageConfirmation": "Вы уверены, что хотите удалить изображение?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Удалить изображение", + "@deleteImageTooltip": {}, + "deleteImage": "Удалить изображение", + "@deleteImage": {}, + "deletePart": "Удалить деталь", + "@deletePart": {}, + "deletePartDetail": "Удалить эту деталь из базы данных", + "@deletePartDetail": {}, + "deleteSuccess": "Удаление успешно завершено", + "@deleteSuccess": {}, + "deliveryDate": "Дата доставки", + "@deliveryDate": {}, + "description": "Описание", + "@description": {}, + "destination": "Назначение", + "@destination": {}, + "destroyed": "Разрушено", + "@destroyed": {}, + "details": "Подробности", + "@details": { + "description": "details" + }, + "documentation": "Документация", + "@documentation": {}, + "downloadComplete": "Загрузка завершена", + "@downloadComplete": {}, + "downloadError": "Ошибка загрузки изображения", + "@downloadError": {}, + "downloading": "Загрузка файла", + "@downloading": {}, + "edit": "Изменить", + "@edit": { + "description": "edit" + }, + "editAttachment": "Редактировать вложение", + "@editAttachment": {}, + "editCategory": "Редактировать категорию", + "@editCategory": {}, + "editLocation": "Редактировать местонахождение", + "@editLocation": {}, + "editNotes": "Редактировать примечания", + "@editNotes": {}, + "editParameter": "Редактировать параметр", + "@editParameter": {}, + "editPart": "Редактировать деталь", + "@editPart": { + "description": "edit part" + }, + "editItem": "Складская позиция", + "@editItem": {}, + "editLineItem": "Изменить позицию", + "@editLineItem": {}, + "email": "Электронная почта", + "@email": {}, + "enterPassword": "Введите пароль", + "@enterPassword": {}, + "enterUsername": "Введите имя пользователя", + "@enterUsername": {}, + "error": "Ошибка", + "@error": { + "description": "Error" + }, + "errorCreate": "Ошибка создания записи базы данных", + "@errorCreate": {}, + "errorDelete": "Ошибка удаления записи базы данных", + "@errorDelete": {}, + "errorDetails": "Подробнее об ошибке", + "@errorDetails": {}, + "errorFetch": "Ошибка при получении данных с сервера", + "@errorFetch": {}, + "errorUserRoles": "Ошибка запроса ролей пользователя с сервера", + "@errorUserRoles": {}, + "errorPluginInfo": "Ошибка при получении данных плагина с сервера", + "@errorPluginInfo": {}, + "errorReporting": "Уведомление об ошибках", + "@errorReporting": {}, + "errorReportUpload": "Отправка отчётов об ошибках", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Загружать анонимные отчеты об ошибках и журналы сбоев", + "@errorReportUploadDetails": {}, + "expiryDate": "Срок годности", + "@expiryDate": {}, + "expiryExpired": "Просрочен", + "@expiryExpired": {}, + "expiryStale": "Устаревшие", + "@expiryStale": {}, + "extraLineItem": "Дополнительные позиции", + "@extraLineItem": {}, + "extraLineItems": "Дополнительные позиции", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "Показать номерные позиции на складе", + "@filterSerializedDetail": {}, + "filterTemplate": "Шаблон", + "@filterTemplate": {}, + "filterTemplateDetail": "Показать шаблоны компонентов", + "@filterTemplateDetail": {}, + "filterTrackable": "Отслеживаемый", + "@filterTrackable": {}, + "filterTrackableDetail": "Показать отслеживаемые компоненты", + "@filterTrackableDetail": {}, + "filterVirtual": "Виртуальный", + "@filterVirtual": {}, + "filterVirtualDetail": "Показать виртуальные компоненты", + "@filterVirtualDetail": {}, + "filteringOptions": "Настройки фильтрации", + "@filteringOptions": {}, + "formatException": "Формат исключения", + "@formatException": {}, + "formatExceptionJson": "Ошибка формата JSON", + "@formatExceptionJson": {}, + "formError": "Ошибка в форме", + "@formError": {}, + "history": "История", + "@history": { + "description": "history" + }, + "home": "Главная", + "@home": {}, + "homeScreen": "Начальный экран", + "@homeScreen": {}, + "homeScreenSettings": "Настройка главной страницы", + "@homeScreenSettings": {}, + "homeShowPo": "Показать заказы на поставку", + "@homeShowPo": {}, + "homeShowPoDescription": "Показывать кнопку заказа на главном экране", + "@homeShowPoDescription": {}, + "homeShowShipments": "Показать отгрузки", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Показывать ожидающие отгрузки на главном экране", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Показать заказы на продажу", + "@homeShowSo": {}, + "homeShowSoDescription": "Показывать кнопку заказов на продажу на главном экране", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Детали с включёнными уведомлениями", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Показывать детали, на которые включены уведомления, на главной странице", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Показать поставщиков", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Отображение кнопки поставщиков на главном экране", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Показать производителей", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Показывать кнопку производителей на главном экране", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Показать заказчиков", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Показывать кнопку покупателя на главном экране", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Не удалось загрузить изображение", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Изображение загружено", + "@imageUploadSuccess": {}, + "inactive": "Неактивный", + "@inactive": {}, + "inactiveCompany": "Эта компания помечена как неактивная", + "@inactiveCompany": {}, + "inactiveDetail": "Эта часть помечена как неактивная", + "@inactiveDetail": {}, + "includeSubcategories": "Включить подкатегории", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Показать результаты из подкатегорий", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Добавить доп. местоположения", + "@includeSublocations": {}, + "includeSublocationsDetail": "Показывать результаты по подпунктам", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Неполные данные профиля", + "@incompleteDetails": {}, + "internalPartNumber": "Внутренний номер", + "@internalPartNumber": {}, + "info": "Информация", + "@info": {}, + "inProduction": "В процессе производства", + "@inProduction": {}, + "inProductionDetail": "Данный объект находится в производстве", + "@inProductionDetail": {}, + "internalPart": "Внутренний компонент", + "@internalPart": {}, + "invalidHost": "Неверное имя хоста", + "@invalidHost": {}, + "invalidHostDetails": "Недопустимый пароль", + "@invalidHostDetails": {}, + "invalidPart": "Недопустимая деталь", + "@invalidPart": {}, + "invalidPartCategory": "Неверная категория детали", + "@invalidPartCategory": {}, + "invalidStockLocation": "Неверное расположение склада", + "@invalidStockLocation": {}, + "invalidStockItem": "Недопустимый товарный пункт", + "@invalidStockItem": {}, + "invalidSupplierPart": "Неверная деталь поставщика", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Неверная комбинация имени пользователя и пароля", + "@invalidUsernamePassword": {}, + "invoice": "Счет", + "@invoice": {}, + "invoiceNumber": "Номер счета", + "@invoiceNumber": {}, + "issue": "Оформить", + "@issue": {}, + "issueDate": "Дата проблемы", + "@issueDate": {}, + "issueOrder": "Оформить заказ", + "@issueOrder": {}, + "itemInLocation": "Элемент уже находится на месте", + "@itemInLocation": {}, + "itemDeleted": "Позиция была удалена", + "@itemDeleted": {}, + "itemUpdated": "Позиция обновлена", + "@itemUpdated": {}, + "keywords": "Ключевые слова", + "@keywords": {}, + "labelDriver": "Драйвер принтера этикеток", + "@labelDriver": {}, + "labelSelectDriver": "Выберите драйвер принтера этикеток", + "@labelSelectDriver": {}, + "labelPrinting": "Печать этикеток", + "@labelPrinting": {}, + "labelPrintingDetail": "Включить печать этикеток", + "@labelPrintingDetail": {}, + "labelTemplate": "Шаблон этикетки", + "@labelTemplate": {}, + "labelSelectTemplate": "Выберите шаблон этикетки", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Выберите принтер этикеток", + "@labelSelectPrinter": {}, + "language": "Язык", + "@language": {}, + "languageDefault": "Язык системы по умолчанию", + "@languageDefault": {}, + "languageSelect": "Выберите язык", + "@languageSelect": {}, + "lastStocktake": "Последняя инвентаризация", + "@lastStocktake": {}, + "lastUpdated": "Последние обновлённые", + "@lastUpdated": {}, + "level": "Уровень", + "@level": {}, + "lineItemAdd": "Добавить позицию", + "@lineItemAdd": {}, + "lineItem": "Элемент строки", + "@lineItem": {}, + "lineItems": "Элементы строки", + "@lineItems": {}, + "lineItemUpdated": "Позиция обновлена", + "@lineItemUpdated": {}, + "locateItem": "Найти деталь на складе", + "@locateItem": {}, + "locateLocation": "Найти местоположение склада", + "@locateLocation": {}, + "locationCreate": "Новое местоположение", + "@locationCreate": {}, + "locationCreateDetail": "Создать новое расположение склада", + "@locationCreateDetail": {}, + "locationDefault": "Расположение по умолчанию", + "@locationDefault": {}, + "locationNotSet": "Не указано месторасположение", + "@locationNotSet": {}, + "locationUpdated": "Расположение склада обновлено", + "@locationUpdated": {}, + "login": "Войти", + "@login": {}, + "loginEnter": "Введите данные для входа", + "@loginEnter": {}, + "loginEnterDetails": "Логин и пароль не хранятся локально", + "@loginEnterDetails": {}, + "link": "Ссылка", + "@link": {}, + "lost": "Потерян", + "@lost": {}, + "manufacturerPart": "Деталь производителя", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Редактировать деталь производителя", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Код производителя", + "@manufacturerPartNumber": {}, + "manufacturer": "Производитель", + "@manufacturer": {}, + "manufacturers": "Производители", + "@manufacturers": {}, + "missingData": "Отсутствующие данные", + "@missingData": {}, + "name": "Название", + "@name": {}, + "no": "Нет", + "@no": {}, + "notApplicable": "Н/Д", + "@notApplicable": {}, + "notConnected": "Соединение не установлено", + "@notConnected": {}, + "notes": "Заметки", + "@notes": { + "description": "Notes" + }, + "notifications": "Уведомления", + "@notifications": {}, + "notificationsEmpty": "Нет непрочитанных уведомлений", + "@notificationsEmpty": {}, + "noResponse": "Нет ответа от сервера", + "@noResponse": {}, + "noResults": "Нет результатов", + "@noResults": {}, + "noImageAvailable": "Нет доступного изображения", + "@noImageAvailable": {}, + "noPricingAvailable": "Нет данных о цене", + "@noPricingAvailable": {}, + "noPricingDataFound": "Для этой детали не найдены данные о ценах", + "@noPricingDataFound": {}, + "noSubcategories": "Нет подкатегории", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Нет доступных подкатегорий", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Неправильный номер", + "@numberInvalid": {}, + "onOrder": "Под заказ", + "@onOrder": {}, + "onOrderDetails": "Заказаные элементы", + "@onOrderDetails": {}, + "orientation": "Ориентация экрана", + "@orientation": {}, + "orientationDetail": "Ориентация экрана (требуется перезапуск)", + "@orientationDetail": {}, + "orientationLandscape": "Альбомная", + "@orientationLandscape": {}, + "orientationPortrait": "Портретная", + "@orientationPortrait": {}, + "orientationSystem": "Система", + "@orientationSystem": {}, + "outstanding": "Не оплачено", + "@outstanding": {}, + "outstandingOrderDetail": "Показать невыполненные заказы", + "@outstandingOrderDetail": {}, + "overdue": "Просрочено", + "@overdue": {}, + "overdueDetail": "Показывать просроченные заказы", + "@overdueDetail": {}, + "packaging": "Упаковка", + "@packaging": {}, + "packageName": "Название упаковки", + "@packageName": {}, + "parameters": "Параметры", + "@parameters": {}, + "parametersSettingDetail": "Отображение параметров детали", + "@parametersSettingDetail": {}, + "parent": "Родитель", + "@parent": {}, + "parentCategory": "Родительская категория", + "@parentCategory": {}, + "parentLocation": "Родительское местоположение", + "@parentLocation": {}, + "part": "Компонент", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Новый компонент", + "@partCreate": {}, + "partCreateDetail": "Создать компонент в данной категории", + "@partCreateDetail": {}, + "partEdited": "Деталь обновлена", + "@partEdited": {}, + "parts": "Номенклатура", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Часть не помечена как продаваемая", + "@partNotSalable": {}, + "partsNone": "Нет компонентов", + "@partsNone": {}, + "partNoResults": "Нет компонентов, соответствующих запросу", + "@partNoResults": {}, + "partPricing": "Цены детали", + "@partPricing": {}, + "partPricingSettingDetail": "Показывать информацию о ценах", + "@pricingSettingDetail": {}, + "partSettings": "Настройки деталей", + "@partSettings": {}, + "partsStarred": "Детали с включёнными уведомлениями", + "@partsStarred": {}, + "partsStarredNone": "Отмеченные детали не доступны", + "@partsStarredNone": {}, + "partSuppliers": "Поставщики детали", + "@partSuppliers": {}, + "partCategory": "Категория детали", + "@partCategory": {}, + "partCategoryTopLevel": "Категория детали верхнего уровня", + "@partCategoryTopLevel": {}, + "partCategories": "Категории деталей", + "@partCategories": {}, + "partDetails": "Информация о детали", + "@partDetails": {}, + "partNotes": "Заметки детали", + "@partNotes": {}, + "partStock": "Складские позиции детали", + "@partStock": { + "description": "part stock" + }, + "password": "Пароль", + "@password": {}, + "passwordEmpty": "Пароль не может быть пустым", + "@passwordEmpty": {}, + "pending": "В обработке", + "@pending": {}, + "permissionAccountDenied": "Ваш аккаунт не имеет разрешения на выполнение этого действия", + "@permissionAccountDenied": {}, + "permissionRequired": "Требуется разрешение", + "@permissionRequired": {}, + "phone": "Телефон", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Подтвердить сканирование данных", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Подтвердите подробности при сканировании позиций", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Включить заказы на закупку", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Включить функцию заказов на закупку", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Кнопка камеры", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Включить кнопку загрузки изображений на экране заказа", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Заказ на поставку", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Новый заказ на поставку", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Редактировать заказ на поставку", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Настройки заказа на закупку", + "@purchaseOrderSettings": {}, + "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": {}, + "rotateClockwise": "Повернуть на 90° по часовой стрелке", + "@rotateClockwise": {}, + "refreshing": "Обновление…", + "@refreshing": {}, + "rejected": "Отклонено", + "@rejected": {}, + "releaseNotes": "Заметки о выпуске", + "@releaseNotes": {}, + "remove": "Удалить", + "@remove": { + "description": "remove" + }, + "removeStock": "Удалить запасы", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Сообщить об ошибке", + "@reportBug": {}, + "reportBugDescription": "Отправить сообщение об ошибке (требуется учетная запись GitHub)", + "@reportBugDescription": {}, + "responsible": "Ответственный", + "@responsible": {}, + "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": "Ресурс не найден", + "@response404": {}, + "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": {}, + "salesOrder": "Заказы на продажу", + "@salesOrder": {}, + "salesOrders": "Заказы на продажу", + "@salesOrders": {}, + "salesOrderEnable": "Включить заказы на продажу", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Включить функцию заказов на продажу", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Кнопка камеры", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Включить кнопку загрузки изображений на экране заказов", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Настройки заказа на продажу", + "@salesOrderSettings": {}, + "salesOrderCreate": "Новый заказ на продажу", + "@saleOrderCreate": {}, + "salesOrderEdit": "Редактировать заказ на продажу", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Заказ на продажу обновлен", + "@salesOrderUpdated": {}, + "save": "Сохранить", + "@save": { + "description": "Save" + }, + "scanBarcode": "Сканировать штрихкод", + "@scanBarcode": {}, + "scanSupplierPart": "Отсканировать штрих-код части от поставщика", + "@scanSupplierPart": {}, + "scanIntoLocation": "Сканировать в местоположение", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Отсканировать этот компонент в местоположение", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Внешний сканер", + "@scannerExternal": {}, + "scannerExternalDetail": "Использовать внешний сканер для чтения штрих-кодов (клик-режим)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Сканирование принятых деталей", + "@scanReceivedParts": {}, + "search": "Поиск", + "@search": { + "description": "search" + }, + "searching": "Поиск", + "@searching": {}, + "searchLocation": "Искать по месту", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "Найти номенклатуру", + "@searchParts": {}, + "searchStock": "Поиск в наличии", + "@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": "Сервер должен начинаться с http[s]", + "@serverStart": {}, + "settings": "Настройки", + "@settings": {}, + "serverInstance": "Экземпляр сервера", + "@serverInstance": {}, + "serverNotConnected": "Сервер не подключен", + "@serverNotConnected": {}, + "serverNotSelected": "Сервер не выбран", + "@serverNotSelected": {}, + "shipment": "Отгрузка", + "@shipment": {}, + "shipments": "Поставки", + "@shipments": {}, + "shipmentsPending": "Ожидающие отгрузки", + "@shipmentsPending": {}, + "shipmentAdd": "Новое Отправление", + "@shipmentAdd": {}, + "shipmentCheck": "Проверить отгрузку", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Отметить этот груз как проверенный", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Отгрузка проверена", + "@shipmentChecked": {}, + "shipmentDate": "Дата отгрузки", + "@shipmentDate": {}, + "shipmentEdit": "Редактировать отгрузку", + "@shipmentEdit": {}, + "shipmentReference": "Ссылка на отгрузку", + "@shipmentReference": {}, + "shipmentSend": "Отправить отгрузку", + "@shipmentSend": {}, + "shipmentUncheck": "Снять отметку с отгрузки", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Отметить этот груз как непроверенный", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Отгрузка обновлена", + "@shipmentUpdated": {}, + "shipped": "Отгружено", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Звуки", + "@sounds": {}, + "soundOnBarcodeAction": "Воспроизводить звуковой сигнал при действиях со штрих-кодом", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Воспроизводить звуковой сигнал при ошибке сервера", + "@soundOnServerError": {}, + "startDate": "Дата начала", + "@startDate": {}, + "status": "Статус", + "@status": {}, + "statusCode": "Код статуса", + "@statusCode": {}, + "stock": "Склад", + "@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": "Складская позиция обновлена", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Сбой обновления складской позиции", + "@stockItemUpdateFailure": {}, + "stockLocation": "Место хранения", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Места хранения", + "@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": "Деталь поставщика", + "@supplierPart": {}, + "supplierPartEdit": "Редактировать деталь поставщика", + "@supplierPartEdit": {}, + "supplierPartNumber": "Номер детали поставщика", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Деталь поставщика обновлена", + "@supplierPartUpdated": {}, + "supplierParts": "Детали поставщика", + "@supplierParts": {}, + "suppliers": "Поставщики", + "@suppliers": {}, + "supplierReference": "Ссылка на поставщика", + "@supplierReference": {}, + "switchCamera": "Переключить камеру", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Фонарик", + "@toggleTorch": {}, + "tokenError": "Ошибка токена", + "@tokenError": {}, + "tokenMissing": "Отсутствует токен", + "@tokenMissing": {}, + "tokenMissingFromResponse": "В ответе отсутствует токен доступа", + "@tokenMissingFromResponse": {}, + "totalPrice": "Общая стоимость", + "@totalPrice": {}, + "trackingNumber": "Номер отслеживания", + "@trackingNumber": {}, + "transfer": "Перемещение", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Переместить запасы", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Переместить складскую позицию в другое место", + "@transferStockDetail": {}, + "transferStockLocation": "Изменить местоположение склада", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Перенести это место на складе в другое", + "@transferStockLocationDetail": {}, + "translate": "Перевод", + "@translate": {}, + "translateHelp": "Помочь перевести приложение InvenTree", + "@translateHelp": {}, + "unavailable": "Недоступно", + "@unavailable": {}, + "unavailableDetail": "Позиция недоступна", + "@unavailableDetail": {}, + "unitPrice": "Цена за ед.", + "@unitPrice": {}, + "units": "Единицы измерения", + "@units": {}, + "unknownResponse": "Неизвестный ответ", + "@unknownResponse": {}, + "upload": "Загрузить", + "@upload": {}, + "uploadFailed": "Не удалось загрузить файл", + "@uploadFailed": {}, + "uploadSuccess": "Файл загружен", + "@uploadSuccess": {}, + "uploadImage": "Загрузить изображение", + "@uploadImage": {}, + "usedIn": "Используется в", + "@usedIn": {}, + "usedInDetails": "Сборки, для которых требуется эта часть", + "@usedInDetails": {}, + "username": "Имя пользователя", + "@username": {}, + "usernameEmpty": "Имя пользователя не может быть пустым", + "@usernameEmpty": {}, + "value": "Значение", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Значение не может быть пустым", + "@valueCannotBeEmpty": {}, + "valueRequired": "Необходимо указать значение", + "@valueRequired": {}, + "variants": "Разновидности", + "@variants": {}, + "version": "Версия", + "@version": {}, + "viewSupplierPart": "Отобразить деталь поставщика", + "@viewSupplierPart": {}, + "website": "Сайт", + "@website": {}, + "yes": "Да", + "@yes": {}, + "price": "Цена", + "@price": {}, + "priceRange": "Диапазон цен", + "@priceRange": {}, + "priceOverrideMin": "Переопределение минимальной цены", + "@priceOverrideMin": {}, + "priceOverrideMax": "Переопределение максимальной цены", + "@priceOverrideMax": {}, + "salePrice": "Цена продажи", + "@salePrice": {}, + "saleHistory": "История продаж", + "@saleHistory": {}, + "supplierPricing": "Цены поставщика", + "@supplierPricing": {}, + "bomCost": "Стоимость спецификации", + "@bomCost": {}, + "internalCost": "Внутренняя стоимость", + "@internalCost": {}, + "variantCost": "Стоимость варианта", + "@variantCost": {}, + "overallPricing": "Общая цена", + "@overallPricing": {}, + "pricingOverrides": "Переопределение цен", + "@pricingOverrides": {}, + "currency": "Валюта", + "@currency": {}, + "priceBreaks": "Разбивка по ценам", + "@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 new file mode 100644 index 0000000..e60c333 --- /dev/null +++ b/lib/l10n/sk_SK/app_sk_SK.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..e0c78b1 --- /dev/null +++ b/lib/l10n/sl_SI/app_sl_SI.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allocate Stock", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Display app release notes", + "@appReleaseNotes": {}, + "appSettings": "App Settings", + "@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", + "@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 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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..75d28b4 --- /dev/null +++ b/lib/l10n/sr_CS/app_sr_CS.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "sr-CS", + "appTitle": "Inventree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "Ok", + "@ok": { + "description": "OK" + }, + "about": "O", + "@about": {}, + "accountDetails": "Detalji naloga", + "@accountDetails": {}, + "actions": "Akcije", + "@actions": { + "description": "" + }, + "actionsNone": "Nema dostupnih akcija", + "@actionsNone": {}, + "add": "Dodaj", + "@add": { + "description": "add" + }, + "addStock": "Dodaj zalihe", + "@addStock": { + "description": "add stock" + }, + "address": "Adresa", + "@address": {}, + "appAbout": "O InvenTree", + "@appAbout": {}, + "appCredits": "Dodane informacije o aplikaciji", + "@appCredits": {}, + "appDetails": "Detalji aplikacije", + "@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": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Prikaži informacije o aplikaciji", + "@appReleaseNotes": {}, + "appSettings": "Podešavanja aplikacije", + "@appSettings": {}, + "appSettingsDetails": "Konfiguriši podešavanja aplikacije", + "@appSettingsDetails": {}, + "assignedToMe": "Dodeljeno meni", + "@assignedToMe": {}, + "assignedToMeDetail": "Prikaži naloge koji su dodeljeni meni", + "@assignedToMeDetail": {}, + "attachments": "Prilozi", + "@attachments": {}, + "attachImage": "Dodaj sliku", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Nema pronađenih priloga", + "@attachmentNone": {}, + "attachmentNoneDetail": "Nema pronađenih priloga", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Izaberi prilog", + "@attachmentSelect": {}, + "attention": "Pažnja", + "@attention": {}, + "available": "Dostupno", + "@available": {}, + "availableStock": "Dostupne zalihe", + "@availableStock": {}, + "barcodes": "Bar kodovi", + "@barcodes": {}, + "barcodeSettings": "Podešavanja bar koda", + "@barcodeSettings": {}, + "barcodeAssign": "Dodeli bar kod", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Skeniraj i dodeli prilagođeni bar kod", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Dodeljen bar kod", + "@barcodeAssigned": {}, + "barcodeError": "Greška pri skeniranju bar koda", + "@barcodeError": {}, + "barcodeInUse": "Bar kod već dodeljen", + "@barcodeInUse": {}, + "barcodeMissingHash": "Nedostaju heš podaci bar koda iz odgovora", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Nema podudaranja za bar kod", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Bar kod nije dodeljen", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Skeniraj bar kod dela", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Skeniraj bar kod da bi primio deo", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Pauzirano skeniranje bar kodova", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Skeniraj za dodelu bar koda", + "@barcodeScanAssign": {}, + "barcodeScanController": "Ulaz skenera", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Izaberi izvor podataka za bar kod skener", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Odlaganje prilikom skeniranja bar koda", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Odlaganje između skeniranja bar kodova", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Skeniraj bar kod", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Skeniraj stavku zaliha na ovu lokaciju", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skeniraj lokaciju zaliha", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Mod jednog skeniranja", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pauziraj bar kod skener nakon svakog skeniranja", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Skenirano na lokaciju", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Stavka nije skenirana u", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skeniraj stavku sa zaliha", + "@barcodeScanItem": {}, + "barcodeTones": "Tonovi bar koda", + "@barcodeTones": {}, + "barcodeUnassign": "Ukloni bar kod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Bar kod nije prepoznat", + "@barcodeUnknown": {}, + "batchCode": "Šifra serije", + "@batchCode": {}, + "billOfMaterials": "Spisak materijala", + "@billOfMaterials": {}, + "bom": "Spisak materijala", + "@bom": {}, + "bomEnable": "Prikaži spisak materijala", + "@bomEnable": {}, + "build": "Izgradnja", + "@build": {}, + "building": "Izrađivanje", + "@building": {}, + "cameraCreationError": "Nije moguće otvoriti kontroler kamere", + "@cameraCreationError": {}, + "cameraInternal": "Interna kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Koristi internu kameru za čitanje bar kodova", + "@cameraInternalDetail": {}, + "cancel": "Otkaži", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Otkaži nalog", + "@cancelOrder": {}, + "category": "Kategorija", + "@category": {}, + "categoryCreate": "Nova kategorija", + "@categoryCreate": {}, + "categoryCreateDetail": "Kreiraj novu kategoriju dela", + "@categoryCreateDetail": {}, + "categoryUpdated": "Ažurirana kategorija dela", + "@categoryUpdated": {}, + "company": "Kompanija", + "@company": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Izmeni kompaniju", + "@companyEdit": {}, + "companyNoResults": "Nema kompanije koje odgovaraju upitu", + "@companyNoResults": {}, + "companyUpdated": "Podaci o kompaniji ažurirani", + "@companyUpdated": {}, + "companies": "Kompanije", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Konfiguriši podešavanja servera", + "@configureServer": {}, + "confirmScan": "Potvrdi prenos", + "@confirmScan": {}, + "confirmScanDetail": "Potvrdi detalje transfera zaliha prilikom skeniranja bar kodova", + "@confirmScanDetail": {}, + "connectionRefused": "Konekcija odbijena", + "@connectionRefused": {}, + "count": "Broj", + "@count": { + "description": "Count" + }, + "countStock": "Prebroj zalihe", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Zasluge", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Mušterija", + "@customer": {}, + "customers": "Mušterije", + "@customers": {}, + "customerReference": "Referenca mušterije", + "@customerReference": {}, + "damaged": "Oštećeno", + "@damaged": {}, + "colorScheme": "Šema boja", + "@colorScheme": {}, + "colorSchemeDetail": "Izaberi šemu boja", + "@colorSchemeDetail": {}, + "darkMode": "Tamni mod", + "@darkMode": {}, + "darkModeEnable": "Omogući tamni mod", + "@darkModeEnable": {}, + "delete": "Obriši", + "@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", + "@destination": {}, + "destroyed": "Uništeno", + "@destroyed": {}, + "details": "Detalji", + "@details": { + "description": "details" + }, + "documentation": "Dokumentacija", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Preuzimanje fajla", + "@downloading": {}, + "edit": "Izmeni", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "Izmeni kategoriju", + "@editCategory": {}, + "editLocation": "Izmeni lokaciju", + "@editLocation": {}, + "editNotes": "Izmeni beleške", + "@editNotes": {}, + "editParameter": "Izmeni parametar", + "@editParameter": {}, + "editPart": "Izmeni deo", + "@editPart": { + "description": "edit part" + }, + "editItem": "Izmeni stavku sa zaliha", + "@editItem": {}, + "editLineItem": "Izmeni stavku porudžbine", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "Unesi lozinku", + "@enterPassword": {}, + "enterUsername": "Unesi korisničko ime", + "@enterUsername": {}, + "error": "Greška", + "@error": { + "description": "Error" + }, + "errorCreate": "Greška pri kreiranju unosa u bazu podataka", + "@errorCreate": {}, + "errorDelete": "Greška pri brisanju zapisa u bazi podataka", + "@errorDelete": {}, + "errorDetails": "Detalji greške", + "@errorDetails": {}, + "errorFetch": "Greška pri prikupljanju podataka sa servera", + "@errorFetch": {}, + "errorUserRoles": "Greška pri prikupljanju podataka o rolama korisnika", + "@errorUserRoles": {}, + "errorPluginInfo": "Greška pri prikupljanju podataka o pluginovima", + "@errorPluginInfo": {}, + "errorReporting": "Prijavljivanje grešaka", + "@errorReporting": {}, + "errorReportUpload": "Dodaj izveštaje o greškama", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Dodaj anonimne izveštaje o greškama i logove", + "@errorReportUploadDetails": {}, + "expiryDate": "Datum isteka", + "@expiryDate": {}, + "expiryExpired": "Isteklo", + "@expiryExpired": {}, + "expiryStale": "Zastarelo", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "feedback": "Povratne informacije", + "@feedback": {}, + "feedbackError": "Greška pri postavljanju povratnih informacija", + "@feedbackError": {}, + "feedbackSuccess": "Povratne informacije poslate", + "@feedbackSuccess": {}, + "filterActive": "Aktivno", + "@filterActive": {}, + "filterActiveDetail": "Prikaži aktivne delove", + "@filterActiveDetail": {}, + "filterAssembly": "Sklopljeno", + "@filterAssembly": {}, + "filterAssemblyDetail": "Prikaži sklopljene delove", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponenta", + "@filterComponent": {}, + "filterComponentDetail": "Prikaži delove komponente", + "@filterComponentDetail": {}, + "filterExternal": "Spoljno", + "@filterExternal": {}, + "filterExternalDetail": "Prikaži zalihe na eksternim lokacijama", + "@filterExternalDetail": {}, + "filterInStock": "Na zalihama", + "@filterInStock": {}, + "filterInStockDetail": "Prikaži delove koji imaju zalihe", + "@filterInStockDetail": {}, + "filterSerialized": "Serijalizovano", + "@filterSerialized": {}, + "filterSerializedDetail": "Prikaži serijalizovane stavke sa zaliha", + "@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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Datum izdavanja", + "@issueDate": {}, + "issueOrder": "Izdaj nalog", + "@issueOrder": {}, + "itemInLocation": "Stavka već na lokaciji", + "@itemInLocation": {}, + "itemDeleted": "Stavka je uklonjena", + "@itemDeleted": {}, + "itemUpdated": "Stavka ažurirana", + "@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", + "@labelPrintingDetail": {}, + "labelTemplate": "Šablon natpisa", + "@labelTemplate": {}, + "labelSelectTemplate": "Izaberi šablon natpisa", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Odaberi štampač natpisa", + "@labelSelectPrinter": {}, + "language": "Jezik", + "@language": {}, + "languageDefault": "Podrazumevani sistemski jezik", + "@languageDefault": {}, + "languageSelect": "Izaberi jezik", + "@languageSelect": {}, + "lastStocktake": "Poslednji popis", + "@lastStocktake": {}, + "lastUpdated": "Poslednji put ažurirano", + "@lastUpdated": {}, + "level": "Nivo", + "@level": {}, + "lineItemAdd": "Dodaj stavku porudžbine", + "@lineItemAdd": {}, + "lineItem": "Stavka porudžbine", + "@lineItem": {}, + "lineItems": "Stavke porudžbine", + "@lineItems": {}, + "lineItemUpdated": "Stavka porudžbine ažurirana", + "@lineItemUpdated": {}, + "locateItem": "Pronađi stavku sa zaliha", + "@locateItem": {}, + "locateLocation": "Pronađi lokaciju zaliha", + "@locateLocation": {}, + "locationCreate": "Nova lokacija", + "@locationCreate": {}, + "locationCreateDetail": "Kreiraj novu lokaciju zaliha", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "Nema određene lokacije", + "@locationNotSet": {}, + "locationUpdated": "Ažurirana lokacija zaliha", + "@locationUpdated": {}, + "login": "Prijava", + "@login": {}, + "loginEnter": "Unesi detalje prijave", + "@loginEnter": {}, + "loginEnterDetails": "Korisničko ime i lozinka se ne skladište lokalno", + "@loginEnterDetails": {}, + "link": "Link", + "@link": {}, + "lost": "Izgubljeno", + "@lost": {}, + "manufacturerPart": "Deo proizvođača", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Izmeni deo proizvođača", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Broj dela proizvođača", + "@manufacturerPartNumber": {}, + "manufacturer": "Proizvođač", + "@manufacturer": {}, + "manufacturers": "Proizvođači", + "@manufacturers": {}, + "missingData": "Nedostajući podaci", + "@missingData": {}, + "name": "Ime", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Nije povezano", + "@notConnected": {}, + "notes": "Beleške", + "@notes": { + "description": "Notes" + }, + "notifications": "Notifikacije", + "@notifications": {}, + "notificationsEmpty": "Nema nepročitanih notifikacija", + "@notificationsEmpty": {}, + "noResponse": "Nema odgovora od servera", + "@noResponse": {}, + "noResults": "Nema rezultata", + "@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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Nevažeći broj", + "@numberInvalid": {}, + "onOrder": "Na nalogu", + "@onOrder": {}, + "onOrderDetails": "Stavke trenutno na nalogu", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..7ff3063 --- /dev/null +++ b/lib/l10n/sv_SE/app_sv_SE.arb @@ -0,0 +1,1215 @@ +{ + "@@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": "Adress", + "@address": {}, + "appAbout": "Om InvenTree", + "@appAbout": {}, + "appCredits": "Ytterligare bidragande till appen", + "@appCredits": {}, + "appDetails": "Appdetaljer", + "@appDetails": {}, + "allocated": "Allokerad", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Kvadrat (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Allokera lager", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "Visa versionsinfo för app", + "@appReleaseNotes": {}, + "appSettings": "Appinställningar", + "@appSettings": {}, + "appSettingsDetails": "Konfigurera inställningar för InvenTree app", + "@appSettingsDetails": {}, + "assignedToMe": "Tilldelade till mig", + "@assignedToMe": {}, + "assignedToMeDetail": "Visa beställningar som är tilldelade till mig", + "@assignedToMeDetail": {}, + "attachments": "Bilagor", + "@attachments": {}, + "attachImage": "Bifoga bild", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Inga bilagor hittades", + "@attachmentNone": {}, + "attachmentNoneDetail": "Inga bilagor hittades", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Välj bilaga", + "@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": {}, + "barcodeMissingHash": "Streckkodshashdata saknas från svar", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Ingen träff för streckkod", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Streckkod inte tilldelad", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Skanna artikelstreckkod", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Skanna streckkod för att ta emot del", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Streckkodsskanning pausad", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tryck för att pausa skanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Skanna för att tilldela streckkod", + "@barcodeScanAssign": {}, + "barcodeScanController": "Skanner indata", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Välj streckkodsläsare indatakälla", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Streckkod Skanna Fördröjning", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Fördröjning mellan streckkodsskanningar", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Skanna en InvenTree streckkod", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Skanna lagervaror till denna plats", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Skanna lagerplats", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Enkelt skanningsläge", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Pausa streckkodsläsare efter varje skanning", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Skannad till plats", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Objektet skannades inte in", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Skanna lagervara", + "@barcodeScanItem": {}, + "barcodeTones": "Streckkods Toner", + "@barcodeTones": {}, + "barcodeUnassign": "Ta bort streckkod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Streckkoden känns inte igen", + "@barcodeUnknown": {}, + "batchCode": "Batchkod", + "@batchCode": {}, + "billOfMaterials": "Stycklista", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Visa stycklista", + "@bomEnable": {}, + "build": "Bygg", + "@build": {}, + "building": "Bygger", + "@building": {}, + "cameraCreationError": "Kunde inte öppna kameraenheten", + "@cameraCreationError": {}, + "cameraInternal": "Intern kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Använd intern kamera för att läsa streckkoder", + "@cameraInternalDetail": {}, + "cancel": "Avbryt", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Avbryt order", + "@cancelOrder": {}, + "category": "Kategori", + "@category": {}, + "categoryCreate": "Ny kategori", + "@categoryCreate": {}, + "categoryCreateDetail": "Skapa ny artikelkategori", + "@categoryCreateDetail": {}, + "categoryUpdated": "Artikel kategori uppdaterad", + "@categoryUpdated": {}, + "company": "Företag", + "@company": {}, + "companyAdd": "Lägg till företag", + "@companyAdd": {}, + "companyEdit": "Redigera företag", + "@companyEdit": {}, + "companyNoResults": "Inga företag som matchar frågan", + "@companyNoResults": {}, + "companyUpdated": "Företagsdetaljer uppdaterade", + "@companyUpdated": {}, + "companies": "Företag", + "@companies": {}, + "complete": "Slutförd", + "@complete": {}, + "completeOrder": "Slutför Order", + "@completeOrder": {}, + "completionDate": "Datum slutfört", + "@completionDate": {}, + "configureServer": "Konfigurera serverinställningar", + "@configureServer": {}, + "confirmScan": "Bekräfta överföring", + "@confirmScan": {}, + "confirmScanDetail": "Bekräfta lageröverföringsdetaljer vid skanning av streckkoder", + "@confirmScanDetail": {}, + "connectionRefused": "Anslutning nekad", + "@connectionRefused": {}, + "count": "Antal", + "@count": { + "description": "Count" + }, + "countStock": "Antal Lager", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Krediter", + "@credits": {}, + "crop": "Beskär", + "@crop": {}, + "cropImage": "Beskär Bild", + "@cropImage": {}, + "customer": "Kund", + "@customer": {}, + "customers": "Kunder", + "@customers": {}, + "customerReference": "Kundreferens", + "@customerReference": {}, + "damaged": "Skadad", + "@damaged": {}, + "colorScheme": "Färgschema", + "@colorScheme": {}, + "colorSchemeDetail": "Välj färgschema", + "@colorSchemeDetail": {}, + "darkMode": "Mörkt läge", + "@darkMode": {}, + "darkModeEnable": "Aktivera mörkt läge", + "@darkModeEnable": {}, + "delete": "Radera", + "@delete": {}, + "deleteFailed": "Borttagning misslyckades", + "@deleteFailed": {}, + "deleteImageConfirmation": "Är du säker på att du vill radera denna bild?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Radera bild", + "@deleteImageTooltip": {}, + "deleteImage": "Radera bild", + "@deleteImage": {}, + "deletePart": "Ta bort del", + "@deletePart": {}, + "deletePartDetail": "Ta bort denna del från databasen", + "@deletePartDetail": {}, + "deleteSuccess": "Borttagning lyckad", + "@deleteSuccess": {}, + "deliveryDate": "Leveransdatum", + "@deliveryDate": {}, + "description": "Beskrivning", + "@description": {}, + "destination": "Destination", + "@destination": {}, + "destroyed": "Förstörd", + "@destroyed": {}, + "details": "Detaljer", + "@details": { + "description": "details" + }, + "documentation": "Dokumentation", + "@documentation": {}, + "downloadComplete": "Nedladdning klar", + "@downloadComplete": {}, + "downloadError": "Fel vid nedladdning av bild", + "@downloadError": {}, + "downloading": "Laddar ner fil", + "@downloading": {}, + "edit": "Redigera", + "@edit": { + "description": "edit" + }, + "editAttachment": "Redigera bilaga", + "@editAttachment": {}, + "editCategory": "Redigera kategori", + "@editCategory": {}, + "editLocation": "Redigera plats", + "@editLocation": {}, + "editNotes": "Redigera anteckningar", + "@editNotes": {}, + "editParameter": "Redigera parameter", + "@editParameter": {}, + "editPart": "Redigera artikel", + "@editPart": { + "description": "edit part" + }, + "editItem": "Ändra lagerartikel", + "@editItem": {}, + "editLineItem": "Redigera radobjekt", + "@editLineItem": {}, + "email": "E-post", + "@email": {}, + "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": {}, + "errorFetch": "Fel vid hämtning av data från servern", + "@errorFetch": {}, + "errorUserRoles": "Fel vid begäran om användarroller från servern", + "@errorUserRoles": {}, + "errorPluginInfo": "Fel vid begäran av plugin-data från servern", + "@errorPluginInfo": {}, + "errorReporting": "Felrapportering", + "@errorReporting": {}, + "errorReportUpload": "Ladda upp felrapporter", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Ladda upp anonyma felrapporter och kraschloggar", + "@errorReportUploadDetails": {}, + "expiryDate": "Förfallodatum", + "@expiryDate": {}, + "expiryExpired": "Förfallen", + "@expiryExpired": {}, + "expiryStale": "Inaktuell", + "@expiryStale": {}, + "extraLineItem": "Extra radobjekt", + "@extraLineItem": {}, + "extraLineItems": "Extra radobjekt", + "@extraLineItems": {}, + "feedback": "Feedback", + "@feedback": {}, + "feedbackError": "Det gick inte att skicka feedback", + "@feedbackError": {}, + "feedbackSuccess": "Feedback inskickat", + "@feedbackSuccess": {}, + "filterActive": "Aktiv", + "@filterActive": {}, + "filterActiveDetail": "Visa aktiva komponenter", + "@filterActiveDetail": {}, + "filterAssembly": "Sammansatt", + "@filterAssembly": {}, + "filterAssemblyDetail": "Visa sammansatta delar", + "@filterAssemblyDetail": {}, + "filterComponent": "Komponent", + "@filterComponent": {}, + "filterComponentDetail": "Visa komponentdelar", + "@filterComponentDetail": {}, + "filterExternal": "Extern", + "@filterExternal": {}, + "filterExternalDetail": "Visa lager på externa platser", + "@filterExternalDetail": {}, + "filterInStock": "I lager", + "@filterInStock": {}, + "filterInStockDetail": "Visa artiklar som har lager", + "@filterInStockDetail": {}, + "filterSerialized": "Serialiserad", + "@filterSerialized": {}, + "filterSerializedDetail": "Visa serialiserade lagervaror", + "@filterSerializedDetail": {}, + "filterTemplate": "Mall", + "@filterTemplate": {}, + "filterTemplateDetail": "Visa mallartiklar", + "@filterTemplateDetail": {}, + "filterTrackable": "Spårbar", + "@filterTrackable": {}, + "filterTrackableDetail": "Visa spårbara artiklar", + "@filterTrackableDetail": {}, + "filterVirtual": "Virtuell", + "@filterVirtual": {}, + "filterVirtualDetail": "Visa virtuella artiklar", + "@filterVirtualDetail": {}, + "filteringOptions": "Filtreringsalternativ", + "@filteringOptions": {}, + "formatException": "Formatera undantag", + "@formatException": {}, + "formatExceptionJson": "JSON-dataformat undantag", + "@formatExceptionJson": {}, + "formError": "Formulär fel", + "@formError": {}, + "history": "Historik", + "@history": { + "description": "history" + }, + "home": "Hem", + "@home": {}, + "homeScreen": "Startsidan", + "@homeScreen": {}, + "homeScreenSettings": "Konfigurera inställningar för startskärmen", + "@homeScreenSettings": {}, + "homeShowPo": "Visa inköpsorder", + "@homeShowPo": {}, + "homeShowPoDescription": "Visa knappen för inköpsorder på startskärmen", + "@homeShowPoDescription": {}, + "homeShowShipments": "Visa leveranser", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Visa väntande leveranser på startskärmen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Visa försäljningsorder", + "@homeShowSo": {}, + "homeShowSoDescription": "Visa knappen för försäljningsorder på startskärmen", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Prenumererade artiklar", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Visa prenumererade artiklar på startskärmen", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Visa leverantörer", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Visa leverantörsknapp på startskärmen", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Visa tillverkare", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Visa tillverkarknapp på startskärmen", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Visa kunder", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Visa kund knappen på startskärmen", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Bilduppladdning misslyckades", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Bild uppladdad", + "@imageUploadSuccess": {}, + "inactive": "Inaktiv", + "@inactive": {}, + "inactiveCompany": "Detta företag är markerat som inaktivt", + "@inactiveCompany": {}, + "inactiveDetail": "Denna artikel är markerad som inaktiv", + "@inactiveDetail": {}, + "includeSubcategories": "Inkludera underkategorier", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Visa resultat från underkategorier", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Inkludera underplats", + "@includeSublocations": {}, + "includeSublocationsDetail": "Visa resultat från underplatser", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Ofullständig profilinformation", + "@incompleteDetails": {}, + "internalPartNumber": "Internt artikelnummer", + "@internalPartNumber": {}, + "info": "Information", + "@info": {}, + "inProduction": "Under produktion", + "@inProduction": {}, + "inProductionDetail": "Denna lagervara är i produktion", + "@inProductionDetail": {}, + "internalPart": "Intern artikel", + "@internalPart": {}, + "invalidHost": "Ogiltigt värdnamn", + "@invalidHost": {}, + "invalidHostDetails": "Angivet värdnamn är inte giltigt", + "@invalidHostDetails": {}, + "invalidPart": "Ogiltig Artikel", + "@invalidPart": {}, + "invalidPartCategory": "Ogiltig artikelkategori", + "@invalidPartCategory": {}, + "invalidStockLocation": "Ogiltig lagerplats", + "@invalidStockLocation": {}, + "invalidStockItem": "Ogiltig lagervara", + "@invalidStockItem": {}, + "invalidSupplierPart": "Ogiltig leverantörs artikel", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Felaktigt användarnamn / lösenord kombination", + "@invalidUsernamePassword": {}, + "invoice": "Faktura", + "@invoice": {}, + "invoiceNumber": "Fakturanummer", + "@invoiceNumber": {}, + "issue": "Ärende", + "@issue": {}, + "issueDate": "Utfärdad datum", + "@issueDate": {}, + "issueOrder": "Ärende order", + "@issueOrder": {}, + "itemInLocation": "Föremålet finns redan på plats", + "@itemInLocation": {}, + "itemDeleted": "Objektet har tagits bort", + "@itemDeleted": {}, + "itemUpdated": "Objekt uppdaterat", + "@itemUpdated": {}, + "keywords": "Nyckelord", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Utskrift av etiketter", + "@labelPrinting": {}, + "labelPrintingDetail": "Aktivera etikettutskrift", + "@labelPrintingDetail": {}, + "labelTemplate": "Etikettmall", + "@labelTemplate": {}, + "labelSelectTemplate": "Välj etikettmall", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Välj etikettskrivare", + "@labelSelectPrinter": {}, + "language": "Språk", + "@language": {}, + "languageDefault": "Standard systemspråk", + "@languageDefault": {}, + "languageSelect": "Välj språk", + "@languageSelect": {}, + "lastStocktake": "Senaste inventering", + "@lastStocktake": {}, + "lastUpdated": "Senast uppdaterad", + "@lastUpdated": {}, + "level": "Nivå", + "@level": {}, + "lineItemAdd": "Lägg till radobjekt", + "@lineItemAdd": {}, + "lineItem": "Rad objekt", + "@lineItem": {}, + "lineItems": "Radobjekt", + "@lineItems": {}, + "lineItemUpdated": "Rad uppdaterad", + "@lineItemUpdated": {}, + "locateItem": "Hitta lagerobjekt", + "@locateItem": {}, + "locateLocation": "Hitta lagerplats", + "@locateLocation": {}, + "locationCreate": "Ny plats", + "@locationCreate": {}, + "locationCreateDetail": "Skapa ny lagerplats", + "@locationCreateDetail": {}, + "locationDefault": "Förvald plats", + "@locationDefault": {}, + "locationNotSet": "Ingen plats specificerad", + "@locationNotSet": {}, + "locationUpdated": "Lagerplatsen uppdaterad", + "@locationUpdated": {}, + "login": "Logga in", + "@login": {}, + "loginEnter": "Ange inloggningsuppgifter", + "@loginEnter": {}, + "loginEnterDetails": "Användarnamn och lösenord sparas inte lokalt", + "@loginEnterDetails": {}, + "link": "Länk", + "@link": {}, + "lost": "Förlorad", + "@lost": {}, + "manufacturerPart": "Tillverkarens artikel", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Redigera tillverkarens artikel", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Tillverkarens artikelnummer", + "@manufacturerPartNumber": {}, + "manufacturer": "Tillverkare", + "@manufacturer": {}, + "manufacturers": "Tillverkare", + "@manufacturers": {}, + "missingData": "Data saknas", + "@missingData": {}, + "name": "Namn", + "@name": {}, + "no": "Nej", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "Ej ansluten", + "@notConnected": {}, + "notes": "Anteckningar", + "@notes": { + "description": "Notes" + }, + "notifications": "Aviseringar", + "@notifications": {}, + "notificationsEmpty": "Inga olästa aviseringar", + "@notificationsEmpty": {}, + "noResponse": "Inget svar från servern", + "@noResponse": {}, + "noResults": "Inga resultat", + "@noResults": {}, + "noImageAvailable": "Ingen bild tillgänglig", + "@noImageAvailable": {}, + "noPricingAvailable": "Ingen prisinformation tillgänglig", + "@noPricingAvailable": {}, + "noPricingDataFound": "Inga prisuppgifter hittades för denna artikel", + "@noPricingDataFound": {}, + "noSubcategories": "Inga underkategorier", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Inga underkategorier tillgängliga", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Ogiltigt nummer", + "@numberInvalid": {}, + "onOrder": "På order", + "@onOrder": {}, + "onOrderDetails": "Artiklar på beställning för närvarande", + "@onOrderDetails": {}, + "orientation": "Skärmorientering", + "@orientation": {}, + "orientationDetail": "Skärmorientering (kräver omstart)", + "@orientationDetail": {}, + "orientationLandscape": "Liggande", + "@orientationLandscape": {}, + "orientationPortrait": "Porträtt", + "@orientationPortrait": {}, + "orientationSystem": "System", + "@orientationSystem": {}, + "outstanding": "Utestående", + "@outstanding": {}, + "outstandingOrderDetail": "Visa utestående order", + "@outstandingOrderDetail": {}, + "overdue": "Försenad", + "@overdue": {}, + "overdueDetail": "Visa försenade ordrar", + "@overdueDetail": {}, + "packaging": "Paketering", + "@packaging": {}, + "packageName": "Paketets namn", + "@packageName": {}, + "parameters": "Parametrar", + "@parameters": {}, + "parametersSettingDetail": "Visa artikelparametrar", + "@parametersSettingDetail": {}, + "parent": "Föregående", + "@parent": {}, + "parentCategory": "Föregående Kategori", + "@parentCategory": {}, + "parentLocation": "Föregående Plats", + "@parentLocation": {}, + "part": "Artkel", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Ny Artikel", + "@partCreate": {}, + "partCreateDetail": "Skapa ny artikel i denna kategori", + "@partCreateDetail": {}, + "partEdited": "Artikel uppdaterad", + "@partEdited": {}, + "parts": "Artiklar", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Artikel inte markerad som säljbart", + "@partNotSalable": {}, + "partsNone": "Inga Artiklar", + "@partsNone": {}, + "partNoResults": "Inga artiklar som matchar sökfrågan", + "@partNoResults": {}, + "partPricing": "Artikelpris", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "partSettings": "Artikel inställningar", + "@partSettings": {}, + "partsStarred": "Prenumererade artiklar", + "@partsStarred": {}, + "partsStarredNone": "Inga stjärnmärkta artiklar tillgängliga", + "@partsStarredNone": {}, + "partSuppliers": "Artikel leverantörer", + "@partSuppliers": {}, + "partCategory": "Artikel Kategori", + "@partCategory": {}, + "partCategoryTopLevel": "Artikel kategori på toppnivå", + "@partCategoryTopLevel": {}, + "partCategories": "Artikelkategorier", + "@partCategories": {}, + "partDetails": "Artikel Detaljer", + "@partDetails": {}, + "partNotes": "Artikel Anteckningar", + "@partNotes": {}, + "partStock": "Artikellager", + "@partStock": { + "description": "part stock" + }, + "password": "Lösenord", + "@password": {}, + "passwordEmpty": "Lösenordet får inte vara tomt", + "@passwordEmpty": {}, + "pending": "Väntande", + "@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", + "@permissionRequired": {}, + "phone": "Telefon", + "@phone": {}, + "printLabel": "Skriv ut etikett", + "@printLabel": {}, + "plugin": "Plugin", + "@plugin": {}, + "pluginPrinter": "Skrivare", + "@pluginPrinter": {}, + "pluginSupport": "Stöd för tillägg aktiverat", + "@pluginSupport": {}, + "pluginSupportDetail": "Servern stöder anpassade plugins", + "@pluginSupportDetail": {}, + "printLabelFailure": "Utskrift av etiketter misslyckades", + "@printLabelFailure": {}, + "printLabelSuccess": "Etikett skickad till skrivare", + "@printLabelSuccess": {}, + "profile": "Profil", + "@profile": {}, + "profileAdd": "Lägg till serverprofil", + "@profileAdd": {}, + "profileConnect": "Anslut till server", + "@profileConnect": {}, + "profileEdit": "Redigera Server profil", + "@profileEdit": {}, + "profileDelete": "Radera serverprofil", + "@profileDelete": {}, + "profileLogout": "Utloggning profil", + "@profileLogout": {}, + "profileName": "Profilnamn", + "@profileName": {}, + "profileNone": "Inga profiler tillgängliga", + "@profileNone": {}, + "profileNotSelected": "Ingen profil vald", + "@profileNotSelected": {}, + "profileSelect": "Välj InvenTree Server", + "@profileSelect": {}, + "profileSelectOrCreate": "Välj server eller skapa en ny profil", + "@profileSelectOrCreate": {}, + "profileTapToCreate": "Tryck för att skapa eller välj en profil", + "@profileTapToCreate": {}, + "projectCode": "Projektkod", + "@projectCode": {}, + "purchaseOrderConfirmScan": "Bekräfta skanningsdata", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Bekräfta detaljer när du skannar in objekt", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Aktivera inköpsordrar", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Aktivera funktionalitet för inköpsordrar", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Genväg för kamera", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Aktivera genväg för bilduppladdning vid inköpsorder", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Inköpsorder", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Ny inköpsorder", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Redigera inköpsorder", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Inställningar för inköpsorder", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Inköpsorder", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Inköpsorder uppdaterad", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Inköpspris", + "@purchasePrice": {}, + "quantity": "Antal", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Tillgängligt antal", + "@quantityAvailable": {}, + "quantityEmpty": "Antal är tomt", + "@quantityEmpty": {}, + "quantityInvalid": "Antalet är ogiltigt", + "@quantityInvalid": {}, + "quantityPositive": "Antal måste vara positiv", + "@quantityPositive": {}, + "queryEmpty": "Ange sökfråga", + "@queryEmpty": {}, + "queryNoResults": "Inga resultat hittades", + "@queryNoResults": {}, + "received": "Mottaget", + "@received": {}, + "receivedFilterDetail": "Visa mottagna artiklar", + "@receivedFilterDetail": {}, + "receiveItem": "Ta emot artikel", + "@receiveItem": {}, + "receivedItem": "Mottagen lagerartikel", + "@receivedItem": {}, + "reference": "Referens", + "@reference": {}, + "refresh": "Uppdatera", + "@refresh": {}, + "rotateClockwise": "Rotera 90° medurs", + "@rotateClockwise": {}, + "refreshing": "Uppdaterar", + "@refreshing": {}, + "rejected": "Avvisad", + "@rejected": {}, + "releaseNotes": "Utgivningsnoteringar", + "@releaseNotes": {}, + "remove": "Ta bort", + "@remove": { + "description": "remove" + }, + "removeStock": "Ta bort lager", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Rapportera bugg", + "@reportBug": {}, + "reportBugDescription": "Skicka in felrapport (kräver GitHub-konto)", + "@reportBugDescription": {}, + "responsible": "Ansvarig", + "@responsible": {}, + "results": "Resultat", + "@results": {}, + "request": "Begäran", + "@request": {}, + "requestFailed": "Begäran misslyckades", + "@requestFailed": {}, + "requestSuccessful": "Begäran lyckades", + "@requestSuccessful": {}, + "requestingData": "Begär data", + "@requestingData": {}, + "required": "Krävs", + "@required": { + "description": "This field is required" + }, + "response400": "Felaktig begäran", + "@response400": {}, + "response401": "Ej autentiserad", + "@response401": {}, + "response403": "Åtkomst nekad", + "@response403": {}, + "response404": "Resursen hittades inte", + "@response404": {}, + "response405": "Metoden är inte tillåten", + "@response405": {}, + "response429": "För många förfrågningar", + "@response429": {}, + "response500": "Internt serverfel", + "@response500": {}, + "response501": "Ej implementerat", + "@response501": {}, + "response502": "Felaktig Gateway", + "@response502": {}, + "response503": "Tjänsten är inte tillgänglig", + "@response503": {}, + "response504": "Gateway Timeout", + "@response504": {}, + "response505": "HTTP-versionen stöds inte", + "@response505": {}, + "responseData": "Svarsdata", + "@responseData": {}, + "responseInvalid": "Ogiltig svarskod", + "@responseInvalid": {}, + "responseUnknown": "Okänt svar", + "@responseUnknown": {}, + "result": "Resultat", + "@result": { + "description": "" + }, + "returned": "Returnerad", + "@returned": {}, + "salesOrder": "Försäljningsorder", + "@salesOrder": {}, + "salesOrders": "Försäljningsordrar", + "@salesOrders": {}, + "salesOrderEnable": "Aktivera försäljningsordrar", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Aktivera funktionen för försäljningsordrar", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Genväg till kamera", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Aktivera genväg för bilduppladdning för försäljningsordrar", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Inställningar för försäljningsordrar", + "@salesOrderSettings": {}, + "salesOrderCreate": "Ny försäljningsorder", + "@saleOrderCreate": {}, + "salesOrderEdit": "Redigera försäljningsorder", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Försäljningsorder uppdaterad", + "@salesOrderUpdated": {}, + "save": "Spara", + "@save": { + "description": "Save" + }, + "scanBarcode": "Skanna streckkod", + "@scanBarcode": {}, + "scanSupplierPart": "Scanna leverantörsartikel streckkod", + "@scanSupplierPart": {}, + "scanIntoLocation": "Skanna till plats", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Skanna det här objektet till plats", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Extern skanner", + "@scannerExternal": {}, + "scannerExternalDetail": "Använd extern skanner för att läsa streckkoder (wedge läge)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Skanna Mottagna artiklar", + "@scanReceivedParts": {}, + "search": "Sök", + "@search": { + "description": "search" + }, + "searching": "Söker", + "@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", + "@searchStock": {}, + "select": "Välj", + "@select": {}, + "selectFile": "Välj fil", + "@selectFile": {}, + "selectImage": "Välj bild", + "@selectImage": {}, + "selectLocation": "Välj en plats", + "@selectLocation": {}, + "send": "Skicka", + "@send": {}, + "serialNumber": "Serienummer", + "@serialNumber": {}, + "serialNumbers": "Serienummer", + "@serialNumbers": {}, + "server": "Server", + "@server": {}, + "serverAddress": "Serveradress", + "@serverAddress": {}, + "serverApiRequired": "Nödvändig API-version", + "@serverApiRequired": {}, + "serverApiVersion": "Server API-version", + "@serverApiVersion": {}, + "serverAuthenticationError": "Autentiseringsfel", + "@serverAuthenticationError": {}, + "serverCertificateError": "Certifikat Fel", + "@serverCertificateError": {}, + "serverCertificateInvalid": "Server HTTPS-certifikat är ogiltigt", + "@serverCertificateInvalid": {}, + "serverConnected": "Ansluten till server", + "@serverConnected": {}, + "serverConnecting": "Ansluter till server", + "@serverConnecting": {}, + "serverCouldNotConnect": "Kunde inte ansluta till servern", + "@serverCouldNotConnect": {}, + "serverEmpty": "Servernamn kan inte vara tomt", + "@serverEmpty": {}, + "serverError": "Serverfel", + "@serverError": {}, + "serverDetails": "Serverdetaljer", + "@serverDetails": {}, + "serverMissingData": "Serversvar saknar obligatoriska fält", + "@serverMissingData": {}, + "serverOld": "Gammal server version", + "@serverOld": {}, + "serverSettings": "Serverinställningar", + "@serverSettings": {}, + "serverStart": "Servern måste börja med http[s]", + "@serverStart": {}, + "settings": "Inställningar", + "@settings": {}, + "serverInstance": "Serverinstans", + "@serverInstance": {}, + "serverNotConnected": "Servern är inte ansluten", + "@serverNotConnected": {}, + "serverNotSelected": "Servern är inte vald", + "@serverNotSelected": {}, + "shipment": "Försändelse", + "@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": "Leveransdatum", + "@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", + "@sku": {}, + "sounds": "Ljud", + "@sounds": {}, + "soundOnBarcodeAction": "Spela upp ljudsignal vid streckkodsåtgärd", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Spela upp ljud vid serverfel", + "@soundOnServerError": {}, + "startDate": "Startdatum", + "@startDate": {}, + "status": "Status", + "@status": {}, + "statusCode": "Statuskod", + "@statusCode": {}, + "stock": "Lager", + "@stock": { + "description": "stock" + }, + "stockDetails": "Nuvarande lagersaldo", + "@stockDetails": {}, + "stockItem": "Lager artikel", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Lager Artiklar", + "@stockItems": {}, + "stockItemCreate": "Ny lagerartikel", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Skapa ny lagerartikel på denna plats", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Ta bort lagerartikel", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Är du säker du vill ta bort denna lagerartikel?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Kunde inte ta bort lagerartikel", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Lagerartikel borttagen", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Lagerhistorik", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Visa historisk lagerspårningsinformation", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Lagerartikel överförd", + "@stockItemTransferred": {}, + "stockItemUpdated": "Lagerartikel uppdaterad", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Inga lagerartiklar tillgängliga", + "@stockItemsNotAvailable": {}, + "stockItemNotes": "Lagerartiklar Anteckningar", + "@stockItemNotes": {}, + "stockItemUpdateSuccess": "Lagerartikel uppdaterad", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "Lagerartikelns uppdatering misslyckades", + "@stockItemUpdateFailure": {}, + "stockLocation": "Lagerplats", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "Lagerplatser", + "@stockLocations": {}, + "stockTopLevel": "Högsta nivå lagerplats", + "@stockTopLevel": {}, + "strictHttps": "Använd strikt HTTPS", + "@strictHttps": {}, + "strictHttpsDetails": "Tvinga strikt kontroll av HTTPs certifikat", + "@strictHttpsDetails": {}, + "subcategory": "Underkategori", + "@subcategory": {}, + "subcategories": "Underkategorier", + "@subcategories": {}, + "sublocation": "Underplacering", + "@sublocation": {}, + "sublocations": "Underplaceringar", + "@sublocations": {}, + "sublocationNone": "Inga Underplaceringar", + "@sublocationNone": {}, + "sublocationNoneDetail": "Inga underplaceringar tillgängliga", + "@sublocationNoneDetail": {}, + "submitFeedback": "Skicka Feedback", + "@submitFeedback": {}, + "suppliedParts": "Levererade delar", + "@suppliedParts": {}, + "supplier": "Leverantör", + "@supplier": {}, + "supplierPart": "Leverantörsartikel", + "@supplierPart": {}, + "supplierPartEdit": "Redigera leverantörsartikel", + "@supplierPartEdit": {}, + "supplierPartNumber": "Leverantör Artikel Nummer", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Leverantör artikel nummer uppdaterad", + "@supplierPartUpdated": {}, + "supplierParts": "Leverantörsartikel", + "@supplierParts": {}, + "suppliers": "Leverantörer", + "@suppliers": {}, + "supplierReference": "Leverantörens referens", + "@supplierReference": {}, + "switchCamera": "Byt Kamera", + "@switchCamera": {}, + "takePicture": "Ta bild", + "@takePicture": {}, + "targetDate": "Måldatum", + "@targetDate": {}, + "templatePart": "Huvudmall Artikel", + "@templatePart": {}, + "testName": "Test namn", + "@testName": {}, + "testPassedOrFailed": "Test passerat eller misslyckats", + "@testPassedOrFailed": {}, + "testsRequired": "Tester som krävs", + "@testsRequired": {}, + "testResults": "Testresultat", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Visa testresultat för lagerposten", + "@testResultsDetail": {}, + "testResultAdd": "Lägg till testresultat", + "@testResultAdd": {}, + "testResultNone": "Inga testresultat", + "@testResultNone": {}, + "testResultNoneDetail": "Inga tillgängliga testresultat", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Fel vid uppladdning av testresultat", + "@testResultUploadFail": {}, + "testResultUploadPass": "Testresultat uppladdat", + "@testResultUploadPass": {}, + "timeout": "Överskriden tidsgräns", + "@timeout": { + "description": "" + }, + "toggleTorch": "Aktivera lampa", + "@toggleTorch": {}, + "tokenError": "Token fel", + "@tokenError": {}, + "tokenMissing": "Token saknas", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Åtkomsttoken saknas från svar", + "@tokenMissingFromResponse": {}, + "totalPrice": "Totalpris", + "@totalPrice": {}, + "trackingNumber": "Sändningsnummer", + "@trackingNumber": {}, + "transfer": "Överföring", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Överföra lager", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Flytta objekt till en annan plats", + "@transferStockDetail": {}, + "transferStockLocation": "Flytta lagerplats", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Flytta denna lagerplats till en annan", + "@transferStockLocationDetail": {}, + "translate": "Översätt", + "@translate": {}, + "translateHelp": "Hjälp till att översätta appen InvenTree", + "@translateHelp": {}, + "unavailable": "Ej tillgänglig", + "@unavailable": {}, + "unavailableDetail": "Objektet är inte tillgängligt", + "@unavailableDetail": {}, + "unitPrice": "Enhetspris", + "@unitPrice": {}, + "units": "Enheter", + "@units": {}, + "unknownResponse": "Okänt svar", + "@unknownResponse": {}, + "upload": "Ladda Upp", + "@upload": {}, + "uploadFailed": "Det gick inte att ladda upp filen", + "@uploadFailed": {}, + "uploadSuccess": "Fil har laddats upp", + "@uploadSuccess": {}, + "uploadImage": "Ladda upp bild", + "@uploadImage": {}, + "usedIn": "Används i", + "@usedIn": {}, + "usedInDetails": "Sammanställning som kräver denna artikel", + "@usedInDetails": {}, + "username": "Användarnamn", + "@username": {}, + "usernameEmpty": "Användarnamn kan inte vara tomt", + "@usernameEmpty": {}, + "value": "Värde", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "Du måste ange ett värde", + "@valueCannotBeEmpty": {}, + "valueRequired": "Värde krävs", + "@valueRequired": {}, + "variants": "Varianter", + "@variants": {}, + "version": "Version", + "@version": {}, + "viewSupplierPart": "Visa leverantörsartikel", + "@viewSupplierPart": {}, + "website": "Webbplats", + "@website": {}, + "yes": "Ja", + "@yes": {}, + "price": "Pris", + "@price": {}, + "priceRange": "Prisintervall", + "@priceRange": {}, + "priceOverrideMin": "Minimum Price Override", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maximum Price Override", + "@priceOverrideMax": {}, + "salePrice": "Försäljningspris", + "@salePrice": {}, + "saleHistory": "Sale History", + "@saleHistory": {}, + "supplierPricing": "Leverantörspriser", + "@supplierPricing": {}, + "bomCost": "BOM Cost", + "@bomCost": {}, + "internalCost": "Internal Cost", + "@internalCost": {}, + "variantCost": "Variant Cost", + "@variantCost": {}, + "overallPricing": "Overall Pricing", + "@overallPricing": {}, + "pricingOverrides": "Pricing Overrides", + "@pricingOverrides": {}, + "currency": "Valuta", + "@currency": {}, + "priceBreaks": "Price Breaks", + "@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 new file mode 100644 index 0000000..ada0c69 --- /dev/null +++ b/lib/l10n/th_TH/app_th_TH.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "th", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "ตกลง", + "@ok": { + "description": "OK" + }, + "about": "เกี่ยวกับ", + "@about": {}, + "accountDetails": "รายละเอียดบัญชีผู้ใช้", + "@accountDetails": {}, + "actions": "การดำเนินการ", + "@actions": { + "description": "" + }, + "actionsNone": "No actions available", + "@actionsNone": {}, + "add": "เพิ่ม", + "@add": { + "description": "add" + }, + "addStock": "เพิ่มสต็อก", + "@addStock": { + "description": "add stock" + }, + "address": "ที่อยู่", + "@address": {}, + "appAbout": "เกี่ยวกับ Inventree", + "@appAbout": {}, + "appCredits": "Additional app credits", + "@appCredits": {}, + "appDetails": "รายละเอียดของแอพพลิเคชั่น", + "@appDetails": {}, + "allocated": "แบ่ง", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "จัดสรรคลัง", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "แสดงข้อมูลรุ่นของโปรแกรม", + "@appReleaseNotes": {}, + "appSettings": "การตั้งค่าแอปพลิเคชั่น", + "@appSettings": {}, + "appSettingsDetails": "การตั้งค่าแอพ Inventree", + "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "ไฟล์แนบ", + "@attachments": {}, + "attachImage": "แนบรูปภาพ", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "ไม่พบไฟล์แนบ", + "@attachmentNone": {}, + "attachmentNoneDetail": "ไม่พบไฟล์แนบ", + "@attachmentNoneDetail": {}, + "attachmentSelect": "เลือกไฟล์แนบ", + "@attachmentSelect": {}, + "attention": "โปรดทราบ", + "@attention": {}, + "available": "พร้อมใช้งาน", + "@available": {}, + "availableStock": "สต็อกที่มีจำหน่าย", + "@availableStock": {}, + "barcodes": "บาร์โค้ด", + "@barcodes": {}, + "barcodeSettings": "ตั้งค่า บาร์โค้ด", + "@barcodeSettings": {}, + "barcodeAssign": "กำหนดบาร์โค้ด", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Scan custom barcode to assign", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "บาร์โค้ดที่กำหนดแล้ว", + "@barcodeAssigned": {}, + "barcodeError": "สแกนบาร์โค้ดผิดพลาด", + "@barcodeError": {}, + "barcodeInUse": "", + "@barcodeInUse": {}, + "barcodeMissingHash": "Barcode hash data missing from response", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "ไม่พบข้อมูลบาร์โค้ด", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Barcode not assigned", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "สแกนบาร์โค้ด", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Scan barcode to receive part", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "หยุดการสแกนบาร์โค้ด", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap 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": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "cameraInternal": "Internal Camera", + "@cameraInternal": {}, + "cameraInternalDetail": "Use internal camera to read barcodes", + "@cameraInternalDetail": {}, + "cancel": "Cancel", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "", + "@cancelOrder": {}, + "category": "Category", + "@category": {}, + "categoryCreate": "New Category", + "@categoryCreate": {}, + "categoryCreateDetail": "Create new part category", + "@categoryCreateDetail": {}, + "categoryUpdated": "Part category updated", + "@categoryUpdated": {}, + "company": "Company", + "@company": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@companyEdit": {}, + "companyNoResults": "No companies matching query", + "@companyNoResults": {}, + "companyUpdated": "Company details updated", + "@companyUpdated": {}, + "companies": "Companies", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Configure server settings", + "@configureServer": {}, + "confirmScan": "Confirm Transfer", + "@confirmScan": {}, + "confirmScanDetail": "Confirm stock transfer details when scanning barcodes", + "@confirmScanDetail": {}, + "connectionRefused": "Connection Refused", + "@connectionRefused": {}, + "count": "Count", + "@count": { + "description": "Count" + }, + "countStock": "Count Stock", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Credits", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "Customer", + "@customer": {}, + "customers": "Customers", + "@customers": {}, + "customerReference": "Customer Reference", + "@customerReference": {}, + "damaged": "Damaged", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "Dark Mode", + "@darkMode": {}, + "darkModeEnable": "Enable dark mode", + "@darkModeEnable": {}, + "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": { + "description": "details" + }, + "documentation": "Documentation", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "Downloading File", + "@downloading": {}, + "edit": "Edit", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "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": {}, + "email": "Email", + "@email": {}, + "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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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", + "@home": {}, + "homeScreen": "Home Screen", + "@homeScreen": {}, + "homeScreenSettings": "Configure home screen settings", + "@homeScreenSettings": {}, + "homeShowPo": "Show Purchase Orders", + "@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", + "@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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "Issue", + "@issue": {}, + "issueDate": "Issue Date", + "@issueDate": {}, + "issueOrder": "Issue Order", + "@issueOrder": {}, + "itemInLocation": "Item already in location", + "@itemInLocation": {}, + "itemDeleted": "Item has been removed", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "Keywords", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "Label Printing", + "@labelPrinting": {}, + "labelPrintingDetail": "Enable label printing", + "@labelPrintingDetail": {}, + "labelTemplate": "Label Template", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "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": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Manufacturer Part Number", + "@manufacturerPartNumber": {}, + "manufacturer": "Manufacturer", + "@manufacturer": {}, + "manufacturers": "Manufacturers", + "@manufacturers": {}, + "missingData": "Missing Data", + "@missingData": {}, + "name": "Name", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "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": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "Your account does not have the required permissions to perform this action", + "@permissionAccountDenied": {}, + "permissionRequired": "Permission Required", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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", + "@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": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "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": {}, + "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", + "@sku": {}, + "sounds": "Sounds", + "@sounds": {}, + "soundOnBarcodeAction": "Play audible tone on barcode action", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Play audible tone on server error", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Token Error", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..9f6b03f --- /dev/null +++ b/lib/l10n/tr_TR/app_tr_TR.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "tr", + "appTitle": "InvenTree", + "@appTitle": { + "description": "InvenTree application title string" + }, + "ok": "TAMAM", + "@ok": { + "description": "OK" + }, + "about": "Hakkında", + "@about": {}, + "accountDetails": "Hesap Ayrıntıları", + "@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": "Ek uygulama kredileri", + "@appCredits": {}, + "appDetails": "Uygulama Ayrıntıları", + "@appDetails": {}, + "allocated": "Tahsis Edildi", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Kare (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Stoku Tahsis Et", + "@allocateStock": {}, + "allocatedStock": "Tahsis Edilen Stok", + "@allocatedStock": {}, + "appReleaseNotes": "Uygulama yayınlama notlarını görüntüle", + "@appReleaseNotes": {}, + "appSettings": "Uygulama Ayarları", + "@appSettings": {}, + "appSettingsDetails": "Uygulama ayarlarından yapılandır", + "@appSettingsDetails": {}, + "assignedToMe": "Bana Atanmış", + "@assignedToMe": {}, + "assignedToMeDetail": "Bana Atanan Emirleri Göster", + "@assignedToMeDetail": {}, + "attachments": "Ekler", + "@attachments": {}, + "attachImage": "Görsel Ekle", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Hiçbir ek bulunamadı", + "@attachmentNone": {}, + "attachmentNoneDetail": "Hiçbir ek bulunamadı", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Ek seçin", + "@attachmentSelect": {}, + "attention": "Dikkat", + "@attention": {}, + "available": "Mevcut", + "@available": {}, + "availableStock": "Stokta hazır", + "@availableStock": {}, + "barcodes": "Barkodlar", + "@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ı", + "@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": {}, + "barcodeScanPart": "Parça barkodnu tara", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Parçayı teslim almak için barkodu tarayın", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Barkod tarama duraklatıldı", + "@barodeScanPaused": {}, + "barcodeScanPause": "Taramayı duraklatmak için dokunun", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Atanmış barkodu tara", + "@barcodeScanAssign": {}, + "barcodeScanController": "Tarayıcı Girişi", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Barkod tarayıcı girdi kaynağını seç", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Barkod Tarama Gecikmesi", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Barkod taramaları arasındaki gecikme", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Bir InvenTree barkodu tara", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Stok kalemlerini bu konumun içine tara", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Stok konumu tara", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Tekli Tarama modu", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Her tarama sonrasında barkod tarayıcıyı duraklat", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Konuma tarandı", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Madde taranmış değil", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Stok kalemi tara", + "@barcodeScanItem": {}, + "barcodeTones": "Barkod Tonları", + "@barcodeTones": {}, + "barcodeUnassign": "Atanmamış barkod", + "@barcodeUnassign": {}, + "barcodeUnknown": "Barkod tanınmadı", + "@barcodeUnknown": {}, + "batchCode": "Grup kodu", + "@batchCode": {}, + "billOfMaterials": "Ürün Ağacı", + "@billOfMaterials": {}, + "bom": "BOM", + "@bom": {}, + "bomEnable": "Ürün Ağacını Görüntüle", + "@bomEnable": {}, + "build": "Üret", + "@build": {}, + "building": "Üretiliyor", + "@building": {}, + "cameraCreationError": "Kamera Kontrolcüsü Açılamadı", + "@cameraCreationError": {}, + "cameraInternal": "Dahili Kamera", + "@cameraInternal": {}, + "cameraInternalDetail": "Barkodları okumak için dahili kamera kullan", + "@cameraInternalDetail": {}, + "cancel": "İptal", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Siparişi İptal Et", + "@cancelOrder": {}, + "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": {}, + "companyAdd": "Şirket Ekle", + "@companyAdd": {}, + "companyEdit": "Şirketi Düzenle", + "@companyEdit": {}, + "companyNoResults": "Sorguyla eşleşen şirket yok", + "@companyNoResults": {}, + "companyUpdated": "Şirket bilgileri güncellendi", + "@companyUpdated": {}, + "companies": "Şirketler", + "@companies": {}, + "complete": "Tamamlandı", + "@complete": {}, + "completeOrder": "Siparişi Tamamla", + "@completeOrder": {}, + "completionDate": "Tamamlanma Tarihi", + "@completionDate": {}, + "configureServer": "Sunucu ayarlarınızı yapılandırın", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Stok sayımı", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Katkıda Bulunanlar", + "@credits": {}, + "crop": "Kırp", + "@crop": {}, + "cropImage": "Görseli Kırp", + "@cropImage": {}, + "customer": "Müşteri", + "@customer": {}, + "customers": "Müşteriler", + "@customers": {}, + "customerReference": "Müşteri Referansı", + "@customerReference": {}, + "damaged": "Hasarlı", + "@damaged": {}, + "colorScheme": "Renk Şeması", + "@colorScheme": {}, + "colorSchemeDetail": "Renk Şeması Seç", + "@colorSchemeDetail": {}, + "darkMode": "Koyu Tema", + "@darkMode": {}, + "darkModeEnable": "Koyu temayı etkinleştir", + "@darkModeEnable": {}, + "delete": "Sil", + "@delete": {}, + "deleteFailed": "Silme işlemi başarısız", + "@deleteFailed": {}, + "deleteImageConfirmation": "Bu görseli silmek istediğinize emin misiniz?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Görseli Sil", + "@deleteImageTooltip": {}, + "deleteImage": "Görseli 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": "Teslim Tarihi", + "@deliveryDate": {}, + "description": "Açıklama", + "@description": {}, + "destination": "Hedef", + "@destination": {}, + "destroyed": "Yok edildi", + "@destroyed": {}, + "details": "Ayrıntılar", + "@details": { + "description": "details" + }, + "documentation": "Dökümantasyon", + "@documentation": {}, + "downloadComplete": "İndirme Tamamlandı", + "@downloadComplete": {}, + "downloadError": "Görsel indirme hatası", + "@downloadError": {}, + "downloading": "Dosya indiriliyor", + "@downloading": {}, + "edit": "Düzenle", + "@edit": { + "description": "edit" + }, + "editAttachment": "Eki Düzenle", + "@editAttachment": {}, + "editCategory": "Kategoriyi düzenle", + "@editCategory": {}, + "editLocation": "Konumu Düzenle", + "@editLocation": {}, + "editNotes": "Notları Düzenle", + "@editNotes": {}, + "editParameter": "Parametre Düzenle", + "@editParameter": {}, + "editPart": "Parçayı Düzenle", + "@editPart": { + "description": "edit part" + }, + "editItem": "Stok kalemi düzenle", + "@editItem": {}, + "editLineItem": "Satırı Düzenle", + "@editLineItem": {}, + "email": "E-posta", + "@email": {}, + "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": {}, + "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", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Anonim olarak hata ve log yükle", + "@errorReportUploadDetails": {}, + "expiryDate": "Son Kullanma Tarihi", + "@expiryDate": {}, + "expiryExpired": "Süresi doldu", + "@expiryExpired": {}, + "expiryStale": "Eskimiş", + "@expiryStale": {}, + "extraLineItem": "Ek Kalem", + "@extraLineItem": {}, + "extraLineItems": "Ek Kalemler", + "@extraLineItems": {}, + "feedback": "Geri Bildirim", + "@feedback": {}, + "feedbackError": "Geribildirim gönderme hatası", + "@feedbackError": {}, + "feedbackSuccess": "Geri bildirim gönderildi", + "@feedbackSuccess": {}, + "filterActive": "Aktif", + "@filterActive": {}, + "filterActiveDetail": "Aktif parçaları 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": {}, + "filterExternal": "Harici", + "@filterExternal": {}, + "filterExternalDetail": "Stoku harici konumlarda göster", + "@filterExternalDetail": {}, + "filterInStock": "Stokta mevcut", + "@filterInStock": {}, + "filterInStockDetail": "Stoku olan parçaları göster", + "@filterInStockDetail": {}, + "filterSerialized": "Sıralandırılmış", + "@filterSerialized": {}, + "filterSerializedDetail": "Seri numaralı stok kalemlerini göster", + "@filterSerializedDetail": {}, + "filterTemplate": "Şablon", + "@filterTemplate": {}, + "filterTemplateDetail": "Şablon parçaları göster", + "@filterTemplateDetail": {}, + "filterTrackable": "Takip edilebilir", + "@filterTrackable": {}, + "filterTrackableDetail": "Takip edilebilir parçaları göster", + "@filterTrackableDetail": {}, + "filterVirtual": "Sanal", + "@filterVirtual": {}, + "filterVirtualDetail": "Sanal parçaları göster", + "@filterVirtualDetail": {}, + "filteringOptions": "Süzgeç Seçenekleri", + "@filteringOptions": {}, + "formatException": "Biçim İstisnası", + "@formatException": {}, + "formatExceptionJson": "JSON veri format istisnası", + "@formatExceptionJson": {}, + "formError": "Form hatası", + "@formError": {}, + "history": "Geçmiş", + "@history": { + "description": "history" + }, + "home": "Ana Sayfa", + "@home": {}, + "homeScreen": "Ana Ekran", + "@homeScreen": {}, + "homeScreenSettings": "Ana ekran ayarlarınızı yapılandırın", + "@homeScreenSettings": {}, + "homeShowPo": "Satın Alma Siparişlerini Göster", + "@homeShowPo": {}, + "homeShowPoDescription": "Satınalma sipariş butonunu ana ekranda göster", + "@homeShowPoDescription": {}, + "homeShowShipments": "Teslimatları Göster", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Bekleyen teslimatları ana ekranda göster", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Satış Siparişlerini Göster", + "@homeShowSo": {}, + "homeShowSoDescription": "Satış siparişleri tuşunu giriş ekranında göster", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Takip Edilen Parçalar", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Takip edilen parçaları ana ekranda göster", + "@homeShowSubscsribedDescription": {}, + "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": "Görsel yükleme başarısız", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Görsel yüklendi", + "@imageUploadSuccess": {}, + "inactive": "Pasif", + "@inactive": {}, + "inactiveCompany": "Bu şirket pasif olarak işaretlendi", + "@inactiveCompany": {}, + "inactiveDetail": "Bu parça pasif olarak işaretlendi", + "@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ı", + "@internalPartNumber": {}, + "info": "Bilgi", + "@info": {}, + "inProduction": "Üretimde", + "@inProduction": {}, + "inProductionDetail": "Bu stok kalemi üretimdedir", + "@inProductionDetail": {}, + "internalPart": "İç Parça", + "@internalPart": {}, + "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 Kalemi", + "@invalidStockItem": {}, + "invalidSupplierPart": "Geçersiz Tedarikçi Parçası", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Geçersiz kullanıcı adı ve şifre", + "@invalidUsernamePassword": {}, + "invoice": "Fatura", + "@invoice": {}, + "invoiceNumber": "Fatura Numarası", + "@invoiceNumber": {}, + "issue": "Sorun", + "@issue": {}, + "issueDate": "Sorun Tarihi", + "@issueDate": {}, + "issueOrder": "Sipariş Düzenle", + "@issueOrder": {}, + "itemInLocation": "Parça zaten konumda", + "@itemInLocation": {}, + "itemDeleted": "Öge kaldırıldı", + "@itemDeleted": {}, + "itemUpdated": "Ürün Güncellendi", + "@itemUpdated": {}, + "keywords": "Anahtar kelimeler", + "@keywords": {}, + "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ı etkinleştir", + "@labelPrintingDetail": {}, + "labelTemplate": "Etiket Şablonu", + "@labelTemplate": {}, + "labelSelectTemplate": "Etiket Şablonunu Seçin", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Etiket Yazıcısını Seçin", + "@labelSelectPrinter": {}, + "language": "Dil", + "@language": {}, + "languageDefault": "Varsayılan sistem dili", + "@languageDefault": {}, + "languageSelect": "Dil Seçin", + "@languageSelect": {}, + "lastStocktake": "Son Stok Sayımı", + "@lastStocktake": {}, + "lastUpdated": "Son güncelleme", + "@lastUpdated": {}, + "level": "Seviye", + "@level": {}, + "lineItemAdd": "Satır Ekle", + "@lineItemAdd": {}, + "lineItem": "Satır", + "@lineItem": {}, + "lineItems": "Satırlar", + "@lineItems": {}, + "lineItemUpdated": "Satır güncellendi", + "@lineItemUpdated": {}, + "locateItem": "Stok kalemi bul", + "@locateItem": {}, + "locateLocation": "Stok konumu bul", + "@locateLocation": {}, + "locationCreate": "Yeni Konum", + "@locationCreate": {}, + "locationCreateDetail": "Yeni stok konumu oluştur", + "@locationCreateDetail": {}, + "locationDefault": "Varsayılan Konum", + "@locationDefault": {}, + "locationNotSet": "Belirtilmiş konum yok", + "@locationNotSet": {}, + "locationUpdated": "Stok lokasyonu güncellendi", + "@locationUpdated": {}, + "login": "Giriş yap", + "@login": {}, + "loginEnter": "Giriş bilgilerinizi girin", + "@loginEnter": {}, + "loginEnterDetails": "Kullanıcı adı ve şifre kutucukları doğru doldurulmadı", + "@loginEnterDetails": {}, + "link": "Bağlantı", + "@link": {}, + "lost": "Kayıp", + "@lost": {}, + "manufacturerPart": "Parça Üreticisi", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Parça Üreticisini Düzenle", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Üretici Parça Numarası", + "@manufacturerPartNumber": {}, + "manufacturer": "Üretici", + "@manufacturer": {}, + "manufacturers": "Üreticiler", + "@manufacturers": {}, + "missingData": "Eksik Veri", + "@missingData": {}, + "name": "Adı", + "@name": {}, + "no": "Hayır", + "@no": {}, + "notApplicable": "Yok / Geçerli Değil", + "@notApplicable": {}, + "notConnected": "Bağlı değil", + "@notConnected": {}, + "notes": "Notlar", + "@notes": { + "description": "Notes" + }, + "notifications": "Bildirimler", + "@notifications": {}, + "notificationsEmpty": "Okunmamış bildirim yok", + "@notificationsEmpty": {}, + "noResponse": "Sunucudan yanıt yok", + "@noResponse": {}, + "noResults": "Sonuç Yok", + "@noResults": {}, + "noImageAvailable": "Görsel 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", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Geçersiz numara", + "@numberInvalid": {}, + "onOrder": "Siparişte", + "@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": {}, + "outstanding": "Açık", + "@outstanding": {}, + "outstandingOrderDetail": "Açık siparişleri göster", + "@outstandingOrderDetail": {}, + "overdue": "Gecikmede", + "@overdue": {}, + "overdueDetail": "Gecikmiş siparişleri göster", + "@overdueDetail": {}, + "packaging": "Paketleme", + "@packaging": {}, + "packageName": "Paket İsmi", + "@packageName": {}, + "parameters": "Parametreler", + "@parameters": {}, + "parametersSettingDetail": "Parça parametrelerini görüntüle", + "@parametersSettingDetail": {}, + "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)" + }, + "partNotSalable": "Parça satılabilir olarak işaretli değil", + "@partNotSalable": {}, + "partsNone": "Parça Yok", + "@partsNone": {}, + "partNoResults": "Sorguyla eşleşen parça yok", + "@partNoResults": {}, + "partPricing": "Parça Fiyatlandırma", + "@partPricing": {}, + "partPricingSettingDetail": "Parça fiyatlandırma bilgisini görüntüle", + "@pricingSettingDetail": {}, + "partSettings": "Parça Ayarları", + "@partSettings": {}, + "partsStarred": "Takip Edilen 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 Ayrıntıları", + "@partDetails": {}, + "partNotes": "Parça notları", + "@partNotes": {}, + "partStock": "Parça stok", + "@partStock": { + "description": "part stock" + }, + "password": "Parola", + "@password": {}, + "passwordEmpty": "Parola boş bırakılamaz", + "@passwordEmpty": {}, + "pending": "Beklemede", + "@pending": {}, + "permissionAccountDenied": "Bu eylemi gerçekleştirmek için gerekli yetkiye sahip değilsiniz", + "@permissionAccountDenied": {}, + "permissionRequired": "İzin Gerekli", + "@permissionRequired": {}, + "phone": "Telefon Numarası", + "@phone": {}, + "printLabel": "Etiket Yazdır", + "@printLabel": {}, + "plugin": "Eklenti", + "@plugin": {}, + "pluginPrinter": "Yazıcı", + "@pluginPrinter": {}, + "pluginSupport": "Eklenti Desteği Etkin", + "@pluginSupport": {}, + "pluginSupportDetail": "Sunucu özel eklentileri destekler", + "@pluginSupportDetail": {}, + "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": {}, + "profileLogout": "Hesaptan çıkış yap", + "@profileLogout": {}, + "profileName": "Profil Adı", + "@profileName": {}, + "profileNone": "Kullanılabiir profil yok", + "@profileNone": {}, + "profileNotSelected": "Profil seçilmedi", + "@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": {}, + "purchaseOrderConfirmScan": "Tarama Verisini Onayla", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Kalemleri tararken ayrıntıları onayla", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Satın Alma Siparişlerini Etkinleştir", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Satın Alma Emirlerinin İşlevselliğini Etkinleştir", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Kamera Kısayolu", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Satın alma siparişi ekranında görsel yükleme kısayolunu etkinleştir", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Satınalma Siparişi", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Yeni Satınalma Emri", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Satın Alma siparişini düzenle", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Satın Alma Emri Ayarları", + "@purchaseOrderSettings": {}, + "purchaseOrders": "Satın Alma Siparişleri", + "@purchaseOrders": {}, + "purchaseOrderUpdated": "Satın Alma Siparişi güncellendi", + "@purchaseOrderUpdated": {}, + "purchasePrice": "Alış Fiyatı", + "@purchasePrice": {}, + "quantity": "Adet", + "@quantity": { + "description": "Quantity" + }, + "quantityAvailable": "Hazır miktar", + "@quantityAvailable": {}, + "quantityEmpty": "Adet boş", + "@quantityEmpty": {}, + "quantityInvalid": "Adet geçersiz", + "@quantityInvalid": {}, + "quantityPositive": "Adet pozitif bir sayı olmalı", + "@quantityPositive": {}, + "queryEmpty": "Arama metni girin", + "@queryEmpty": {}, + "queryNoResults": "Sorgu için sonuç yok", + "@queryNoResults": {}, + "received": "Teslim Alındı", + "@received": {}, + "receivedFilterDetail": "Teslim alınan kalemleri göster", + "@receivedFilterDetail": {}, + "receiveItem": "Kalemi Teslim Al", + "@receiveItem": {}, + "receivedItem": "Teslim alınan stok kalemleri", + "@receivedItem": {}, + "reference": "Referans", + "@reference": {}, + "refresh": "Yenile", + "@refresh": {}, + "rotateClockwise": "Saat yönünde 90° Döndür", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Sorumlu", + "@responsible": {}, + "results": "Sonuçlar", + "@results": {}, + "request": "Talep", + "@request": {}, + "requestFailed": "İstek Başarısız", + "@requestFailed": {}, + "requestSuccessful": "İstek başarılı", + "@requestSuccessful": {}, + "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": {}, + "salesOrder": "Satış Siparişi", + "@salesOrder": {}, + "salesOrders": "Satış Siparişleri", + "@salesOrders": {}, + "salesOrderEnable": "Satış Siparişlerini Etkinleştir", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Satış Siparişlerinin İşlevselliğini Etkinleştir", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Kamera Kısayolu", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Satış siparişi ekranında görsel yükleme kısayolunu etkinleştir", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Satış emirleri ayarları", + "@salesOrderSettings": {}, + "salesOrderCreate": "Yeni Satış Siparişi", + "@saleOrderCreate": {}, + "salesOrderEdit": "Satış Siparişini Düzenle", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Satış siparişi güncellendi", + "@salesOrderUpdated": {}, + "save": "Kaydet", + "@save": { + "description": "Save" + }, + "scanBarcode": "Barkod Tara", + "@scanBarcode": {}, + "scanSupplierPart": "Tedarikçi parça barkodunu tara", + "@scanSupplierPart": {}, + "scanIntoLocation": "Konuma Tara", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Bu ögeyi konuma tara", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Harici Tarayıcı", + "@scannerExternal": {}, + "scannerExternalDetail": "Barkodları okumak için harici tarayıcı kullan (keyboard wedge modu)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Teslim Alınan Parçaları Tara", + "@scanReceivedParts": {}, + "search": "Ara", + "@search": { + "description": "search" + }, + "searching": "Aranıyor", + "@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", + "@searchStock": {}, + "select": "Seç", + "@select": {}, + "selectFile": "Dosya Seç", + "@selectFile": {}, + "selectImage": "Görsel Seç", + "@selectImage": {}, + "selectLocation": "Bir yer seçin", + "@selectLocation": {}, + "send": "Gönder", + "@send": {}, + "serialNumber": "Seri Numara", + "@serialNumber": {}, + "serialNumbers": "Seri Numaraları", + "@serialNumbers": {}, + "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 Ayrıntıları", + "@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": {}, + "serverNotSelected": "Sunucu bulunamadı", + "@serverNotSelected": {}, + "shipment": "Teslimat", + "@shipment": {}, + "shipments": "Gönderiler", + "@shipments": {}, + "shipmentsPending": "Bekleyen Teslimatlar", + "@shipmentsPending": {}, + "shipmentAdd": "Gönderi Ekle", + "@shipmentAdd": {}, + "shipmentCheck": "Sevkiyatı Kontrol Et", + "@shipmentCheck": {}, + "shipmentCheckDetail": "Bu sevkiyatı kontrol edildi olarak işaretle", + "@shipmentCheckDetail": {}, + "shipmentChecked": "Sevkiyat Kontrol Edildi", + "@shipmentChecked": {}, + "shipmentDate": "Teslimat Tarihi", + "@shipmentDate": {}, + "shipmentEdit": "Teslimatı Düzenle", + "@shipmentEdit": {}, + "shipmentReference": "Teslimat Referansı", + "@shipmentReference": {}, + "shipmentSend": "Teslimatı Gönder", + "@shipmentSend": {}, + "shipmentUncheck": "Sevkiyat Kontrolünü Kaldır", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "Bu teslimatı kontrol edilmedi olarak işaretle", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "Teslimat Güncellendi", + "@shipmentUpdated": {}, + "shipped": "Gönderildi", + "@shipped": {}, + "sku": "SKU", + "@sku": {}, + "sounds": "Sesler", + "@sounds": {}, + "soundOnBarcodeAction": "Barkod işleminde sesli ton çal", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Sunucu hatasında sesli ton çal", + "@soundOnServerError": {}, + "startDate": "Başlangıç Tarihi", + "@startDate": {}, + "status": "Durum", + "@status": {}, + "statusCode": "Durum Kodu", + "@statusCode": {}, + "stock": "Stok", + "@stock": { + "description": "stock" + }, + "stockDetails": "Şimdiki mevcut stok miktarı", + "@stockDetails": {}, + "stockItem": "Stok Kalemi", + "@stockItem": { + "description": "stock item title" + }, + "stockItems": "Stok Kalemleri", + "@stockItems": {}, + "stockItemCreate": "Yeni Stok Kalemi", + "@stockItemCreate": {}, + "stockItemCreateDetail": "Bu konumda yeni stok kalemi oluştur", + "@stockItemCreateDetail": {}, + "stockItemDelete": "Stok parçasını sil", + "@stockItemDelete": {}, + "stockItemDeleteConfirm": "Bu stok kalemini silmek istediğinize emin misiniz?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Stok kalemi silinemedi", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stok kalemi silindi", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stok Geçmişi", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Geçmiş stok takip bilgisini görüntüle", + "@stockItemHistoryDetail": {}, + "stockItemTransferred": "Stok kalemi aktarıldı", + "@stockItemTransferred": {}, + "stockItemUpdated": "Stok kalemi güncellendi", + "@stockItemUpdated": {}, + "stockItemsNotAvailable": "Stok kalemi bulunmamaktadır", + "@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": {}, + "strictHttps": "Katı HTTPS Kullan", + "@strictHttps": {}, + "strictHttpsDetails": "HTTPS sertifikalarını katı kontrole zorla", + "@strictHttpsDetails": {}, + "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": {}, + "supplierPart": "Tedarikçi Parçası", + "@supplierPart": {}, + "supplierPartEdit": "Tedarikçi Parçasını Düzenle", + "@supplierPartEdit": {}, + "supplierPartNumber": "Tedarikçi Parça Numarası", + "@supplierPartNumber": {}, + "supplierPartUpdated": "Tedarikçi Parçası Güncellendi", + "@supplierPartUpdated": {}, + "supplierParts": "Tedarikçi Parçaları", + "@supplierParts": {}, + "suppliers": "Tedarikçiler", + "@suppliers": {}, + "supplierReference": "Tedarikçi Referansı", + "@supplierReference": {}, + "switchCamera": "Kamerayı Değiştir", + "@switchCamera": {}, + "takePicture": "Resim Çek", + "@takePicture": {}, + "targetDate": "Hedeflenen Tarih", + "@targetDate": {}, + "templatePart": "Üst Şablon Parçası", + "@templatePart": {}, + "testName": "Test Adı", + "@testName": {}, + "testPassedOrFailed": "Test başarılı veya hatalı", + "@testPassedOrFailed": {}, + "testsRequired": "Gerekli Testler", + "@testsRequired": {}, + "testResults": "Test Sonuçları", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Stok kalemi test sonuçlarını görüntüle", + "@testResultsDetail": {}, + "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": "" + }, + "toggleTorch": "Feneri Aç/Kapat", + "@toggleTorch": {}, + "tokenError": "Token Hatası", + "@tokenError": {}, + "tokenMissing": "Eksik Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Eksik cevaptan tokena eriş", + "@tokenMissingFromResponse": {}, + "totalPrice": "Toplam Fiyat", + "@totalPrice": {}, + "trackingNumber": "Takip Numarası", + "@trackingNumber": {}, + "transfer": "Aktarım", + "@transfer": { + "description": "transfer" + }, + "transferStock": "Stok Aktar", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "Ögeyi farklı bir konuma aktar", + "@transferStockDetail": {}, + "transferStockLocation": "Stok Konumunu Aktar", + "@transferStockLocation": {}, + "transferStockLocationDetail": "Bu stok konumunu başka bir konuma aktar", + "@transferStockLocationDetail": {}, + "translate": "Çeviri", + "@translate": {}, + "translateHelp": "Çeviriye yardım et", + "@translateHelp": {}, + "unavailable": "Mevcut Değil", + "@unavailable": {}, + "unavailableDetail": "Ürün Mevcut Değil", + "@unavailableDetail": {}, + "unitPrice": "Birim Fiyat", + "@unitPrice": {}, + "units": "Birim", + "@units": {}, + "unknownResponse": "Bilinmeyen Yanıt", + "@unknownResponse": {}, + "upload": "Yükle", + "@upload": {}, + "uploadFailed": "Dosya yüklenemedi", + "@uploadFailed": {}, + "uploadSuccess": "Dosya yüklendi", + "@uploadSuccess": {}, + "uploadImage": "Görsel Yükle", + "@uploadImage": {}, + "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": {}, + "variants": "Varyantlar", + "@variants": {}, + "version": "Sürüm", + "@version": {}, + "viewSupplierPart": "Tedarikçi Parçası Görüntüle", + "@viewSupplierPart": {}, + "website": "Web sitesi", + "@website": {}, + "yes": "Evet", + "@yes": {}, + "price": "Fiyat", + "@price": {}, + "priceRange": "Fiyat Aralığı", + "@priceRange": {}, + "priceOverrideMin": "Minimum Fiyat Geçersiz Kılma", + "@priceOverrideMin": {}, + "priceOverrideMax": "Maksimum Fiyat Geçersiz Kılma", + "@priceOverrideMax": {}, + "salePrice": "Satış Fiyatı", + "@salePrice": {}, + "saleHistory": "Satış Geçmişi", + "@saleHistory": {}, + "supplierPricing": "Tedarikçi Fiyatlandırması", + "@supplierPricing": {}, + "bomCost": "BoM Maliyeti", + "@bomCost": {}, + "internalCost": "Dahili Maliyet", + "@internalCost": {}, + "variantCost": "Varyant Maliyeti", + "@variantCost": {}, + "overallPricing": "Genel Fiyatlandırma", + "@overallPricing": {}, + "pricingOverrides": "Fiyatlandırma Genel Bakış", + "@pricingOverrides": {}, + "currency": "Para Birimi", + "@currency": {}, + "priceBreaks": "Fiyat Kademeleri", + "@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 new file mode 100644 index 0000000..8201634 --- /dev/null +++ b/lib/l10n/uk_UA/app_uk_UA.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "uk", + "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": {}, + "allocated": "Виділено", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Квадрат (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "Виділити запас", + "@allocateStock": {}, + "allocatedStock": "Виділений Запас", + "@allocatedStock": {}, + "appReleaseNotes": "Показати примітки до випуску", + "@appReleaseNotes": {}, + "appSettings": "Налаштування додатку", + "@appSettings": {}, + "appSettingsDetails": "Налаштування додатку InvenTree", + "@appSettingsDetails": {}, + "assignedToMe": "Призначені мені", + "@assignedToMe": {}, + "assignedToMeDetail": "Показати замовлення, призначені мені", + "@assignedToMeDetail": {}, + "attachments": "Вкладення", + "@attachments": {}, + "attachImage": "Прикріпити зображення", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "Вкладення не знайдено", + "@attachmentNone": {}, + "attachmentNoneDetail": "Вкладення не знайдено", + "@attachmentNoneDetail": {}, + "attachmentSelect": "Виберіть вкладення", + "@attachmentSelect": {}, + "attention": "Попередження", + "@attention": {}, + "available": "Доступно", + "@available": {}, + "availableStock": "Доступний склад", + "@availableStock": {}, + "barcodes": "ШК", + "@barcodes": {}, + "barcodeSettings": "Налаштування штрих-коду", + "@barcodeSettings": {}, + "barcodeAssign": "Призначити штрих-код", + "@barcodeAssign": {}, + "barcodeAssignDetail": "Сканувати користувацький штрих-код щоб призначити", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "Код товару призначено", + "@barcodeAssigned": {}, + "barcodeError": "Помилка сканування штрих-коду", + "@barcodeError": {}, + "barcodeInUse": "Код товару вже призначений", + "@barcodeInUse": {}, + "barcodeMissingHash": "Відсутні хеш-дані штрих-коду з відповіді", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "Не знайдено відповідного штрих-коду", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "Код товару не призначений", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "Сканування штрихкоду запчастини", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Сканувати код коду, щоб отримати запчастину", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Сканування штрих-кодів призупинено", + "@barodeScanPaused": {}, + "barcodeScanPause": "Торкніться або утримуйте, щоб призупинити сканування", + "@barcodeScanPause": {}, + "barcodeScanAssign": "Сканувати щоб призначити штрих-код", + "@barcodeScanAssign": {}, + "barcodeScanController": "Сканер вводу", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "Виберіть джерело введення сканера штрих-кодів", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "Затримка сканування штрих-коду", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "Затримка між скануваннями штрих-кодів", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "Сканувати штрих-код InvenTree", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "Просканувати запас товару в це місце", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "Сканувати місце розташування запасів", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "Режим одного сканування", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "Призупинити сканер штрих-коду після кожного сканування", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "Проскановано на місце", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "Елемент не проскановано", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "Просканувати запас товару", + "@barcodeScanItem": {}, + "barcodeTones": "Штрих-коди", + "@barcodeTones": {}, + "barcodeUnassign": "Скасувати призначення штрих-коду", + "@barcodeUnassign": {}, + "barcodeUnknown": "Штрих-код не розпізнаний", + "@barcodeUnknown": {}, + "batchCode": "Пакетний код", + "@batchCode": {}, + "billOfMaterials": "Специфікація матеріалів", + "@billOfMaterials": {}, + "bom": "Список матеріалів", + "@bom": {}, + "bomEnable": "Показати специфікацію матеріалів", + "@bomEnable": {}, + "build": "Зібрати", + "@build": {}, + "building": "Збірка", + "@building": {}, + "cameraCreationError": "Не вдалося відкрити контролер камери", + "@cameraCreationError": {}, + "cameraInternal": "Вбудована камера", + "@cameraInternal": {}, + "cameraInternalDetail": "Використовувати вбудовану камеру для зчитування штрих-кодів", + "@cameraInternalDetail": {}, + "cancel": "Скасувати", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Скасувати замовлення", + "@cancelOrder": {}, + "category": "Категорія", + "@category": {}, + "categoryCreate": "Нова категорія", + "@categoryCreate": {}, + "categoryCreateDetail": "Створити нову категорію деталей", + "@categoryCreateDetail": {}, + "categoryUpdated": "Категорію частини оновлено", + "@categoryUpdated": {}, + "company": "Компанія", + "@company": {}, + "companyAdd": "Додати Компанію", + "@companyAdd": {}, + "companyEdit": "Змінити компанію", + "@companyEdit": {}, + "companyNoResults": "Немає компаній, що відповідають запиту", + "@companyNoResults": {}, + "companyUpdated": "Дані про компанію оновлено", + "@companyUpdated": {}, + "companies": "Компанії", + "@companies": {}, + "complete": "Завершити", + "@complete": {}, + "completeOrder": "Завершити замовлення", + "@completeOrder": {}, + "completionDate": "Дата завершення", + "@completionDate": {}, + "configureServer": "Налаштування сервера", + "@configureServer": {}, + "confirmScan": "Підтвердити переказ", + "@confirmScan": {}, + "confirmScanDetail": "Підтверджувати інформацію про передавання запасів під час сканування штрих-кодів", + "@confirmScanDetail": {}, + "connectionRefused": "З'єднання відхилено", + "@connectionRefused": {}, + "count": "Кількість", + "@count": { + "description": "Count" + }, + "countStock": "Кількість запасів", + "@countStock": { + "description": "Count Stock" + }, + "credits": "", + "@credits": {}, + "crop": "Обрізати", + "@crop": {}, + "cropImage": "Обрізати зображення", + "@cropImage": {}, + "customer": "Покупець", + "@customer": {}, + "customers": "", + "@customers": {}, + "customerReference": "Посилання клієнта", + "@customerReference": {}, + "damaged": "Пошкоджений", + "@damaged": {}, + "colorScheme": "Колірна схема", + "@colorScheme": {}, + "colorSchemeDetail": "Виберіть колірну схему", + "@colorSchemeDetail": {}, + "darkMode": "Темна тема", + "@darkMode": {}, + "darkModeEnable": "Увімкнути темний режим", + "@darkModeEnable": {}, + "delete": "Видалити", + "@delete": {}, + "deleteFailed": "Помилка видалення", + "@deleteFailed": {}, + "deleteImageConfirmation": "Ви дійсно хочете видалити це зображення?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "Видалити Зображення", + "@deleteImageTooltip": {}, + "deleteImage": "Видалити Зображення", + "@deleteImage": {}, + "deletePart": "Видалити деталь", + "@deletePart": {}, + "deletePartDetail": "Видалити цю частину з бази даних", + "@deletePartDetail": {}, + "deleteSuccess": "Операція видалення пройшла успішно", + "@deleteSuccess": {}, + "deliveryDate": "Дата Доставки", + "@deliveryDate": {}, + "description": "Опис", + "@description": {}, + "destination": "Місце призначення", + "@destination": {}, + "destroyed": "Знищений", + "@destroyed": {}, + "details": "Деталі", + "@details": { + "description": "details" + }, + "documentation": "Документація", + "@documentation": {}, + "downloadComplete": "Завантаження завершено", + "@downloadComplete": {}, + "downloadError": "Помилка завантаження зображення", + "@downloadError": {}, + "downloading": "Завантаження файлу", + "@downloading": {}, + "edit": "Редагувати", + "@edit": { + "description": "edit" + }, + "editAttachment": "Редагувати вкладення", + "@editAttachment": {}, + "editCategory": "Редагувати категорію", + "@editCategory": {}, + "editLocation": "Редагувати локацію", + "@editLocation": {}, + "editNotes": "Редагувати примітки", + "@editNotes": {}, + "editParameter": "Редагувати параметри", + "@editParameter": {}, + "editPart": "Редагувати деталь", + "@editPart": { + "description": "edit part" + }, + "editItem": "Редагувати позицію на складі", + "@editItem": {}, + "editLineItem": "Редагувати рядок", + "@editLineItem": {}, + "email": "Ел. пошта", + "@email": {}, + "enterPassword": "Введіть пароль", + "@enterPassword": {}, + "enterUsername": "Введіть ім'я користувача", + "@enterUsername": {}, + "error": "Помилка", + "@error": { + "description": "Error" + }, + "errorCreate": "Помилка створення запису в базі даних", + "@errorCreate": {}, + "errorDelete": "Помилка видалення запису бази даних", + "@errorDelete": {}, + "errorDetails": "Інформація про помилку", + "@errorDetails": {}, + "errorFetch": "Помилка отримання даних з сервера", + "@errorFetch": {}, + "errorUserRoles": "Помилка запиту ролей із сервера", + "@errorUserRoles": {}, + "errorPluginInfo": "Помилка запиту даних плагіна з сервера", + "@errorPluginInfo": {}, + "errorReporting": "Звіт про помилки", + "@errorReporting": {}, + "errorReportUpload": "Вивантажити звіти про помилки", + "@errorReportUpload": {}, + "errorReportUploadDetails": "Вивантажувати анонімні звіти про помилки та журнали помилок", + "@errorReportUploadDetails": {}, + "expiryDate": "Термін дії", + "@expiryDate": {}, + "expiryExpired": "Прострочено", + "@expiryExpired": {}, + "expiryStale": "Несвіже", + "@expiryStale": {}, + "extraLineItem": "Додатковий рядок у списку", + "@extraLineItem": {}, + "extraLineItems": "Додаткові рядки у списку", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "Показати серіалізовані стокові елементи", + "@filterSerializedDetail": {}, + "filterTemplate": "Шаблон", + "@filterTemplate": {}, + "filterTemplateDetail": "Показувати частини шаблонів", + "@filterTemplateDetail": {}, + "filterTrackable": "Відстежуваний", + "@filterTrackable": {}, + "filterTrackableDetail": "Показати відстежувані частини", + "@filterTrackableDetail": {}, + "filterVirtual": "Віртуальний", + "@filterVirtual": {}, + "filterVirtualDetail": "Показати віртуальні запчастини", + "@filterVirtualDetail": {}, + "filteringOptions": "Опції фільтрування", + "@filteringOptions": {}, + "formatException": "Помилка формату", + "@formatException": {}, + "formatExceptionJson": "Помилка у форматі JSON", + "@formatExceptionJson": {}, + "formError": "Помилка форми", + "@formError": {}, + "history": "Історія", + "@history": { + "description": "history" + }, + "home": "Домашня сторінка", + "@home": {}, + "homeScreen": "Домашній екран", + "@homeScreen": {}, + "homeScreenSettings": "Налаштування параметрів головного екрану", + "@homeScreenSettings": {}, + "homeShowPo": "Показати замовлення на купівлю", + "@homeShowPo": {}, + "homeShowPoDescription": "Показувати кнопку замовлення на домашньому екрані", + "@homeShowPoDescription": {}, + "homeShowShipments": "Показати відправлення", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Показати відкладені відправлення на головному екрані", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "Показати замовлення", + "@homeShowSo": {}, + "homeShowSoDescription": "Показувати кнопку замовлення на домашньому екрані", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "Підписані частини", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "Показувати підписані запчастини на головному екрані", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "Показати постачальників", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "Показати кнопку постачальників на домашньому екрані", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "Показати виробників", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "Показувати кнопку виробника на головному екрані", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "Показати покупців", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "Показувати кнопку клієнтів на головному екрані", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "Не вдалося завантажити зображення", + "@imageUploadFailure": {}, + "imageUploadSuccess": "Зображення завантажено", + "@imageUploadSuccess": {}, + "inactive": "Неактивний", + "@inactive": {}, + "inactiveCompany": "Ця компанія позначена як неактивна", + "@inactiveCompany": {}, + "inactiveDetail": "Ця частина позначена як неактивна", + "@inactiveDetail": {}, + "includeSubcategories": "Включити підкатегорії", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "Показати результати з підкатегорій", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "Включати під-локації", + "@includeSublocations": {}, + "includeSublocationsDetail": "Показати результати з під-локацій", + "@includeSublocationsDetail": {}, + "incompleteDetails": "Неповні дані профілю", + "@incompleteDetails": {}, + "internalPartNumber": "Внутрішній номер позиції", + "@internalPartNumber": {}, + "info": "Інфо", + "@info": {}, + "inProduction": "У виробництві", + "@inProduction": {}, + "inProductionDetail": "Ця позиція у виробництві", + "@inProductionDetail": {}, + "internalPart": "Внутрішня частина", + "@internalPart": {}, + "invalidHost": "Невірна назва хосту", + "@invalidHost": {}, + "invalidHostDetails": "Вказане ім'я хосту недійсне", + "@invalidHostDetails": {}, + "invalidPart": "Некоректна частина", + "@invalidPart": {}, + "invalidPartCategory": "Неправильна категорія деталі", + "@invalidPartCategory": {}, + "invalidStockLocation": "Недійсне розташування запасів", + "@invalidStockLocation": {}, + "invalidStockItem": "Недійсна складська позиція", + "@invalidStockItem": {}, + "invalidSupplierPart": "Некоректний постачальник", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "Неправильна комбінація імені користувача та пароля", + "@invalidUsernamePassword": {}, + "invoice": "Інвойс", + "@invoice": {}, + "invoiceNumber": "Номер Інвойсу", + "@invoiceNumber": {}, + "issue": "Видача", + "@issue": {}, + "issueDate": "Дата Видачі", + "@issueDate": {}, + "issueOrder": "Оформити Замовлення", + "@issueOrder": {}, + "itemInLocation": "Товар вже на місці", + "@itemInLocation": {}, + "itemDeleted": "Елемент було видалено", + "@itemDeleted": {}, + "itemUpdated": "Запис оновлено", + "@itemUpdated": {}, + "keywords": "Ключові слова", + "@keywords": {}, + "labelDriver": "Драйвер Етикеток", + "@labelDriver": {}, + "labelSelectDriver": "Вибрати Драйвер Принтера Етикеток", + "@labelSelectDriver": {}, + "labelPrinting": "Друк Ярликів", + "@labelPrinting": {}, + "labelPrintingDetail": "Увімкнути друк ярликів", + "@labelPrintingDetail": {}, + "labelTemplate": "Шаблон Ярлика", + "@labelTemplate": {}, + "labelSelectTemplate": "Вибрати Шаблон Етикетки", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Вибрати Принтер Етикеток", + "@labelSelectPrinter": {}, + "language": "Мова", + "@language": {}, + "languageDefault": "Типова мова системи", + "@languageDefault": {}, + "languageSelect": "Вибір мови", + "@languageSelect": {}, + "lastStocktake": "Остання інвентаризація", + "@lastStocktake": {}, + "lastUpdated": "Останнє оновлення", + "@lastUpdated": {}, + "level": "Рівень", + "@level": {}, + "lineItemAdd": "Додати Позицію", + "@lineItemAdd": {}, + "lineItem": "Позиція", + "@lineItem": {}, + "lineItems": "Позиції", + "@lineItems": {}, + "lineItemUpdated": "Позицію оновлено", + "@lineItemUpdated": {}, + "locateItem": "Знайти елемент запасів", + "@locateItem": {}, + "locateLocation": "Знайти розташування запасів", + "@locateLocation": {}, + "locationCreate": "Нове розташування", + "@locationCreate": {}, + "locationCreateDetail": "Створити нове розташування на складі", + "@locationCreateDetail": {}, + "locationDefault": "Розташування за замовчуванням", + "@locationDefault": {}, + "locationNotSet": "Розташування не вказано", + "@locationNotSet": {}, + "locationUpdated": "Розташування запасів оновлено", + "@locationUpdated": {}, + "login": "Увійти", + "@login": {}, + "loginEnter": "Введіть дані для входу", + "@loginEnter": {}, + "loginEnterDetails": "Ім'я користувача та пароль не зберігаються локально", + "@loginEnterDetails": {}, + "link": "Посилання", + "@link": {}, + "lost": "Втрачено", + "@lost": {}, + "manufacturerPart": "Виробник деталі", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Редагувати виробника деталі", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "Номер позиції виробника", + "@manufacturerPartNumber": {}, + "manufacturer": "Виробник", + "@manufacturer": {}, + "manufacturers": "Виробники", + "@manufacturers": {}, + "missingData": "Відсутні дані", + "@missingData": {}, + "name": "Назва", + "@name": {}, + "no": "Ні", + "@no": {}, + "notApplicable": "Н/Д", + "@notApplicable": {}, + "notConnected": "Не під’єднано", + "@notConnected": {}, + "notes": "Нотатки", + "@notes": { + "description": "Notes" + }, + "notifications": "Сповіщення", + "@notifications": {}, + "notificationsEmpty": "Непрочитані сповіщення відсутні", + "@notificationsEmpty": {}, + "noResponse": "Немає відповіді від сервера", + "@noResponse": {}, + "noResults": "Нічого не знайдено", + "@noResults": {}, + "noImageAvailable": "Немає доступного зображення", + "@noImageAvailable": {}, + "noPricingAvailable": "Ціни не вказано", + "@noPricingAvailable": {}, + "noPricingDataFound": "Для цієї деталі не знайдено даних про ціну", + "@noPricingDataFound": {}, + "noSubcategories": "Немає Підкатегорій", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "Немає доступних підкатегорій", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "Некоректний номер", + "@numberInvalid": {}, + "onOrder": "У замовленні", + "@onOrder": {}, + "onOrderDetails": "Позиції в поточних замовленнях", + "@onOrderDetails": {}, + "orientation": "Орієнтація екрана", + "@orientation": {}, + "orientationDetail": "Орієнтація екрана (потребує перезапуску)", + "@orientationDetail": {}, + "orientationLandscape": "Альбомна орієнтація", + "@orientationLandscape": {}, + "orientationPortrait": "Портретна орієнтація екрану", + "@orientationPortrait": {}, + "orientationSystem": "Орієнтація задана системою", + "@orientationSystem": {}, + "outstanding": "Відмінно", + "@outstanding": {}, + "outstandingOrderDetail": "Показати незавершені замовлення", + "@outstandingOrderDetail": {}, + "overdue": "Протерміновані", + "@overdue": {}, + "overdueDetail": "Показати протерміновані замовлення", + "@overdueDetail": {}, + "packaging": "Пакування", + "@packaging": {}, + "packageName": "Назва пакету", + "@packageName": {}, + "parameters": "Параметри", + "@parameters": {}, + "parametersSettingDetail": "Показувати параметри частини", + "@parametersSettingDetail": {}, + "parent": "Батьківський елемент", + "@parent": {}, + "parentCategory": "Батьківська категорія", + "@parentCategory": {}, + "parentLocation": "Батьківська локація", + "@parentLocation": {}, + "part": "Позиція", + "@part": { + "description": "Part (single)" + }, + "partCreate": "Нова позиція", + "@partCreate": {}, + "partCreateDetail": "Створити нову категорію деталей", + "@partCreateDetail": {}, + "partEdited": "Позиція оновлена", + "@partEdited": {}, + "parts": "Позиції", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "Позиція не позначена як торгова", + "@partNotSalable": {}, + "partsNone": "Немає позицій", + "@partsNone": {}, + "partNoResults": "Немає позицій відповідних запиту", + "@partNoResults": {}, + "partPricing": "Ціна деталі", + "@partPricing": {}, + "partPricingSettingDetail": "Відображати інформацію про ціни на деталь", + "@pricingSettingDetail": {}, + "partSettings": "Налаштування позиції", + "@partSettings": {}, + "partsStarred": "Підписані позиції", + "@partsStarred": {}, + "partsStarredNone": "Немає вибраних позицій", + "@partsStarredNone": {}, + "partSuppliers": "Постачальники позиції", + "@partSuppliers": {}, + "partCategory": "Категорія деталей", + "@partCategory": {}, + "partCategoryTopLevel": "Категорія деталей вищого рівня", + "@partCategoryTopLevel": {}, + "partCategories": "Категорії позицій", + "@partCategories": {}, + "partDetails": "Подробиці позиції", + "@partDetails": {}, + "partNotes": "Примітки до позиції", + "@partNotes": {}, + "partStock": "Наявність На Складі", + "@partStock": { + "description": "part stock" + }, + "password": "Пароль", + "@password": {}, + "passwordEmpty": "Пароль не може бути порожнім", + "@passwordEmpty": {}, + "pending": "В очікуванні", + "@pending": {}, + "permissionAccountDenied": "Ваш обліковий запис не має необхідних прав для виконання цієї дії", + "@permissionAccountDenied": {}, + "permissionRequired": "Потрібен дозвіл", + "@permissionRequired": {}, + "phone": "Телефон", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Підтвердити сканування даних", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Підтвердити подробиці при скануванні в позицій", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "Увімкнути Закупівлю", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "Увімкнути функціонал закупівлі", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "Швидкий Доступ до Камери", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "Увімкнути ярлик для завантаження зображень на екрані закупівель", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "Замовлення на Закупівлю", + "@purchaseOrder": {}, + "purchaseOrderCreate": "Нове Замовлення на Закупівлю", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "Редагувати Замовлення на Закупівлю", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "Налаштування замовлення на закупівлю", + "@purchaseOrderSettings": {}, + "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": {}, + "rotateClockwise": "Повернути на 90° за годинниковою стрілкою", + "@rotateClockwise": {}, + "refreshing": "Оновлення", + "@refreshing": {}, + "rejected": "Відхилено", + "@rejected": {}, + "releaseNotes": "Замітки до випуску", + "@releaseNotes": {}, + "remove": "Видалити", + "@remove": { + "description": "remove" + }, + "removeStock": "Remove Stock", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "Зголосити помилку", + "@reportBug": {}, + "reportBugDescription": "Відправити звіт про помилку (потрібен обліковий запис GitHub)", + "@reportBugDescription": {}, + "responsible": "Відповідальний", + "@responsible": {}, + "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": "Ресурс не знайдено", + "@response404": {}, + "response405": "Цей метод заборонений", + "@response405": {}, + "response429": "Занадто багато запитів", + "@response429": {}, + "response500": "Внутрішня помилка сервера", + "@response500": {}, + "response501": "Не реалізовано", + "@response501": {}, + "response502": "Поганий шлюз", + "@response502": {}, + "response503": "Сервіс недоступний", + "@response503": {}, + "response504": "Шлю не відповідає", + "@response504": {}, + "response505": "Версія HTTP не підтримується", + "@response505": {}, + "responseData": "Дані відповіді", + "@responseData": {}, + "responseInvalid": "Невірний код відповіді", + "@responseInvalid": {}, + "responseUnknown": "Невідома відповідь", + "@responseUnknown": {}, + "result": "Результат", + "@result": { + "description": "" + }, + "returned": "Повернуто", + "@returned": {}, + "salesOrder": "Замовлення", + "@salesOrder": {}, + "salesOrders": "Замовлення", + "@salesOrders": {}, + "salesOrderEnable": "Увімкнути замовлення", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "Активувати можливість замовлення продажів", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "Комбінація клавіш камери", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "Enable image upload shortcut on sales order screen", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "Параметри замовлень", + "@salesOrderSettings": {}, + "salesOrderCreate": "Нове замовлення", + "@saleOrderCreate": {}, + "salesOrderEdit": "Редагувати замовлення", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Замовлення оновлено", + "@salesOrderUpdated": {}, + "save": "Зберегти", + "@save": { + "description": "Save" + }, + "scanBarcode": "Сканувати штрих-код", + "@scanBarcode": {}, + "scanSupplierPart": "Сканувати штрих-код позиції постачальника", + "@scanSupplierPart": {}, + "scanIntoLocation": "", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "Scan this item into location", + "@scanIntoLocationDetail": {}, + "scannerExternal": "Зовнішній сканер", + "@scannerExternal": {}, + "scannerExternalDetail": "Використовувати зовнішній сканер для читання штрих-кодів (wedge режим)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "Scan Received Parts", + "@scanReceivedParts": {}, + "search": "Пошук", + "@search": { + "description": "search" + }, + "searching": "Триває пошук", + "@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", + "@searchStock": {}, + "select": "Вибрати", + "@select": {}, + "selectFile": "Вибрати файл", + "@selectFile": {}, + "selectImage": "Виберіть зображення", + "@selectImage": {}, + "selectLocation": "Select a location", + "@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": "Server cannot be empty", + "@serverEmpty": {}, + "serverError": "Помилка сервера", + "@serverError": {}, + "serverDetails": "Інформація про сервер", + "@serverDetails": {}, + "serverMissingData": "На сервері відсутні обов'язкові поля для відповіді", + "@serverMissingData": {}, + "serverOld": "Стара версія сервера", + "@serverOld": {}, + "serverSettings": "Налаштування сервера", + "@serverSettings": {}, + "serverStart": "Адреса сервера мусить починатися з http[s]", + "@serverStart": {}, + "settings": "Налаштування", + "@settings": {}, + "serverInstance": "Екземпляр сервера", + "@serverInstance": {}, + "serverNotConnected": "Відсутнє з'єднання з сервером", + "@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", + "@sku": {}, + "sounds": "Звуки", + "@sounds": {}, + "soundOnBarcodeAction": "Відтворити звук при скануванні", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "Відтворити звук при помилці сервера", + "@soundOnServerError": {}, + "startDate": "Дата початку", + "@startDate": {}, + "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": "Ви впевнені, що хочете видалити цей товар?", + "@stockItemDeleteConfirm": {}, + "stockItemDeleteFailure": "Could not delete stock item", + "@stockItemDeleteFailure": {}, + "stockItemDeleteSuccess": "Stock item deleted", + "@stockItemDeleteSuccess": {}, + "stockItemHistory": "Stock History", + "@stockItemHistory": {}, + "stockItemHistoryDetail": "Відображення історичної інформації відстеження запасів", + "@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": "Застосувати обмежену перевірку HTTP-сертифікатів", + "@strictHttpsDetails": {}, + "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": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "takePicture": "Зробити фото", + "@takePicture": {}, + "targetDate": "Target Date", + "@targetDate": {}, + "templatePart": "Parent Template Part", + "@templatePart": {}, + "testName": "Назва тесту", + "@testName": {}, + "testPassedOrFailed": "Тест завершився успішно або помилкою", + "@testPassedOrFailed": {}, + "testsRequired": "Вимаганні тести", + "@testsRequired": {}, + "testResults": "Результат тесту", + "@testResults": { + "description": "" + }, + "testResultsDetail": "Показати результати перевірки товару на складі", + "@testResultsDetail": {}, + "testResultAdd": "Додати результат тесту", + "@testResultAdd": {}, + "testResultNone": "Відсутні результати тесту", + "@testResultNone": {}, + "testResultNoneDetail": "Результати тесту недоступні", + "@testResultNoneDetail": {}, + "testResultUploadFail": "Помилка при завантаженні результатів тесту", + "@testResultUploadFail": {}, + "testResultUploadPass": "Test result uploaded", + "@testResultUploadPass": {}, + "timeout": "Тайм-аут", + "@timeout": { + "description": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "Помилка токену", + "@tokenError": {}, + "tokenMissing": "Missing Token", + "@tokenMissing": {}, + "tokenMissingFromResponse": "Access token missing from response", + "@tokenMissingFromResponse": {}, + "totalPrice": "Total Price", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "Unit Price", + "@unitPrice": {}, + "units": "Units", + "@units": {}, + "unknownResponse": "Unknown Response", + "@unknownResponse": {}, + "upload": "Upload", + "@upload": {}, + "uploadFailed": "File upload failed", + "@uploadFailed": {}, + "uploadSuccess": "File uploaded", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..b981e99 --- /dev/null +++ b/lib/l10n/vi_VN/app_vi_VN.arb @@ -0,0 +1,1215 @@ +{ + "@@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": "Chức nă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 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": {}, + "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": {}, + "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", + "@appSettings": {}, + "appSettingsDetails": "Cấu hình cài đặt ứng dụng", + "@appSettingsDetails": {}, + "assignedToMe": "", + "@assignedToMe": {}, + "assignedToMeDetail": "", + "@assignedToMeDetail": {}, + "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": {}, + "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", + "@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": {}, + "barcodeScanPart": "Quét mã hàng hóa", + "@barcodeScanPart": {}, + "barcodeReceivePart": "Quét mã vạch để nhận sản phẩm", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "Quét mã vạch đã bị dừng", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@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", + "@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", + "@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", + "@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", + "@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": {}, + "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", + "@cameraInternalDetail": {}, + "cancel": "Hủy bỏ", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "Hủy đơn hàng", + "@cancelOrder": {}, + "category": "Danh mục", + "@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": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "Edit Company", + "@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": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "Cấu hình thiết lập máy chủ", + "@configureServer": {}, + "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", + "@count": { + "description": "Count" + }, + "countStock": "Kiểm kê", + "@countStock": { + "description": "Count Stock" + }, + "credits": "Tín dụng", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "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": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "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": {}, + "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", + "@destination": {}, + "destroyed": "Đã hủy", + "@destroyed": {}, + "details": "Chi tiết", + "@details": { + "description": "details" + }, + "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": {}, + "edit": "Sửa", + "@edit": { + "description": "edit" + }, + "editAttachment": "Sửa tệp đính kèm", + "@editAttachment": {}, + "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": {}, + "email": "Địa chỉ email", + "@email": {}, + "enterPassword": "Nhập mật khẩu", + "@enterPassword": {}, + "enterUsername": "Nhập tên người dùng", + "@enterUsername": {}, + "error": "Lỗi", + "@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": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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": {}, + "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": {}, + "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", + "@filterTemplateDetail": {}, + "filterTrackable": "Có thể theo dõi", + "@filterTrackable": {}, + "filterTrackableDetail": "Hiển thị phụ kiện đang theo dõi", + "@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ệ", + "@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" + }, + "home": "Trang chủ", + "@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", + "@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ủ", + "@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", + "@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": {}, + "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": {}, + "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": {}, + "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": {}, + "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": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "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": {}, + "itemDeleted": "Hàng hóa đã bị xóa", + "@itemDeleted": {}, + "itemUpdated": "Mẫu đã được cập nhật", + "@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", + "@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", + "@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": {}, + "lineItemAdd": "Thêm hạng mục", + "@lineItemAdd": {}, + "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": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "Không xác định được vị trí", + "@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", + "@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", + "@manufacturer": {}, + "manufacturers": "Nhà sản xuất", + "@manufacturers": {}, + "missingData": "Dữ liệu còn thiếu", + "@missingData": {}, + "name": "Tên", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "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": {}, + "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", + "@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 đơ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", + "@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)" + }, + "partNotSalable": "Đánh dấu không thể bán cho hàng hoá", + "@partNotSalable": {}, + "partsNone": "Không có phụ tùng", + "@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", + "@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": {}, + "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", + "@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": {}, + "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", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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ủ", + "@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": {}, + "profileLogout": "Thoát hồ sơ", + "@profileLogout": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "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": {}, + "responsible": "Responsible", + "@responsible": {}, + "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": {}, + "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": {}, + "salesOrder": "Đơn hàng bán", + "@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", + "@salesOrderEdit": {}, + "salesOrderUpdated": "Đơn hàng bán đã được cập nhật", + "@salesOrderUpdated": {}, + "save": "Lưu lại", + "@save": { + "description": "Save" + }, + "scanBarcode": "Quét mã vạch", + "@scanBarcode": {}, + "scanSupplierPart": "Quét mã nhà cung cấp hàng hoá", + "@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", + "@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" + }, + "searching": "Đang tìm kiếm", + "@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", + "@searchStock": {}, + "select": "Chọn", + "@select": {}, + "selectFile": "Chọn file", + "@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", + "@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": {}, + "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ủ", + "@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": {}, + "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": {}, + "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", + "@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": {}, + "startDate": "Start Date", + "@startDate": {}, + "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": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "takePicture": "Chụp ảnh", + "@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", + "@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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "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": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "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": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "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": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "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", + "@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": {}, + "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": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ 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 new file mode 100644 index 0000000..2f7c498 --- /dev/null +++ b/lib/l10n/zh_CN/app_zh_CN.arb @@ -0,0 +1,1215 @@ +{ + "@@locale": "zh-CN", + "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": "额外 app 凭据", + "@appCredits": {}, + "appDetails": "应用详情", + "@appDetails": {}, + "allocated": "已分配", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "正方形 (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "分配库存", + "@allocateStock": {}, + "allocatedStock": "已分配库存", + "@allocatedStock": {}, + "appReleaseNotes": "显示应用发布笔记", + "@appReleaseNotes": {}, + "appSettings": "应用设置", + "@appSettings": {}, + "appSettingsDetails": "配置 InvenTree app 设置项", + "@appSettingsDetails": {}, + "assignedToMe": "已分派给我", + "@assignedToMe": {}, + "assignedToMeDetail": "显示分派给我的订单", + "@assignedToMeDetail": {}, + "attachments": "附件", + "@attachments": {}, + "attachImage": "附加图片", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "找不到附件。", + "@attachmentNone": {}, + "attachmentNoneDetail": "未找到附件", + "@attachmentNoneDetail": {}, + "attachmentSelect": "选择附件", + "@attachmentSelect": {}, + "attention": "注意", + "@attention": {}, + "available": "可用的", + "@available": {}, + "availableStock": "可用库存", + "@availableStock": {}, + "barcodes": "条形码", + "@barcodes": {}, + "barcodeSettings": "条形码设置", + "@barcodeSettings": {}, + "barcodeAssign": "分配条形码", + "@barcodeAssign": {}, + "barcodeAssignDetail": "扫描定制条形码以分配", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "条形码已分配", + "@barcodeAssigned": {}, + "barcodeError": "条形码扫描出错", + "@barcodeError": {}, + "barcodeInUse": "条形码已经被分配", + "@barcodeInUse": {}, + "barcodeMissingHash": "响应中缺少条形码的哈希数据", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "无匹配条形码", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "未分配条形码", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "扫描零件条形码", + "@barcodeScanPart": {}, + "barcodeReceivePart": "扫描条形码以接收零件", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "条形码扫描已暂停", + "@barodeScanPaused": {}, + "barcodeScanPause": "点击以暂停扫描", + "@barcodeScanPause": {}, + "barcodeScanAssign": "扫描以分配条形码", + "@barcodeScanAssign": {}, + "barcodeScanController": "扫描仪输入", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "选择条码枪的输入源", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "条形码扫描延迟设置", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "两次条形码扫描之间的延迟时间", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "扫描 InvenTree 条形码", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "将库存项扫描进这个位置", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "扫描库存地点", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "单次扫描模式", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "每次扫描后暂停一下条码枪", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "已扫描至位置", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "未扫描到物品", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "扫描库存项", + "@barcodeScanItem": {}, + "barcodeTones": "条形码的音调", + "@barcodeTones": {}, + "barcodeUnassign": "取消分配条形码", + "@barcodeUnassign": {}, + "barcodeUnknown": "无法识别条形码", + "@barcodeUnknown": {}, + "batchCode": "批号", + "@batchCode": {}, + "billOfMaterials": "物料清单", + "@billOfMaterials": {}, + "bom": "物料清单", + "@bom": {}, + "bomEnable": "显示物料清单", + "@bomEnable": {}, + "build": "生产", + "@build": {}, + "building": "正在构建", + "@building": {}, + "cameraCreationError": "无法启动相机控制器", + "@cameraCreationError": {}, + "cameraInternal": "内置相机", + "@cameraInternal": {}, + "cameraInternalDetail": "使用内置相机读取条形码", + "@cameraInternalDetail": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "取消订单", + "@cancelOrder": {}, + "category": "类别", + "@category": {}, + "categoryCreate": "新建类别", + "@categoryCreate": {}, + "categoryCreateDetail": "新建零件类别", + "@categoryCreateDetail": {}, + "categoryUpdated": "零件类别已更新", + "@categoryUpdated": {}, + "company": "公司", + "@company": {}, + "companyAdd": "添加新公司", + "@companyAdd": {}, + "companyEdit": "编辑公司信息", + "@companyEdit": {}, + "companyNoResults": "没有符合查询的公司", + "@companyNoResults": {}, + "companyUpdated": "公司详情已更新", + "@companyUpdated": {}, + "companies": "公司", + "@companies": {}, + "complete": "完成", + "@complete": {}, + "completeOrder": "完成订单", + "@completeOrder": {}, + "completionDate": "完成日期", + "@completionDate": {}, + "configureServer": "配置服务器的设置", + "@configureServer": {}, + "confirmScan": "确认转移", + "@confirmScan": {}, + "confirmScanDetail": "扫描条形码时确认库存转移详情", + "@confirmScanDetail": {}, + "connectionRefused": "连接被拒绝", + "@connectionRefused": {}, + "count": "数量", + "@count": { + "description": "Count" + }, + "countStock": "库存数量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "致谢", + "@credits": {}, + "crop": "裁剪", + "@crop": {}, + "cropImage": "裁剪图片", + "@cropImage": {}, + "customer": "客户", + "@customer": {}, + "customers": "客户信息", + "@customers": {}, + "customerReference": "客户指引", + "@customerReference": {}, + "damaged": "破损", + "@damaged": {}, + "colorScheme": "配色方案", + "@colorScheme": {}, + "colorSchemeDetail": "选择配色方案", + "@colorSchemeDetail": {}, + "darkMode": "暗黑模式", + "@darkMode": {}, + "darkModeEnable": "启用暗黑模式", + "@darkModeEnable": {}, + "delete": "删除", + "@delete": {}, + "deleteFailed": "删除操作失败", + "@deleteFailed": {}, + "deleteImageConfirmation": "您确认要删除此图片吗?", + "@deleteImageConfirmation": {}, + "deleteImageTooltip": "删除图片", + "@deleteImageTooltip": {}, + "deleteImage": "删除图片", + "@deleteImage": {}, + "deletePart": "删除零件", + "@deletePart": {}, + "deletePartDetail": "从数据库中删除此零件", + "@deletePartDetail": {}, + "deleteSuccess": "删除操作成功", + "@deleteSuccess": {}, + "deliveryDate": "交货日期", + "@deliveryDate": {}, + "description": "描述", + "@description": {}, + "destination": "目的地", + "@destination": {}, + "destroyed": "销毁", + "@destroyed": {}, + "details": "详细信息", + "@details": { + "description": "details" + }, + "documentation": "文档", + "@documentation": {}, + "downloadComplete": "下载完成", + "@downloadComplete": {}, + "downloadError": "下载图片时出错", + "@downloadError": {}, + "downloading": "下载文件中", + "@downloading": {}, + "edit": "编辑", + "@edit": { + "description": "edit" + }, + "editAttachment": "编辑附件", + "@editAttachment": {}, + "editCategory": "编辑类别", + "@editCategory": {}, + "editLocation": "编辑位置", + "@editLocation": {}, + "editNotes": "编辑备注", + "@editNotes": {}, + "editParameter": "编辑参数", + "@editParameter": {}, + "editPart": "编辑零件", + "@editPart": { + "description": "edit part" + }, + "editItem": "编辑库存项", + "@editItem": {}, + "editLineItem": "编辑行项目", + "@editLineItem": {}, + "email": "电子邮件", + "@email": {}, + "enterPassword": "输入密码", + "@enterPassword": {}, + "enterUsername": "输入用户名", + "@enterUsername": {}, + "error": "错误", + "@error": { + "description": "Error" + }, + "errorCreate": "创建数据库条目时出错", + "@errorCreate": {}, + "errorDelete": "删除数据库条目时出错", + "@errorDelete": {}, + "errorDetails": "错误详情", + "@errorDetails": {}, + "errorFetch": "从服务器获取数据时出错", + "@errorFetch": {}, + "errorUserRoles": "从服务器请求用户角色时出错", + "@errorUserRoles": {}, + "errorPluginInfo": "从服务器请求插件数据时出错", + "@errorPluginInfo": {}, + "errorReporting": "错误报告", + "@errorReporting": {}, + "errorReportUpload": "上传错误报告", + "@errorReportUpload": {}, + "errorReportUploadDetails": "上传匿名错误报告和崩溃日志", + "@errorReportUploadDetails": {}, + "expiryDate": "有效期至", + "@expiryDate": {}, + "expiryExpired": "已过期", + "@expiryExpired": {}, + "expiryStale": "临期", + "@expiryStale": {}, + "extraLineItem": "额外行项目", + "@extraLineItem": {}, + "extraLineItems": "额外行项目", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "显示已序列化的库存物品", + "@filterSerializedDetail": {}, + "filterTemplate": "模板", + "@filterTemplate": {}, + "filterTemplateDetail": "显示模板零件", + "@filterTemplateDetail": {}, + "filterTrackable": "可追踪", + "@filterTrackable": {}, + "filterTrackableDetail": "显示可追踪的零件", + "@filterTrackableDetail": {}, + "filterVirtual": "虚拟", + "@filterVirtual": {}, + "filterVirtualDetail": "显示虚拟零件", + "@filterVirtualDetail": {}, + "filteringOptions": "过滤选项", + "@filteringOptions": {}, + "formatException": "格式异常", + "@formatException": {}, + "formatExceptionJson": "JSON 数据格式异常", + "@formatExceptionJson": {}, + "formError": "表单错误", + "@formError": {}, + "history": "历史", + "@history": { + "description": "history" + }, + "home": "主页", + "@home": {}, + "homeScreen": "主屏幕", + "@homeScreen": {}, + "homeScreenSettings": "配置主屏幕设置", + "@homeScreenSettings": {}, + "homeShowPo": "显示采购订单", + "@homeShowPo": {}, + "homeShowPoDescription": "在主屏幕上显示订单按钮", + "@homeShowPoDescription": {}, + "homeShowShipments": "显示货件", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "在首页显示待处理货件", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "显示销售订单", + "@homeShowSo": {}, + "homeShowSoDescription": "在主屏幕上显示销售订单按钮", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "已订阅的零件", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "在主屏幕上显示已订阅的零件", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "显示供应商", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "在主屏幕上显示供应商按钮", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "显示制造商", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "在主屏幕上显示制造商按钮", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "显示客户", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "在主屏幕上显示客户按钮", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "图片上传失败", + "@imageUploadFailure": {}, + "imageUploadSuccess": "图片已上传", + "@imageUploadSuccess": {}, + "inactive": "未激活", + "@inactive": {}, + "inactiveCompany": "此公司被标记为不活跃", + "@inactiveCompany": {}, + "inactiveDetail": "此零件已被标为未激活", + "@inactiveDetail": {}, + "includeSubcategories": "包含子类别", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "显示子类别中的结果", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "包括次级位置", + "@includeSublocations": {}, + "includeSublocationsDetail": "显示次级位置中的结果", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完整的配置文件详细信息", + "@incompleteDetails": {}, + "internalPartNumber": "内部零件号", + "@internalPartNumber": {}, + "info": "信息", + "@info": {}, + "inProduction": "生产中的", + "@inProduction": {}, + "inProductionDetail": "该库存物品正在生产中", + "@inProductionDetail": {}, + "internalPart": "内部零件", + "@internalPart": {}, + "invalidHost": "无效的主机名", + "@invalidHost": {}, + "invalidHostDetails": "提供的主机名无效", + "@invalidHostDetails": {}, + "invalidPart": "无效零件", + "@invalidPart": {}, + "invalidPartCategory": "无效零件类别", + "@invalidPartCategory": {}, + "invalidStockLocation": "无效库存地点", + "@invalidStockLocation": {}, + "invalidStockItem": "无效库存项", + "@invalidStockItem": {}, + "invalidSupplierPart": "无效的供应商零件", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "无效的用户名密码组合", + "@invalidUsernamePassword": {}, + "invoice": "发票", + "@invoice": {}, + "invoiceNumber": "发票号码", + "@invoiceNumber": {}, + "issue": "下单任务", + "@issue": {}, + "issueDate": "签发日期", + "@issueDate": {}, + "issueOrder": "下达订单", + "@issueOrder": {}, + "itemInLocation": "物品已就位", + "@itemInLocation": {}, + "itemDeleted": "项目已移除", + "@itemDeleted": {}, + "itemUpdated": "库存项有更新", + "@itemUpdated": {}, + "keywords": "关键词", + "@keywords": {}, + "labelDriver": "标签打印机", + "@labelDriver": {}, + "labelSelectDriver": "选择标签打印机", + "@labelSelectDriver": {}, + "labelPrinting": "打印标签", + "@labelPrinting": {}, + "labelPrintingDetail": "启用标签打印功能", + "@labelPrintingDetail": {}, + "labelTemplate": "标签模板", + "@labelTemplate": {}, + "labelSelectTemplate": "选择标签模板", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "选择标签打印机", + "@labelSelectPrinter": {}, + "language": "语言", + "@language": {}, + "languageDefault": "系统默认语言", + "@languageDefault": {}, + "languageSelect": "选择语言", + "@languageSelect": {}, + "lastStocktake": "最近库存盘点", + "@lastStocktake": {}, + "lastUpdated": "最近更新", + "@lastUpdated": {}, + "level": "级", + "@level": {}, + "lineItemAdd": "添加行项目", + "@lineItemAdd": {}, + "lineItem": "行项目", + "@lineItem": {}, + "lineItems": "行项目", + "@lineItems": {}, + "lineItemUpdated": "行项目已更新", + "@lineItemUpdated": {}, + "locateItem": "定位库存项", + "@locateItem": {}, + "locateLocation": "定位存货位置", + "@locateLocation": {}, + "locationCreate": "新建仓储位置", + "@locationCreate": {}, + "locationCreateDetail": "创建新库存地点", + "@locationCreateDetail": {}, + "locationDefault": "默认位置", + "@locationDefault": {}, + "locationNotSet": "没有指定仓储位置", + "@locationNotSet": {}, + "locationUpdated": "库存地点已更新", + "@locationUpdated": {}, + "login": "登入", + "@login": {}, + "loginEnter": "输入登录详情", + "@loginEnter": {}, + "loginEnterDetails": "用户名和密码未存储在本地", + "@loginEnterDetails": {}, + "link": "链接", + "@link": {}, + "lost": "丢失", + "@lost": {}, + "manufacturerPart": "制造商零件", + "@manufacturerPart": {}, + "manufacturerPartEdit": "编辑制造商零件", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "制造商零件号", + "@manufacturerPartNumber": {}, + "manufacturer": "制造商", + "@manufacturer": {}, + "manufacturers": "制造商", + "@manufacturers": {}, + "missingData": "缺失数据", + "@missingData": {}, + "name": "名称", + "@name": {}, + "no": "否", + "@no": {}, + "notApplicable": "不适用", + "@notApplicable": {}, + "notConnected": "未连接", + "@notConnected": {}, + "notes": "注释", + "@notes": { + "description": "Notes" + }, + "notifications": "通知", + "@notifications": {}, + "notificationsEmpty": "没有未读通知", + "@notificationsEmpty": {}, + "noResponse": "服务器未响应", + "@noResponse": {}, + "noResults": "无结果", + "@noResults": {}, + "noImageAvailable": "没有可用的图片", + "@noImageAvailable": {}, + "noPricingAvailable": "无可用价格", + "@noPricingAvailable": {}, + "noPricingDataFound": "未找到此零件的定价数据", + "@noPricingDataFound": {}, + "noSubcategories": "无子类别", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "无可用子类别", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "无效的数字", + "@numberInvalid": {}, + "onOrder": "已订购", + "@onOrder": {}, + "onOrderDetails": "当前订购项目", + "@onOrderDetails": {}, + "orientation": "屏幕方向​​​​​​​​​​​​​​", + "@orientation": {}, + "orientationDetail": "屏幕方向(需要重启)", + "@orientationDetail": {}, + "orientationLandscape": "横向", + "@orientationLandscape": {}, + "orientationPortrait": "纵向", + "@orientationPortrait": {}, + "orientationSystem": "系统", + "@orientationSystem": {}, + "outstanding": "未完成", + "@outstanding": {}, + "outstandingOrderDetail": "显示未完成的订单", + "@outstandingOrderDetail": {}, + "overdue": "逾期", + "@overdue": {}, + "overdueDetail": "显示逾期订单", + "@overdueDetail": {}, + "packaging": "打包", + "@packaging": {}, + "packageName": "包名", + "@packageName": {}, + "parameters": "参数", + "@parameters": {}, + "parametersSettingDetail": "显示零件参数", + "@parametersSettingDetail": {}, + "parent": "上级", + "@parent": {}, + "parentCategory": "上级类别", + "@parentCategory": {}, + "parentLocation": "上级地点", + "@parentLocation": {}, + "part": "零件", + "@part": { + "description": "Part (single)" + }, + "partCreate": "新零件", + "@partCreate": {}, + "partCreateDetail": "在此类别中创建新的零件", + "@partCreateDetail": {}, + "partEdited": "零件已更新", + "@partEdited": {}, + "parts": "零件", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "零件未被标记为可销售", + "@partNotSalable": {}, + "partsNone": "无零件", + "@partsNone": {}, + "partNoResults": "没有匹配查询的零件", + "@partNoResults": {}, + "partPricing": "零件价格", + "@partPricing": {}, + "partPricingSettingDetail": "显示零件价格信息", + "@pricingSettingDetail": {}, + "partSettings": "零件设置", + "@partSettings": {}, + "partsStarred": "订阅的零件", + "@partsStarred": {}, + "partsStarredNone": "没有可用的带星号零件", + "@partsStarredNone": {}, + "partSuppliers": "零件供应商", + "@partSuppliers": {}, + "partCategory": "零件类别", + "@partCategory": {}, + "partCategoryTopLevel": "上一级零件类别", + "@partCategoryTopLevel": {}, + "partCategories": "零件类别", + "@partCategories": {}, + "partDetails": "零件详情", + "@partDetails": {}, + "partNotes": "零件注释", + "@partNotes": {}, + "partStock": "零件库存", + "@partStock": { + "description": "part stock" + }, + "password": "密码", + "@password": {}, + "passwordEmpty": "密码不能为空", + "@passwordEmpty": {}, + "pending": "等待", + "@pending": {}, + "permissionAccountDenied": "您的账户没有执行此操作所需的权限", + "@permissionAccountDenied": {}, + "permissionRequired": "需要授权:", + "@permissionRequired": {}, + "phone": "电话", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "确认扫描数据", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "扫描物品时确认详情", + "@purchaseOrderConfirmScanDetail": {}, + "purchaseOrderEnable": "启用采购订单", + "@purchaseOrderEnable": {}, + "purchaseOrderEnableDetail": "启用采购订单功能", + "@purchaseOrderEnableDetail": {}, + "purchaseOrderShowCamera": "相机快捷方式", + "@purchaseOrderShowCamera": {}, + "purchaseOrderShowCameraDetail": "在采购订单页面启用图像上传快捷方式", + "@purchaseOrderShowCameraDetail": {}, + "purchaseOrder": "采购订单", + "@purchaseOrder": {}, + "purchaseOrderCreate": "新采购订单", + "@purchaseOrderCreate": {}, + "purchaseOrderEdit": "编辑采购订单", + "@purchaseOrderEdit": {}, + "purchaseOrderSettings": "采购订单设置", + "@purchaseOrderSettings": {}, + "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": {}, + "rotateClockwise": "顺时针旋转 90°", + "@rotateClockwise": {}, + "refreshing": "正在刷新", + "@refreshing": {}, + "rejected": "已拒绝", + "@rejected": {}, + "releaseNotes": "更新日志", + "@releaseNotes": {}, + "remove": "移除", + "@remove": { + "description": "remove" + }, + "removeStock": "移除库存", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "反馈问题", + "@reportBug": {}, + "reportBugDescription": "提交 bug 报告 (需要 GitHub 账户)", + "@reportBugDescription": {}, + "responsible": "负责人", + "@responsible": {}, + "results": "结果", + "@results": {}, + "request": "请求", + "@request": {}, + "requestFailed": "请求失败", + "@requestFailed": {}, + "requestSuccessful": "请求成功", + "@requestSuccessful": {}, + "requestingData": "正在请求数据", + "@requestingData": {}, + "required": "必填", + "@required": { + "description": "This field is required" + }, + "response400": "错误的请求", + "@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": "未知响应", + "@responseUnknown": {}, + "result": "结果", + "@result": { + "description": "" + }, + "returned": "已退回", + "@returned": {}, + "salesOrder": "销售订单", + "@salesOrder": {}, + "salesOrders": "销售订单", + "@salesOrders": {}, + "salesOrderEnable": "启用销售订单", + "@salesOrderEnable": {}, + "salesOrderEnableDetail": "启用销售订单功能", + "@salesOrderEnableDetail": {}, + "salesOrderShowCamera": "相机快捷方式", + "@salesOrderShowCamera": {}, + "salesOrderShowCameraDetail": "在销售订单页面启用图像上传快捷方式", + "@salesOrderShowCameraDetail": {}, + "salesOrderSettings": "销售订单设置", + "@salesOrderSettings": {}, + "salesOrderCreate": "新的销售订单", + "@saleOrderCreate": {}, + "salesOrderEdit": "编辑销售订单", + "@salesOrderEdit": {}, + "salesOrderUpdated": "销售订单已更新", + "@salesOrderUpdated": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "扫描条形码", + "@scanBarcode": {}, + "scanSupplierPart": "扫描供应商条形码", + "@scanSupplierPart": {}, + "scanIntoLocation": "已扫描至位置", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "扫描此项目到此位置", + "@scanIntoLocationDetail": {}, + "scannerExternal": "外部扫描器", + "@scannerExternal": {}, + "scannerExternalDetail": "使用外部扫描仪读取条形码 (分割模式)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "扫描收到的零件", + "@scanReceivedParts": {}, + "search": "搜索", + "@search": { + "description": "search" + }, + "searching": "搜索", + "@searching": {}, + "searchLocation": "搜索仓储位置", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "搜索零件", + "@searchParts": {}, + "searchStock": "搜索库存", + "@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": {}, + "shipment": "发货", + "@shipment": {}, + "shipments": "配送", + "@shipments": {}, + "shipmentsPending": "待处理货件", + "@shipmentsPending": {}, + "shipmentAdd": "添加配送", + "@shipmentAdd": {}, + "shipmentCheck": "查询物流", + "@shipmentCheck": {}, + "shipmentCheckDetail": "标记为已核对", + "@shipmentCheckDetail": {}, + "shipmentChecked": "已核对", + "@shipmentChecked": {}, + "shipmentDate": "发货日期", + "@shipmentDate": {}, + "shipmentEdit": "编辑货件", + "@shipmentEdit": {}, + "shipmentReference": "参考编号", + "@shipmentReference": {}, + "shipmentSend": "确认发货", + "@shipmentSend": {}, + "shipmentUncheck": "取消核对", + "@shipmentUncheck": {}, + "shipmentUncheckDetail": "标记为未核对", + "@shipmentUncheckDetail": {}, + "shipmentUpdated": "货件信息已更新", + "@shipmentUpdated": {}, + "shipped": "已配送", + "@shipped": {}, + "sku": "库存单位 (SKU)", + "@sku": {}, + "sounds": "声音", + "@sounds": {}, + "soundOnBarcodeAction": "播放条形码动作音效", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "服务器错误时播放音效", + "@soundOnServerError": {}, + "startDate": "起始日期", + "@startDate": {}, + "status": "状态", + "@status": {}, + "statusCode": "状态码", + "@statusCode": {}, + "stock": "库存", + "@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": "库存项已更新", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "库存项更新失败", + "@stockItemUpdateFailure": {}, + "stockLocation": "库存地点", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "库存地点", + "@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": "供应商零件", + "@supplierPart": {}, + "supplierPartEdit": "编辑供应商零件", + "@supplierPartEdit": {}, + "supplierPartNumber": "供应商零件编号", + "@supplierPartNumber": {}, + "supplierPartUpdated": "供应商零件已更新", + "@supplierPartUpdated": {}, + "supplierParts": "供应商零件", + "@supplierParts": {}, + "suppliers": "供应商", + "@suppliers": {}, + "supplierReference": "供应商参考", + "@supplierReference": {}, + "switchCamera": "切换摄像头", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "切换手电筒", + "@toggleTorch": {}, + "tokenError": "令牌错误", + "@tokenError": {}, + "tokenMissing": "缺少令牌", + "@tokenMissing": {}, + "tokenMissingFromResponse": "响应中缺少访问令牌", + "@tokenMissingFromResponse": {}, + "totalPrice": "总价", + "@totalPrice": {}, + "trackingNumber": "运单号", + "@trackingNumber": {}, + "transfer": "转移", + "@transfer": { + "description": "transfer" + }, + "transferStock": "转移库存", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "将物品转移到另一个位置", + "@transferStockDetail": {}, + "transferStockLocation": "转移库存地点", + "@transferStockLocation": {}, + "transferStockLocationDetail": "将此库存地点转移到另一个", + "@transferStockLocationDetail": {}, + "translate": "转移", + "@translate": {}, + "translateHelp": "协助翻译 InvenTree 应用", + "@translateHelp": {}, + "unavailable": "不可用", + "@unavailable": {}, + "unavailableDetail": "物品不可用", + "@unavailableDetail": {}, + "unitPrice": "单价", + "@unitPrice": {}, + "units": "单位", + "@units": {}, + "unknownResponse": "未知响应", + "@unknownResponse": {}, + "upload": "上传", + "@upload": {}, + "uploadFailed": "文件上传失败", + "@uploadFailed": {}, + "uploadSuccess": "文件已上传", + "@uploadSuccess": {}, + "uploadImage": "上传图片", + "@uploadImage": {}, + "usedIn": "用途", + "@usedIn": {}, + "usedInDetails": "需要此零件的装配体", + "@usedInDetails": {}, + "username": "用户名", + "@username": {}, + "usernameEmpty": "用户名不能为空", + "@usernameEmpty": {}, + "value": "值", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "数值不能为空", + "@valueCannotBeEmpty": {}, + "valueRequired": "值为必填项", + "@valueRequired": {}, + "variants": "变体", + "@variants": {}, + "version": "版本", + "@version": {}, + "viewSupplierPart": "查看供应商零件", + "@viewSupplierPart": {}, + "website": "网站", + "@website": {}, + "yes": "是", + "@yes": {}, + "price": "价格", + "@price": {}, + "priceRange": "价格范围", + "@priceRange": {}, + "priceOverrideMin": "最低价格覆盖", + "@priceOverrideMin": {}, + "priceOverrideMax": "最高自定义价格", + "@priceOverrideMax": {}, + "salePrice": "销售价格", + "@salePrice": {}, + "saleHistory": "销售历史", + "@saleHistory": {}, + "supplierPricing": "供应商价格", + "@supplierPricing": {}, + "bomCost": "物料清单成本", + "@bomCost": {}, + "internalCost": "内部成本", + "@internalCost": {}, + "variantCost": "变体成本", + "@variantCost": {}, + "overallPricing": "总定价", + "@overallPricing": {}, + "pricingOverrides": "价格覆盖", + "@pricingOverrides": {}, + "currency": "币种", + "@currency": {}, + "priceBreaks": "批发价", + "@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 new file mode 100644 index 0000000..b0871e1 --- /dev/null +++ b/lib/l10n/zh_TW/app_zh_TW.arb @@ -0,0 +1,1215 @@ +{ + "@@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": {}, + "allocated": "已分配", + "@allocated": {}, + "aspectRatio16x9": "16:9", + "@aspectRatio16x9": {}, + "aspectRatio3x2": "3:2", + "@aspectRatio3x2": {}, + "aspectRatio4x3": "4:3", + "@aspectRatio4x3": {}, + "aspectRatioSquare": "Square (1:1)", + "@aspectRatioSquare": {}, + "allocateStock": "分配庫存", + "@allocateStock": {}, + "allocatedStock": "Allocated Stock", + "@allocatedStock": {}, + "appReleaseNotes": "顯示應用程式發布說明", + "@appReleaseNotes": {}, + "appSettings": "程式設定", + "@appSettings": {}, + "appSettingsDetails": "配置 InvenTree 應用程式設定", + "@appSettingsDetails": {}, + "assignedToMe": "Assigned to Me", + "@assignedToMe": {}, + "assignedToMeDetail": "Show orders which are assigned to me", + "@assignedToMeDetail": {}, + "attachments": "附件", + "@attachments": {}, + "attachImage": "附加影像", + "@attachImage": { + "description": "Attach an image" + }, + "attachmentNone": "找不到附件", + "@attachmentNone": {}, + "attachmentNoneDetail": "找不到附件", + "@attachmentNoneDetail": {}, + "attachmentSelect": "選取附件", + "@attachmentSelect": {}, + "attention": "關注", + "@attention": {}, + "available": "可用", + "@available": {}, + "availableStock": "可用庫存", + "@availableStock": {}, + "barcodes": "條碼", + "@barcodes": {}, + "barcodeSettings": "條形碼設置", + "@barcodeSettings": {}, + "barcodeAssign": "設定條碼", + "@barcodeAssign": {}, + "barcodeAssignDetail": "掃描定制條碼以設置", + "@barcodeAssignDetail": {}, + "barcodeAssigned": "條碼已設置", + "@barcodeAssigned": {}, + "barcodeError": "掃碼錯誤", + "@barcodeError": {}, + "barcodeInUse": "條碼已被用過", + "@barcodeInUse": {}, + "barcodeMissingHash": "回應中缺少條碼的哈希數", + "@barcodeMissingHash": {}, + "barcodeNoMatch": "無匹配條碼", + "@barcodeNoMatch": {}, + "barcodeNotAssigned": "未設置條碼", + "@barcodeNotAssigned": {}, + "barcodeScanPart": "掃描零件條碼", + "@barcodeScanPart": {}, + "barcodeReceivePart": "掃描條碼以接收零件", + "@barcodeReceivePart": {}, + "barcodeScanPaused": "條碼掃描已暫停", + "@barodeScanPaused": {}, + "barcodeScanPause": "Tap to pause scanning", + "@barcodeScanPause": {}, + "barcodeScanAssign": "掃描以設置條碼", + "@barcodeScanAssign": {}, + "barcodeScanController": "掃碼器輸入", + "@barcodeScanController": {}, + "barcodeScanControllerDetail": "選擇掃碼器輸入來源", + "@barcodeScanControllerDetail": {}, + "barcodeScanDelay": "掃碼延遲設定", + "@barcodeScanDelay": {}, + "barcodeScanDelayDetail": "兩次掃碼之間的延遲時間", + "@barcodeScanDelayDetail": {}, + "barcodeScanGeneral": "掃描 InvenTree 條碼", + "@barcodeScanGeneral": {}, + "barcodeScanInItems": "將庫存項目掃描進這個位置", + "@barcodeScanInItems": {}, + "barcodeScanLocation": "掃描庫存地點", + "@barcodeScanLocation": {}, + "barcodeScanSingle": "單掃模式", + "@barcodeScanSingle": {}, + "barcodeScanSingleDetail": "每次掃碼後暫停一下", + "@barcodeScanSingleDetail": {}, + "barcodeScanIntoLocationSuccess": "已掃描至位置", + "@barcodeScanIntoLocationSuccess": {}, + "barcodeScanIntoLocationFailure": "未掃描物品", + "@barcodeScanIntoLocationFailure": {}, + "barcodeScanItem": "掃描庫存項目", + "@barcodeScanItem": {}, + "barcodeTones": "條碼的音調", + "@barcodeTones": {}, + "barcodeUnassign": "條碼取消設置", + "@barcodeUnassign": {}, + "barcodeUnknown": "無法辨識條碼", + "@barcodeUnknown": {}, + "batchCode": "批號", + "@batchCode": {}, + "billOfMaterials": "材料清單", + "@billOfMaterials": {}, + "bom": "材料清單", + "@bom": {}, + "bomEnable": "顯示材料清單", + "@bomEnable": {}, + "build": "生產", + "@build": {}, + "building": "生產中", + "@building": {}, + "cameraCreationError": "Could not open camera controller", + "@cameraCreationError": {}, + "cameraInternal": "內置相機", + "@cameraInternal": {}, + "cameraInternalDetail": "使用內置相機讀取條碼", + "@cameraInternalDetail": {}, + "cancel": "取消", + "@cancel": { + "description": "Cancel" + }, + "cancelOrder": "取消訂單", + "@cancelOrder": {}, + "category": "類別", + "@category": {}, + "categoryCreate": "新增類別", + "@categoryCreate": {}, + "categoryCreateDetail": "新建零件類別", + "@categoryCreateDetail": {}, + "categoryUpdated": "零件類別已更新", + "@categoryUpdated": {}, + "company": "公司", + "@company": {}, + "companyAdd": "Add Company", + "@companyAdd": {}, + "companyEdit": "編輯公司", + "@companyEdit": {}, + "companyNoResults": "沒有符合查詢的公司", + "@companyNoResults": {}, + "companyUpdated": "公司詳情已更新", + "@companyUpdated": {}, + "companies": "公司", + "@companies": {}, + "complete": "Complete", + "@complete": {}, + "completeOrder": "Complete Order", + "@completeOrder": {}, + "completionDate": "Completion Date", + "@completionDate": {}, + "configureServer": "伺服器設定", + "@configureServer": {}, + "confirmScan": "確認轉移", + "@confirmScan": {}, + "confirmScanDetail": "掃描條碼時確認庫存轉移詳情", + "@confirmScanDetail": {}, + "connectionRefused": "連線被拒", + "@connectionRefused": {}, + "count": "數量", + "@count": { + "description": "Count" + }, + "countStock": "庫存數量", + "@countStock": { + "description": "Count Stock" + }, + "credits": "感謝", + "@credits": {}, + "crop": "Crop", + "@crop": {}, + "cropImage": "Crop Image", + "@cropImage": {}, + "customer": "客戶", + "@customer": {}, + "customers": "客戶", + "@customers": {}, + "customerReference": "客戶編號", + "@customerReference": {}, + "damaged": "已損壞", + "@damaged": {}, + "colorScheme": "Color Scheme", + "@colorScheme": {}, + "colorSchemeDetail": "Select color scheme", + "@colorSchemeDetail": {}, + "darkMode": "深色模式", + "@darkMode": {}, + "darkModeEnable": "啟用深色模式", + "@darkModeEnable": {}, + "delete": "刪除", + "@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", + "@destination": {}, + "destroyed": "已損毀", + "@destroyed": {}, + "details": "詳細資訊", + "@details": { + "description": "details" + }, + "documentation": "文件", + "@documentation": {}, + "downloadComplete": "Download Complete", + "@downloadComplete": {}, + "downloadError": "Error downloading image", + "@downloadError": {}, + "downloading": "下載檔案", + "@downloading": {}, + "edit": "編輯", + "@edit": { + "description": "edit" + }, + "editAttachment": "Edit Attachment", + "@editAttachment": {}, + "editCategory": "編輯類別", + "@editCategory": {}, + "editLocation": "編輯位置", + "@editLocation": {}, + "editNotes": "編輯備註", + "@editNotes": {}, + "editParameter": "編輯參數", + "@editParameter": {}, + "editPart": "編輯零件", + "@editPart": { + "description": "edit part" + }, + "editItem": "編輯庫存項目", + "@editItem": {}, + "editLineItem": "編輯行項目", + "@editLineItem": {}, + "email": "Email", + "@email": {}, + "enterPassword": "輸入密碼", + "@enterPassword": {}, + "enterUsername": "輸入使用者名稱", + "@enterUsername": {}, + "error": "錯誤", + "@error": { + "description": "Error" + }, + "errorCreate": "創建數據庫條目時出錯", + "@errorCreate": {}, + "errorDelete": "刪除數據庫條目時出錯", + "@errorDelete": {}, + "errorDetails": "錯誤詳情", + "@errorDetails": {}, + "errorFetch": "從服務器獲取數據時出錯", + "@errorFetch": {}, + "errorUserRoles": "從服務器請求用戶角色時出錯", + "@errorUserRoles": {}, + "errorPluginInfo": "從服務器請求插件數據時出錯", + "@errorPluginInfo": {}, + "errorReporting": "錯誤報告", + "@errorReporting": {}, + "errorReportUpload": "上傳錯誤報告", + "@errorReportUpload": {}, + "errorReportUploadDetails": "上傳匿名錯誤報告和崩潰日誌", + "@errorReportUploadDetails": {}, + "expiryDate": "Expiry Date", + "@expiryDate": {}, + "expiryExpired": "Expired", + "@expiryExpired": {}, + "expiryStale": "Stale", + "@expiryStale": {}, + "extraLineItem": "Extra Line Item", + "@extraLineItem": {}, + "extraLineItems": "Extra Line Items", + "@extraLineItems": {}, + "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": {}, + "filterSerializedDetail": "顯示已序列化的庫存物品", + "@filterSerializedDetail": {}, + "filterTemplate": "範本", + "@filterTemplate": {}, + "filterTemplateDetail": "顯示模板零件", + "@filterTemplateDetail": {}, + "filterTrackable": "可追蹤", + "@filterTrackable": {}, + "filterTrackableDetail": "顯示可追踪的零件", + "@filterTrackableDetail": {}, + "filterVirtual": "虛擬", + "@filterVirtual": {}, + "filterVirtualDetail": "顯示虛擬零件", + "@filterVirtualDetail": {}, + "filteringOptions": "篩選選項", + "@filteringOptions": {}, + "formatException": "格式異常", + "@formatException": {}, + "formatExceptionJson": "JSON 數據格式異常", + "@formatExceptionJson": {}, + "formError": "表單錯誤", + "@formError": {}, + "history": "歷史", + "@history": { + "description": "history" + }, + "home": "首頁", + "@home": {}, + "homeScreen": "主畫面", + "@homeScreen": {}, + "homeScreenSettings": "伺服器設定", + "@homeScreenSettings": {}, + "homeShowPo": "顯示採購訂單", + "@homeShowPo": {}, + "homeShowPoDescription": "在主屏幕上顯示訂單按鈕", + "@homeShowPoDescription": {}, + "homeShowShipments": "Show Shipments", + "@homeShowShipments": {}, + "homeShowShipmentsDescription": "Show pending shipments on the home screen", + "@homeShowShipmentsDescription": {}, + "homeShowSo": "顯示銷售訂單", + "@homeShowSo": {}, + "homeShowSoDescription": "在主屏幕上顯示銷售訂單按鈕", + "@homeShowSoDescription": {}, + "homeShowSubscribed": "訂閱零件通知", + "@homeShowSubscribed": {}, + "homeShowSubscribedDescription": "在主屏幕上顯示已訂閱的零件", + "@homeShowSubscsribedDescription": {}, + "homeShowSuppliers": "顯示供應商", + "@homeShowSuppliers": {}, + "homeShowSuppliersDescription": "在主屏幕上顯示供應商按鈕", + "@homeShowSupplierDescription": {}, + "homeShowManufacturers": "顯示生產商", + "@homeShowManufacturers": {}, + "homeShowManufacturersDescription": "在主屏幕上顯示製造商按鈕", + "@homeShowManufacturersDescription": {}, + "homeShowCustomers": "顯示客戶", + "@homeShowCustomers": {}, + "homeShowCustomersDescription": "在主屏幕上顯示客户按鈕", + "@homeShowCustomersDescription": {}, + "imageUploadFailure": "圖片上傳失敗", + "@imageUploadFailure": {}, + "imageUploadSuccess": "圖片上傳", + "@imageUploadSuccess": {}, + "inactive": "未啟用", + "@inactive": {}, + "inactiveCompany": "此公司被標記為不活躍", + "@inactiveCompany": {}, + "inactiveDetail": "此零件已被標為未激活", + "@inactiveDetail": {}, + "includeSubcategories": "包含子分類", + "@includeSubcategories": {}, + "includeSubcategoriesDetail": "顯示子類別中的結果", + "@includeSubcategoriesDetail": {}, + "includeSublocations": "包括次級位置", + "@includeSublocations": {}, + "includeSublocationsDetail": "顯示次級位置中的結果", + "@includeSublocationsDetail": {}, + "incompleteDetails": "不完整的配置文件詳細信息", + "@incompleteDetails": {}, + "internalPartNumber": "內部零件號", + "@internalPartNumber": {}, + "info": "資訊", + "@info": {}, + "inProduction": "生產中的", + "@inProduction": {}, + "inProductionDetail": "該庫存物品正在生產中", + "@inProductionDetail": {}, + "internalPart": "內部零件", + "@internalPart": {}, + "invalidHost": "無效的主機名", + "@invalidHost": {}, + "invalidHostDetails": "提供的主機名無效", + "@invalidHostDetails": {}, + "invalidPart": "無效零件", + "@invalidPart": {}, + "invalidPartCategory": "無效零件類別", + "@invalidPartCategory": {}, + "invalidStockLocation": "無效庫存地點", + "@invalidStockLocation": {}, + "invalidStockItem": "無效庫存項", + "@invalidStockItem": {}, + "invalidSupplierPart": "無效的供應商零件", + "@invalidSupplierPart": {}, + "invalidUsernamePassword": "無效的用户名密碼組合", + "@invalidUsernamePassword": {}, + "invoice": "Invoice", + "@invoice": {}, + "invoiceNumber": "Invoice Number", + "@invoiceNumber": {}, + "issue": "發行", + "@issue": {}, + "issueDate": "發行日期", + "@issueDate": {}, + "issueOrder": "發行訂單", + "@issueOrder": {}, + "itemInLocation": "物品已就位", + "@itemInLocation": {}, + "itemDeleted": "項目已移除", + "@itemDeleted": {}, + "itemUpdated": "Item updated", + "@itemUpdated": {}, + "keywords": "關鍵字", + "@keywords": {}, + "labelDriver": "Label Driver", + "@labelDriver": {}, + "labelSelectDriver": "Select Label Printer Driver", + "@labelSelectDriver": {}, + "labelPrinting": "標籤印製", + "@labelPrinting": {}, + "labelPrintingDetail": "啓用標籤打印功能", + "@labelPrintingDetail": {}, + "labelTemplate": "標籤模板", + "@labelTemplate": {}, + "labelSelectTemplate": "Select Label Template", + "@labelSelectTemplate": {}, + "labelSelectPrinter": "Select Label Printer", + "@labelSelectPrinter": {}, + "language": "語言", + "@language": {}, + "languageDefault": "系統默認語言", + "@languageDefault": {}, + "languageSelect": "選擇語言", + "@languageSelect": {}, + "lastStocktake": "最近庫存盤點", + "@lastStocktake": {}, + "lastUpdated": "最近更新", + "@lastUpdated": {}, + "level": "級", + "@level": {}, + "lineItemAdd": "添加行項目", + "@lineItemAdd": {}, + "lineItem": "行項目", + "@lineItem": {}, + "lineItems": "行項目", + "@lineItems": {}, + "lineItemUpdated": "行項目已更新", + "@lineItemUpdated": {}, + "locateItem": "定位庫存項", + "@locateItem": {}, + "locateLocation": "定位存貨位置", + "@locateLocation": {}, + "locationCreate": "新建倉儲位置", + "@locationCreate": {}, + "locationCreateDetail": "創建新庫存地點", + "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "沒有指定倉儲位置", + "@locationNotSet": {}, + "locationUpdated": "庫存地點已更新", + "@locationUpdated": {}, + "login": "登入", + "@login": {}, + "loginEnter": "輸入登錄詳情", + "@loginEnter": {}, + "loginEnterDetails": "用户名和密碼未存儲在本地", + "@loginEnterDetails": {}, + "link": "鏈接", + "@link": {}, + "lost": "丟失", + "@lost": {}, + "manufacturerPart": "Manufacturer Part", + "@manufacturerPart": {}, + "manufacturerPartEdit": "Edit Manufacturer Part", + "@manufacturerPartEdit": {}, + "manufacturerPartNumber": "製造商零件號", + "@manufacturerPartNumber": {}, + "manufacturer": "製造商", + "@manufacturer": {}, + "manufacturers": "製造商", + "@manufacturers": {}, + "missingData": "缺失數據", + "@missingData": {}, + "name": "名稱", + "@name": {}, + "no": "No", + "@no": {}, + "notApplicable": "N/A", + "@notApplicable": {}, + "notConnected": "未連接", + "@notConnected": {}, + "notes": "備註", + "@notes": { + "description": "Notes" + }, + "notifications": "通知", + "@notifications": {}, + "notificationsEmpty": "沒有未讀通知", + "@notificationsEmpty": {}, + "noResponse": "服務器未響應", + "@noResponse": {}, + "noResults": "無結果", + "@noResults": {}, + "noImageAvailable": "No image available", + "@noImageAvailable": {}, + "noPricingAvailable": "No pricing available", + "@noPricingAvailable": {}, + "noPricingDataFound": "No pricing data found for this part", + "@noPricingDataFound": {}, + "noSubcategories": "無子類別", + "@noSubcategories": {}, + "noSubcategoriesAvailable": "無可用子類別", + "@noSubcategoriesAvailable": {}, + "numberInvalid": "無效的數字", + "@numberInvalid": {}, + "onOrder": "已訂購", + "@onOrder": {}, + "onOrderDetails": "當前訂購項目", + "@onOrderDetails": {}, + "orientation": "屏幕方向​​​​​​​​​​​​​​", + "@orientation": {}, + "orientationDetail": "屏幕方向(需要重啓)", + "@orientationDetail": {}, + "orientationLandscape": "橫向", + "@orientationLandscape": {}, + "orientationPortrait": "縱向", + "@orientationPortrait": {}, + "orientationSystem": "系統", + "@orientationSystem": {}, + "outstanding": "未完成", + "@outstanding": {}, + "outstandingOrderDetail": "顯示未完成的訂單", + "@outstandingOrderDetail": {}, + "overdue": "逾期", + "@overdue": {}, + "overdueDetail": "顯示逾期訂單", + "@overdueDetail": {}, + "packaging": "打包", + "@packaging": {}, + "packageName": "包名", + "@packageName": {}, + "parameters": "參數", + "@parameters": {}, + "parametersSettingDetail": "顯示零件參數", + "@parametersSettingDetail": {}, + "parent": "上級", + "@parent": {}, + "parentCategory": "上級類別", + "@parentCategory": {}, + "parentLocation": "上級地點", + "@parentLocation": {}, + "part": "零件", + "@part": { + "description": "Part (single)" + }, + "partCreate": "新零件", + "@partCreate": {}, + "partCreateDetail": "在此類別中創建新的零件", + "@partCreateDetail": {}, + "partEdited": "零件已更新", + "@partEdited": {}, + "parts": "零件", + "@parts": { + "description": "Part (multiple)" + }, + "partNotSalable": "零件未被標記為可銷售", + "@partNotSalable": {}, + "partsNone": "無零件", + "@partsNone": {}, + "partNoResults": "沒有匹配查詢的零件", + "@partNoResults": {}, + "partPricing": "Part Pricing", + "@partPricing": {}, + "partPricingSettingDetail": "Display part pricing information", + "@pricingSettingDetail": {}, + "partSettings": "零件設置", + "@partSettings": {}, + "partsStarred": "訂閲的零件", + "@partsStarred": {}, + "partsStarredNone": "沒有可用的帶星號零件", + "@partsStarredNone": {}, + "partSuppliers": "零件供應商", + "@partSuppliers": {}, + "partCategory": "零件類別", + "@partCategory": {}, + "partCategoryTopLevel": "上一級零件類別", + "@partCategoryTopLevel": {}, + "partCategories": "零件類別", + "@partCategories": {}, + "partDetails": "零件詳情", + "@partDetails": {}, + "partNotes": "零件註釋", + "@partNotes": {}, + "partStock": "零件庫存", + "@partStock": { + "description": "part stock" + }, + "password": "密碼", + "@password": {}, + "passwordEmpty": "密碼不能為空", + "@passwordEmpty": {}, + "pending": "Pending", + "@pending": {}, + "permissionAccountDenied": "您的賬户沒有執行此操作所需的權限", + "@permissionAccountDenied": {}, + "permissionRequired": "需要授權:", + "@permissionRequired": {}, + "phone": "Phone", + "@phone": {}, + "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": {}, + "purchaseOrderConfirmScan": "Confirm Scan Data", + "@purchaseOrderConfirmScan": {}, + "purchaseOrderConfirmScanDetail": "Confirm details when scanning in items", + "@purchaseOrderConfirmScanDetail": {}, + "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": "採購訂單已更新", + "@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": {}, + "rotateClockwise": "Rotate 90° clockwise", + "@rotateClockwise": {}, + "refreshing": "正在刷新", + "@refreshing": {}, + "rejected": "已拒絕", + "@rejected": {}, + "releaseNotes": "更新日誌", + "@releaseNotes": {}, + "remove": "移除", + "@remove": { + "description": "remove" + }, + "removeStock": "移除庫存", + "@removeStock": { + "description": "remove stock" + }, + "reportBug": "反饋問題", + "@reportBug": {}, + "reportBugDescription": "提交 bug 報告 (需要 GitHub 賬户)", + "@reportBugDescription": {}, + "responsible": "Responsible", + "@responsible": {}, + "results": "結果", + "@results": {}, + "request": "請求", + "@request": {}, + "requestFailed": "請求失敗", + "@requestFailed": {}, + "requestSuccessful": "請求成功", + "@requestSuccessful": {}, + "requestingData": "正在請求數據", + "@requestingData": {}, + "required": "必填", + "@required": { + "description": "This field is required" + }, + "response400": "錯誤的請求", + "@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": "未知響應", + "@responseUnknown": {}, + "result": "結果", + "@result": { + "description": "" + }, + "returned": "已退回", + "@returned": {}, + "salesOrder": "銷售訂單", + "@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": "編輯銷售訂單", + "@salesOrderEdit": {}, + "salesOrderUpdated": "銷售訂單已更新", + "@salesOrderUpdated": {}, + "save": "保存", + "@save": { + "description": "Save" + }, + "scanBarcode": "掃描條碼", + "@scanBarcode": {}, + "scanSupplierPart": "掃描供應商條碼", + "@scanSupplierPart": {}, + "scanIntoLocation": "已掃描至位置", + "@scanIntoLocation": {}, + "scanIntoLocationDetail": "掃描此項目到此位置", + "@scanIntoLocationDetail": {}, + "scannerExternal": "外部掃描器", + "@scannerExternal": {}, + "scannerExternalDetail": "使用外部掃描儀讀取條碼 (分割模式)", + "@scannerExternalDetail": {}, + "scanReceivedParts": "掃描收到的零件", + "@scanReceivedParts": {}, + "search": "搜索", + "@search": { + "description": "search" + }, + "searching": "搜索", + "@searching": {}, + "searchLocation": "搜索倉儲位置", + "@searchLocation": {}, + "searchOrderingField": "Ordering Field", + "@searchOrderingField": {}, + "searchOrderingDirection": "Ordering Direction", + "@searchOrderingDirection": {}, + "searchOrderingAscending": "Ascending", + "@searchOrderingAscending": {}, + "searchOrderingDescending": "Descending", + "@searchOrderingDescending": {}, + "searchParts": "搜索零件", + "@searchParts": {}, + "searchStock": "搜索庫存", + "@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": {}, + "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)", + "@sku": {}, + "sounds": "聲音", + "@sounds": {}, + "soundOnBarcodeAction": "播放條碼動作音效", + "@soundOnBarcodeAction": {}, + "soundOnServerError": "服務器錯誤時播放音效", + "@soundOnServerError": {}, + "startDate": "Start Date", + "@startDate": {}, + "status": "狀態", + "@status": {}, + "statusCode": "狀態碼", + "@statusCode": {}, + "stock": "庫存", + "@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": "庫存項已更新", + "@stockItemUpdateSuccess": {}, + "stockItemUpdateFailure": "庫存項更新失敗", + "@stockItemUpdateFailure": {}, + "stockLocation": "庫存地點", + "@stockLocation": { + "description": "stock location" + }, + "stockLocations": "庫存地點", + "@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": "供應商零件", + "@supplierPart": {}, + "supplierPartEdit": "編輯供應商零件", + "@supplierPartEdit": {}, + "supplierPartNumber": "供應商零件編號", + "@supplierPartNumber": {}, + "supplierPartUpdated": "供應商零件已更新", + "@supplierPartUpdated": {}, + "supplierParts": "供應商零件", + "@supplierParts": {}, + "suppliers": "供應商", + "@suppliers": {}, + "supplierReference": "供應商參考", + "@supplierReference": {}, + "switchCamera": "Switch Camera", + "@switchCamera": {}, + "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": "" + }, + "toggleTorch": "Toggle Torch", + "@toggleTorch": {}, + "tokenError": "令牌錯誤", + "@tokenError": {}, + "tokenMissing": "缺少令牌", + "@tokenMissing": {}, + "tokenMissingFromResponse": "響應中缺少訪問令牌", + "@tokenMissingFromResponse": {}, + "totalPrice": "總價", + "@totalPrice": {}, + "trackingNumber": "Tracking Number", + "@trackingNumber": {}, + "transfer": "轉移", + "@transfer": { + "description": "transfer" + }, + "transferStock": "轉移庫存", + "@transferStock": { + "description": "transfer stock" + }, + "transferStockDetail": "將物品轉移到另一個位置", + "@transferStockDetail": {}, + "transferStockLocation": "轉移庫存地點", + "@transferStockLocation": {}, + "transferStockLocationDetail": "將此庫存地點轉移到另一個", + "@transferStockLocationDetail": {}, + "translate": "轉移", + "@translate": {}, + "translateHelp": "協助翻譯 InvenTree 應用", + "@translateHelp": {}, + "unavailable": "Unavailable", + "@unavailable": {}, + "unavailableDetail": "Item is not available", + "@unavailableDetail": {}, + "unitPrice": "單價", + "@unitPrice": {}, + "units": "單位", + "@units": {}, + "unknownResponse": "未知響應", + "@unknownResponse": {}, + "upload": "上傳", + "@upload": {}, + "uploadFailed": "文件上傳失敗", + "@uploadFailed": {}, + "uploadSuccess": "文件已上傳", + "@uploadSuccess": {}, + "uploadImage": "Upload Image", + "@uploadImage": {}, + "usedIn": "用途", + "@usedIn": {}, + "usedInDetails": "需要此零件的裝配體", + "@usedInDetails": {}, + "username": "用户名", + "@username": {}, + "usernameEmpty": "用户名不能為空", + "@usernameEmpty": {}, + "value": "值", + "@value": { + "description": "value" + }, + "valueCannotBeEmpty": "數值不能為空", + "@valueCannotBeEmpty": {}, + "valueRequired": "值為必填項", + "@valueRequired": {}, + "variants": "變體", + "@variants": {}, + "version": "版本", + "@version": {}, + "viewSupplierPart": "查看供應商零件", + "@viewSupplierPart": {}, + "website": "網站", + "@website": {}, + "yes": "Yes", + "@yes": {}, + "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": {} +} \ No newline at end of file diff --git a/lib/labels.dart b/lib/labels.dart new file mode 100644 index 0000000..2b7cc27 --- /dev/null +++ b/lib/labels.dart @@ -0,0 +1,280 @@ +import "package:flutter/cupertino.dart"; +import "package:flutter/material.dart"; +import "package:inventree/api.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. + * + */ +Future selectAndPrintLabel( + BuildContext context, + String labelType, + int instanceId, +) async { + if (!InvenTreeAPI().isConnected()) { + return; + } + + if (!InvenTreeAPI().supportsModernLabelPrinting) { + // Legacy label printing API not supported + showSnackIcon("Label printing not supported by server", success: false); + return; + } + + // 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?; + } + + // Default plugin + final defaultPlugin = await InvenTreeSettingsManager().getValue( + INV_LABEL_DEFAULT_PLUGIN, + null, + ); + + // 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": { + "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, + PRINT_LABEL_URL, + baseFields, + method: "POST", + modelData: {"plugin": defaultPlugin, "template": defaultTemplate}, + formHandler: formHandler, + onSuccess: (data) async { + handlePrintingSuccess(context, data, 0); + }, + ); +} diff --git a/lib/main.dart b/lib/main.dart index e52a8ff..5db07ee 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,104 +1,190 @@ import "dart:async"; -import "package:flutter_localizations/flutter_localizations.dart"; -import "package:flutter_gen/gen_l10n/app_localizations.dart"; - import "package:flutter/material.dart"; +import "package:flutter/services.dart"; + +import "package:adaptive_theme/adaptive_theme.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/inventree/sentry.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"; - Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - await runZonedGuarded>(() async { + final savedThemeMode = await AdaptiveTheme.getThemeMode(); - PackageInfo info = await PackageInfo.fromPlatform(); - String pkg = info.packageName; - String version = info.version; - String build = info.buildNumber; + await runZonedGuarded>( + () async { + 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}"; - await Sentry.init((options) { - options.dsn = SENTRY_DSN_KEY; - options.release = release; - options.environment = isInDebugMode() ? "debug" : "release"; - }); + 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 { + // 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", + }, + ); + }; - // Ensure that the error gets reported to sentry! - await sentryReportError(details.exception, details.stack); - }; + final int orientation = + await InvenTreeSettingsManager().getValue( + INV_SCREEN_ORIENTATION, + SCREEN_ORIENTATION_SYSTEM, + ) + as int; - runApp( - InvenTreeApp() - ); + List orientations = []; - }, (Object error, StackTrace stackTrace) async { - sentryReportError(error, stackTrace); - }); + 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); + }, + ); } -class InvenTreeApp extends StatelessWidget { +class InvenTreeApp extends StatefulWidget { // This widget is the root of your application. + const InvenTreeApp(this.savedThemeMode); + + final AdaptiveThemeMode? savedThemeMode; + + @override + InvenTreeAppState createState() => InvenTreeAppState(savedThemeMode); + + static InvenTreeAppState? of(BuildContext context) => + context.findAncestorStateOfType(); +} + +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(); + + // Run some async init tasks + runInitTasks(); + } + + // 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 PackageInfo info = await PackageInfo.fromPlatform(); + + if (version != info.version) { + // Save latest version to the settings database + await InvenTreeSettingsManager().setValue("recentVersion", info.version); + + // Load release notes from external file + String notes = await rootBundle.loadString("assets/release_notes.md"); + + // Show the release notes + OneContext().push( + MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)), + ); + } + } + + // Update the app locale + void setLocale(Locale? locale) { + setState(() { + _locale = locale; + }); + } + + Locale? get locale => _locale; + @override Widget build(BuildContext context) { - - return MaterialApp( - debugShowCheckedModeBanner: false, - builder: OneContext().builder, - navigatorKey: OneContext().key, - onGenerateTitle: (BuildContext context) => "InvenTree", - theme: ThemeData( - primarySwatch: Colors.lightBlue, - secondaryHeaderColor: Colors.blueGrey, + return AdaptiveTheme( + light: ThemeData( + brightness: Brightness.light, + colorSchemeSeed: Colors.lightBlueAccent, + useMaterial3: true, + ), + dark: ThemeData( + brightness: Brightness.dark, + colorSchemeSeed: Colors.blue, + useMaterial3: true, + ), + initial: savedThemeMode ?? AdaptiveThemeMode.system, + 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, ), - home: InvenTreeHomePage(), - localizationsDelegates: [ - 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 - ], - ); } -} \ No newline at end of file +} diff --git a/lib/preferences.dart b/lib/preferences.dart index 2c52a88..92eda1f 100644 --- a/lib/preferences.dart +++ b/lib/preferences.dart @@ -1,16 +1,70 @@ import "dart:async"; +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"; +// 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_SHIPMENTS = "homeShowShipments"; +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"; + +// 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_BOM = "partShowBom"; +const String INV_PART_SHOW_PRICING = "partShowPricing"; + +// Stock settings +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"; +const String INV_PO_CONFIRM_SCAN = "poConfirmScan"; + +// 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"; + +// 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; +const int BARCODE_CONTROLLER_WEDGE = 1; /* * Class for storing InvenTree preferences in a NoSql DB */ class InvenTreePreferencesDB { - InvenTreePreferencesDB._(); static final InvenTreePreferencesDB _singleton = InvenTreePreferencesDB._(); @@ -22,7 +76,6 @@ class InvenTreePreferencesDB { bool isOpen = false; Future get database async { - if (!isOpen) { // Calling _openDatabase will also complete the completer with database instance _openDatabase(); @@ -40,46 +93,92 @@ 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 getSelectedLocale() async { + final String locale_name = await getValue("customLocale", "") as String; - // Expand sublocation list in StockLocation view - bool expandLocationList = false; + if (locale_name.isEmpty) { + return null; + } - // Expand item list in StockLocation view - bool expandStockList = true; + for (var locale in supported_locales) { + if (locale.toString() == locale_name) { + return locale; + } + } - // Ensure we only ever create a single instance of the preferences class - static final InvenTreePreferences _api = InvenTreePreferences._internal(); + // No matching locale found + return null; + } -} \ No newline at end of file + Future setSelectedLocale(Locale? locale) async { + await setValue("customLocale", locale?.toString() ?? ""); + } + + Future removeValue(String key) async { + await store.record(key).delete(await _db); + } + + Future getValue(String key, dynamic backup) async { + dynamic value = await store.record(key).get(await _db); + + // Retrieve value + if (value == "__null__") { + value = null; + } + + 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 if (value is String) { + return value.toLowerCase().contains("t"); + } else { + return false; + } + } + + // Store a key:value pair in the database + Future setValue(String key, dynamic value) async { + // Encode null values as strings + value ??= "__null__"; + + 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/about.dart b/lib/settings/about.dart index f62179c..fa11eb3 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -4,68 +4,74 @@ 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:inventree/widget/link_icon.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:inventree/l10.dart"; import "package:url_launcher/url_launcher.dart"; -class InvenTreeAboutWidget extends StatelessWidget { +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); - const String docsUrl = "https://inventree.readthedocs.io/en/latest/app/app/"; - - if (await canLaunch(docsUrl)) { - await launch(docsUrl); + if (await canLaunchUrl(docsUrl)) { + await launchUrl(docsUrl); } } - Future _reportBug(BuildContext context) async { + Future _reportBug(BuildContext context) async { + var url = Uri( + scheme: "https", + host: "github.com", + path: "inventree/inventree-app/issues/new/", + queryParameters: {"title": "Enter bug description"}, + ); - const String url = "https://github.com/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"; + Future _translate() async { + 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); } } @override Widget build(BuildContext context) { - List tiles = []; tiles.add( @@ -74,33 +80,66 @@ 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: FaIcon(FontAwesomeIcons.globe), - trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.timesCircle, 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), + ), ); tiles.add( ListTile( title: Text(L10().version), - subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.infoCircle), - ) + subtitle: Text( + InvenTreeAPI().serverVersion.isNotEmpty + ? InvenTreeAPI().serverVersion + : L10().notConnected, + ), + leading: Icon(TablerIcons.info_circle), + ), ); tiles.add( ListTile( title: Text(L10().serverInstance), - subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : L10().notConnected), - leading: FaIcon(FontAwesomeIcons.server), - ) + subtitle: Text( + InvenTreeAPI().serverInstance.isNotEmpty + ? InvenTreeAPI().serverInstance + : L10().notConnected, + ), + leading: Icon(TablerIcons.server), + ), + ); + + // Display extra tile if the server supports plugins + tiles.add( + ListTile( + title: Text(L10().pluginSupport), + subtitle: Text(L10().pluginSupportDetail), + leading: Icon(TablerIcons.plug), + ), ); } else { tiles.add( @@ -110,8 +149,8 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().serverNotConnected, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.exclamationCircle) - ) + leading: Icon(TablerIcons.exclamation_circle), + ), ); } @@ -121,90 +160,93 @@ class InvenTreeAboutWidget extends StatelessWidget { L10().appDetails, style: TextStyle(fontWeight: FontWeight.bold), ), - ) + ), ); tiles.add( ListTile( title: Text(L10().packageName), subtitle: Text("${info.packageName}"), - leading: FaIcon(FontAwesomeIcons.box) - ) + leading: Icon(TablerIcons.box), + ), ); tiles.add( ListTile( title: Text(L10().version), subtitle: Text("${info.version} - Build ${info.buildNumber}"), - leading: FaIcon(FontAwesomeIcons.infoCircle) - ) + leading: Icon(TablerIcons.info_circle), + ), ); tiles.add( ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + leading: Icon(TablerIcons.file, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { _releaseNotes(context); }, - ) + ), ); tiles.add( ListTile( title: Text(L10().credits), subtitle: Text(L10().appCredits), - leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_CLICK), + leading: Icon(TablerIcons.balloon, color: COLOR_ACTION), + trailing: LinkIcon(), onTap: () { _credits(context); - } - ) + }, + ), ); tiles.add( ListTile( title: Text(L10().documentation), - subtitle: Text("https://inventree.readthedocs.io"), - leading: FaIcon(FontAwesomeIcons.book, color: COLOR_CLICK), + subtitle: Text(DOCS_URL), + leading: Icon(TablerIcons.book, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { _openDocs(); }, - ) + ), ); tiles.add( ListTile( title: Text(L10().translate), subtitle: Text(L10().translateHelp), - leading: FaIcon(FontAwesomeIcons.language, color: COLOR_CLICK), + leading: Icon(TablerIcons.language, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { _translate(); - } - ) + }, + ), ); tiles.add( ListTile( title: Text(L10().reportBug), subtitle: Text(L10().reportBugDescription), - leading: FaIcon(FontAwesomeIcons.bug, color: COLOR_CLICK), + leading: Icon(TablerIcons.bug, color: COLOR_ACTION), + trailing: LinkIcon(external: true), onTap: () { - _reportBug(context); + _reportBug(context); }, - ) + ), ); return Scaffold( appBar: AppBar( title: Text(L10().appAbout), + 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 124246d..ba2d7cb 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -1,10 +1,20 @@ - import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:inventree/api.dart"; +import "package:one_context/one_context.dart"; +import "package:adaptive_theme/adaptive_theme.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"; +import "package:inventree/api_form.dart"; import "package:inventree/l10.dart"; -import "package:inventree/app_settings.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"; class InvenTreeAppSettingsWidget extends StatefulWidget { @override @@ -12,132 +22,298 @@ class InvenTreeAppSettingsWidget extends StatefulWidget { } class _InvenTreeAppSettingsState extends State { - _InvenTreeAppSettingsState(); - final GlobalKey<_InvenTreeAppSettingsState> _settingsKey = GlobalKey<_InvenTreeAppSettingsState>(); + final GlobalKey<_InvenTreeAppSettingsState> _settingsKey = + GlobalKey<_InvenTreeAppSettingsState>(); // Sound settings bool barcodeSounds = true; bool serverSounds = true; - // Part settings - bool partSubcategory = false; - - // Stock settings - bool stockSublocation = false; - bool stockShowHistory = false; - bool reportErrors = true; bool strictHttps = false; + bool enableLabelPrinting = true; + bool darkMode = false; + + int screenOrientation = SCREEN_ORIENTATION_SYSTEM; + + Locale? locale; @override void initState() { super.initState(); - loadSettings(); + loadSettings(OneContext().context!); } - Future loadSettings() async { + Future loadSettings(BuildContext context) async { + showLoadingOverlay(); - // Load initial settings + 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; + darkMode = AdaptiveTheme.of(context).mode.isDark; - partSubcategory = await InvenTreeSettingsManager().getValue(INV_PART_SUBCATEGORY, true) as bool; + locale = await InvenTreeSettingsManager().getSelectedLocale(); - stockSublocation = await InvenTreeSettingsManager().getValue(INV_STOCK_SUBLOCATION, true) as bool; - stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; + hideLoadingOverlay(); - reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; - strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; + if (mounted) { + setState(() {}); + } + } - setState(() { - }); + Future _selectLocale(BuildContext context) async { + List> options = [ + {"display_name": L10().languageDefault, "value": null}, + ]; + + // Construct a list of available locales + for (var locale in supported_locales) { + options.add({ + "display_name": LocaleNames.of(context)!.nameOf(locale.toString()), + "value": locale.toString(), + }); + } + + Map fields = { + "locale": { + "label": L10().language, + "type": "choice", + "choices": options, + "value": locale?.toString(), + }, + }; + + launchApiForm( + context, + L10().languageSelect, + "", + fields, + icon: TablerIcons.circle_check, + onSuccess: (Map data) async { + String locale_name = (data["locale"] ?? "") as String; + Locale? selected_locale; + + for (var locale in supported_locales) { + if (locale.toString() == locale_name) { + selected_locale = locale; + } + } + + await InvenTreeSettingsManager().setSelectedLocale(selected_locale); + + setState(() { + locale = selected_locale; + }); + + // Refresh the entire app locale + InvenTreeApp.of(context)?.setLocale(locale); + + // 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; + } + + IconData orientationIcon = Icons.screen_rotation; + + switch (screenOrientation) { + case SCREEN_ORIENTATION_PORTRAIT: + orientationIcon = Icons.screen_lock_portrait; + case SCREEN_ORIENTATION_LANDSCAPE: + orientationIcon = Icons.screen_lock_landscape; + case SCREEN_ORIENTATION_SYSTEM: + default: + orientationIcon = Icons.screen_rotation; + } return Scaffold( key: _settingsKey, appBar: AppBar( title: Text(L10().appSettings), + backgroundColor: COLOR_APP_BAR, ), body: Container( child: ListView( children: [ - ListTile( - title: Text( - L10().parts, - style: TextStyle(fontWeight: FontWeight.bold), - ), - leading: FaIcon(FontAwesomeIcons.shapes), - ), - ListTile( - title: Text(L10().includeSubcategories), - subtitle: Text(L10().includeSubcategoriesDetail), - leading: FaIcon(FontAwesomeIcons.sitemap), - trailing: Switch( - value: partSubcategory, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_PART_SUBCATEGORY, value); - setState(() { - partSubcategory = value; - }); - }, - ), - ), - /* Stock Settings */ - Divider(height: 3), - ListTile( - title: Text(L10().stock, - style: TextStyle(fontWeight: FontWeight.bold), - ), - leading: FaIcon(FontAwesomeIcons.boxes), - ), - ListTile( - title: Text(L10().includeSublocations), - subtitle: Text(L10().includeSublocationsDetail), - leading: FaIcon(FontAwesomeIcons.sitemap), - trailing: Switch( - value: stockSublocation, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STOCK_SUBLOCATION, value); - setState(() { - stockSublocation = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().stockItemHistory), - subtitle: Text(L10().stockItemHistoryDetail), - leading: FaIcon(FontAwesomeIcons.history), - trailing: Switch( - value: stockShowHistory, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STOCK_SHOW_HISTORY, value); - setState(() { - stockShowHistory = value; - }); - }, - ), - ), /* Sound Settings */ Divider(height: 3), + ListTile( + title: Text( + L10().appSettings, + style: TextStyle(fontWeight: FontWeight.bold), + ), + leading: Icon(TablerIcons.device_mobile), + ), + ListTile( + title: Text(L10().darkMode), + subtitle: Text(L10().darkModeEnable), + leading: Icon(TablerIcons.sun_moon), + trailing: Switch( + value: darkMode, + onChanged: (bool value) { + if (value) { + AdaptiveTheme.of(context).setDark(); + } else { + AdaptiveTheme.of(context).setLight(); + } + setState(() { + darkMode = value; + }); + }, + ), + ), + 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().labelPrinting), + subtitle: Text(L10().labelPrintingDetail), + leading: Icon(TablerIcons.printer), + 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), + leading: Icon(TablerIcons.lock), + trailing: Switch( + value: strictHttps, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_STRICT_HTTPS, value); + setState(() { + strictHttps = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().language), + subtitle: Text(languageName), + leading: Icon(TablerIcons.language), + onTap: () async { + _selectLocale(context); + }, + ), + ListTile( + title: Text(L10().errorReportUpload), + subtitle: Text(L10().errorReportUploadDetails), + leading: Icon(TablerIcons.bug), + trailing: Switch( + value: reportErrors, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_REPORT_ERRORS, value); + setState(() { + reportErrors = value; + }); + }, + ), + ), ListTile( title: Text( L10().sounds, style: TextStyle(fontWeight: FontWeight.bold), ), - leading: FaIcon(FontAwesomeIcons.volumeUp), + 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) { @@ -151,11 +327,14 @@ 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) { - InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); + InvenTreeSettingsManager().setValue( + INV_SOUNDS_BARCODE, + value, + ); setState(() { barcodeSounds = value; }); @@ -163,44 +342,9 @@ class _InvenTreeAppSettingsState extends State { ), ), Divider(height: 1), - ListTile( - title: Text( - L10().appSettings, - style: TextStyle(fontWeight: FontWeight.bold), - ), - leading: FaIcon(FontAwesomeIcons.mobile), - ), - ListTile( - title: Text(L10().strictHttps), - subtitle: Text(L10().strictHttpsDetails), - leading: FaIcon(FontAwesomeIcons.lock), - trailing: Switch( - value: strictHttps, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_STRICT_HTTPS, value); - setState(() { - strictHttps = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().errorReportUpload), - subtitle: Text(L10().errorReportUploadDetails), - leading: FaIcon(FontAwesomeIcons.bug), - trailing: Switch( - value: reportErrors, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_REPORT_ERRORS, value); - setState(() { - reportErrors = value; - }); - }, - ), - ), - ] - ) - ) + ], + ), + ), ); } -} \ No newline at end of file +} diff --git a/lib/settings/barcode_settings.dart b/lib/settings/barcode_settings.dart new file mode 100644 index 0000000..0d70970 --- /dev/null +++ b/lib/settings/barcode_settings.dart @@ -0,0 +1,196 @@ +import "package:flutter/material.dart"; +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"; + +class InvenTreeBarcodeSettingsWidget extends StatefulWidget { + @override + _InvenTreeBarcodeSettingsState createState() => + _InvenTreeBarcodeSettingsState(); +} + +class _InvenTreeBarcodeSettingsState + extends State { + _InvenTreeBarcodeSettingsState(); + + int barcodeScanDelay = 500; + int barcodeScanType = BARCODE_CONTROLLER_CAMERA; + bool barcodeScanSingle = false; + + final TextEditingController _barcodeScanDelayController = + TextEditingController(); + + @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, + ); + + 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) { + // Construct an icon for the barcode scanner input + Widget? barcodeInputIcon; + + switch (barcodeScanType) { + case BARCODE_CONTROLLER_WEDGE: + barcodeInputIcon = Icon(Icons.barcode_reader); + case BARCODE_CONTROLLER_CAMERA: + default: + barcodeInputIcon = Icon(TablerIcons.camera); + } + + return Scaffold( + appBar: AppBar( + title: Text(L10().barcodeSettings), + backgroundColor: COLOR_APP_BAR, + ), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().barcodeScanController), + subtitle: Text(L10().barcodeScanControllerDetail), + leading: Icon(Icons.qr_code_scanner), + trailing: barcodeInputIcon, + onTap: () async { + choiceDialog( + L10().barcodeScanController, + [ + ListTile( + title: Text(L10().cameraInternal), + subtitle: Text(L10().cameraInternalDetail), + leading: Icon(TablerIcons.camera), + ), + ListTile( + title: Text(L10().scannerExternal), + subtitle: Text(L10().scannerExternalDetail), + leading: Icon(Icons.barcode_reader), + ), + ], + onSelected: (idx) async { + barcodeScanType = idx as int; + InvenTreeSettingsManager().setValue( + INV_BARCODE_SCAN_TYPE, + barcodeScanType, + ); + if (mounted) { + setState(() {}); + } + }, + ); + }, + ), + ListTile( + title: Text(L10().barcodeScanDelay), + subtitle: Text(L10().barcodeScanDelayDetail), + leading: Icon(TablerIcons.hourglass), + trailing: GestureDetector( + child: Text("${barcodeScanDelay} ms"), + onTap: () { + _editBarcodeScanDelay(context); + }, + ), + ), + ListTile( + title: Text(L10().barcodeScanSingle), + subtitle: Text(L10().barcodeScanSingleDetail), + leading: Icon(Icons.barcode_reader), + trailing: Switch( + value: barcodeScanSingle, + onChanged: (bool v) { + InvenTreeSettingsManager().setValue( + INV_BARCODE_SCAN_SINGLE, + v, + ); + setState(() { + barcodeScanSingle = v; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 7b93f40..a4da9d2 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -1,11 +1,9 @@ - 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:font_awesome_flutter/font_awesome_flutter.dart"; - -import "package:inventree/app_settings.dart"; +import "package:inventree/preferences.dart"; class HomeScreenSettingsWidget extends StatefulWidget { @override @@ -13,14 +11,16 @@ class HomeScreenSettingsWidget extends StatefulWidget { } class _HomeScreenSettingsState extends State { - _HomeScreenSettingsState(); - final GlobalKey<_HomeScreenSettingsState> _settingsKey = GlobalKey<_HomeScreenSettingsState>(); + final GlobalKey<_HomeScreenSettingsState> _settingsKey = + GlobalKey<_HomeScreenSettingsState>(); // Home screen settings bool homeShowSubscribed = true; bool homeShowPo = true; + bool homeShowSo = true; + bool homeShowShipments = true; bool homeShowSuppliers = true; bool homeShowManufacturers = true; bool homeShowCustomers = true; @@ -32,77 +32,139 @@ 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; - 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; - setState(() { - }); + homeShowShipments = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SHIPMENTS, 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(() {}); } @override Widget build(BuildContext context) { - return Scaffold( - key: _settingsKey, - appBar: AppBar( - title: Text(L10().homeScreen), - ), - body: Container( - child: ListView( - children: [ - ListTile( - title: Text(L10().homeShowSubscribed), - subtitle: Text(L10().homeShowSubscribedDescription), - leading: FaIcon(FontAwesomeIcons.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: FaIcon(FontAwesomeIcons.shoppingCart), - trailing: Switch( - value: homeShowPo, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_PO, value); - setState(() { - homeShowPo = value; - }); - }, - ), - ), - ListTile( - title: Text(L10().homeShowSuppliers), - subtitle: Text(L10().homeShowSuppliersDescription), - leading: FaIcon(FontAwesomeIcons.building), - trailing: Switch( - value: homeShowSuppliers, - onChanged: (bool value) { - InvenTreeSettingsManager().setValue(INV_HOME_SHOW_SUPPLIERS, value); - setState(() { - homeShowSuppliers = 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().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), + 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), - leading: FaIcon(FontAwesomeIcons.industry), + leading: Icon(TablerIcons.building_factory_2), trailing: Switch( value: homeShowManufacturers, onChanged: (bool value) { @@ -113,23 +175,27 @@ class _HomeScreenSettingsState extends State { }, ), ), - ListTile( - title: Text(L10().homeShowCustomers), - subtitle: Text(L10().homeShowCustomersDescription), - leading: FaIcon(FontAwesomeIcons.userTie), - 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 5c29e16..2e04d49 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -1,284 +1,118 @@ 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/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(); - - 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); - - _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); - - _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.questionCircle, - color: COLOR_WARNING - ); - } - - // Reflect the connection status of the server - if (InvenTreeAPI().isConnected()) { - return FaIcon( - FontAwesomeIcons.checkCircle, - color: COLOR_SUCCESS - ); - } else if (InvenTreeAPI().isConnecting()) { - return Spinner( - icon: FontAwesomeIcons.spinner, - color: COLOR_PROGRESS, - ); - } else { - return FaIcon( - FontAwesomeIcons.timesCircle, - 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 ? COLOR_SELECTED : null, - subtitle: Text("${profile.server}"), - trailing: _getProfileIcon(profile), - onTap: () { - _selectProfile(context, profile); - }, - onLongPress: () { - showDialog( - context: context, - 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.edit) - ) - ), - SimpleDialogOption( - onPressed: () { - Navigator.of(context).pop(); - // Navigator.of(context, rootNavigator: true).pop(); - confirmationDialog( - L10().delete, - L10().profileDelete + "?", - onAccept: () { - _deleteProfile(profile); - } - ); - }, - child: ListTile( - title: Text(L10().profileDelete), - leading: FaIcon(FontAwesomeIcons.trashAlt), - ) - ) - ], - ); - } - ); - }, - )); - } - } 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.plusCircle), - 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(profile); -} - -class _ProfileEditState extends State { - - _ProfileEditState(this.profile) : super(); - - UserProfile? profile; - +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(); + + // 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: Icon(TablerIcons.user_check), + ), + ListTile( + title: Text(L10().server), + subtitle: Text(widget.profile.server), + leading: Icon(TablerIcons.server), + ), + Divider(), + ]; + + List after = []; + + 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)), + ), + ); + } return Scaffold( appBar: AppBar( - title: Text(profile == null ? L10().profileAdd : L10().profileEdit), + title: Text(L10().login), + backgroundColor: COLOR_APP_BAR, actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.save), + icon: Icon(TablerIcons.transition_right, color: COLOR_SUCCESS), onPressed: () async { - if (formKey.currentState!.validate()) { - formKey.currentState!.save(); - - UserProfile? prf = 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); }, - ) - ] + ), + ], ), body: Form( key: formKey, @@ -288,80 +122,14 @@ class _ProfileEditState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - TextFormField( - decoration: InputDecoration( - labelText: L10().profileName, - labelStyle: TextStyle(fontWeight: FontWeight.bold), - ), - initialValue: 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: 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) { - print("Scheme: ${uri.scheme}"); - if (!["http", "https"].contains(uri.scheme.toLowerCase())) { - return L10().serverStart; - } - } else { - return L10().invalidHost; - } - } - - // Everything is OK - return null; - }, - ), + ...before, TextFormField( decoration: InputDecoration( labelText: L10().username, labelStyle: TextStyle(fontWeight: FontWeight.bold), - hintText: L10().enterUsername + hintText: L10().enterUsername, ), - initialValue: profile?.username ?? "", + initialValue: "", keyboardType: TextInputType.text, onSaved: (value) { username = value?.trim() ?? ""; @@ -379,12 +147,22 @@ class _ProfileEditState extends State { 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: profile?.password ?? "", + initialValue: "", keyboardType: TextInputType.visiblePassword, - obscureText: true, + obscureText: _obscured, onSaved: (value) { - password = value ?? ""; + password = value?.trim() ?? ""; }, validator: (value) { if (value == null || value.trim().isEmpty) { @@ -392,14 +170,14 @@ class _ProfileEditState extends State { } 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 new file mode 100644 index 0000000..aa13678 --- /dev/null +++ b/lib/settings/part_settings.dart @@ -0,0 +1,154 @@ +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"; + +class InvenTreePartSettingsWidget extends StatefulWidget { + @override + _InvenTreePartSettingsState createState() => _InvenTreePartSettingsState(); +} + +class _InvenTreePartSettingsState extends State { + _InvenTreePartSettingsState(); + + bool partShowBom = true; + bool partShowPricing = true; + bool stockShowHistory = false; + bool stockShowTests = false; + bool stockConfirmScan = false; + + @override + void initState() { + super.initState(); + + loadSettings(); + } + + Future loadSettings() async { + 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(() {}); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(L10().partSettings), + backgroundColor: COLOR_APP_BAR, + ), + body: Container( + child: ListView( + children: [ + ListTile( + title: Text(L10().bom), + subtitle: Text(L10().bomEnable), + leading: Icon(TablerIcons.list), + trailing: Switch( + value: partShowBom, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_PART_SHOW_BOM, value); + setState(() { + partShowBom = value; + }); + }, + ), + ), + 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), + subtitle: Text(L10().stockItemHistoryDetail), + leading: Icon(TablerIcons.history), + trailing: Switch( + value: stockShowHistory, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_STOCK_SHOW_HISTORY, + value, + ); + setState(() { + stockShowHistory = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().testResults), + subtitle: Text(L10().testResultsDetail), + leading: Icon(TablerIcons.test_pipe), + trailing: Switch( + value: stockShowTests, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_STOCK_SHOW_TESTS, + value, + ); + setState(() { + stockShowTests = value; + }); + }, + ), + ), + ListTile( + title: Text(L10().confirmScan), + subtitle: Text(L10().confirmScanDetail), + leading: Icon(TablerIcons.qrcode), + trailing: Switch( + value: stockConfirmScan, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue( + INV_STOCK_CONFIRM_SCAN, + value, + ); + setState(() { + stockConfirmScan = value; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/settings/purchase_order_settings.dart b/lib/settings/purchase_order_settings.dart new file mode 100644 index 0000000..8b6452c --- /dev/null +++ b/lib/settings/purchase_order_settings.dart @@ -0,0 +1,108 @@ +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"; + +class InvenTreePurchaseOrderSettingsWidget extends StatefulWidget { + @override + _InvenTreePurchaseOrderSettingsState createState() => + _InvenTreePurchaseOrderSettingsState(); +} + +class _InvenTreePurchaseOrderSettingsState + extends State { + _InvenTreePurchaseOrderSettingsState(); + + bool poEnable = true; + bool poShowCamera = true; + bool poConfirmScan = 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, + ); + poConfirmScan = await InvenTreeSettingsManager().getBool( + INV_PO_CONFIRM_SCAN, + true, + ); + + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + 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; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/settings/release.dart b/lib/settings/release.dart index b04b1eb..7f8e11d 100644 --- a/lib/settings/release.dart +++ b/lib/settings/release.dart @@ -1,45 +1,68 @@ import "package:flutter/material.dart"; import "package:flutter_markdown/flutter_markdown.dart"; -import "package:inventree/l10.dart"; +import "package:inventree/app_colors.dart"; +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) + title: Text(L10().releaseNotes), + backgroundColor: COLOR_APP_BAR, ), body: Markdown( selectable: false, data: releaseNotes, - ) + onTapLink: (url, href, title) { + var link = href ?? ""; + if (link.isNotEmpty) { + 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)) { + await launchUrl(link); + } + } + @override - Widget build (BuildContext context) { + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(L10().credits), + backgroundColor: COLOR_APP_BAR, ), body: Markdown( selectable: false, - data: credits - ) + data: credits, + onTapLink: (url, href, title) { + var link = href ?? ""; + if (link.isNotEmpty) { + openLink(link); + } + }, + ), ); } -} \ 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..e009f86 --- /dev/null +++ b/lib/settings/sales_order_settings.dart @@ -0,0 +1,86 @@ +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"; + +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), + 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; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/settings/select_server.dart b/lib/settings/select_server.dart new file mode 100644 index 0000000..bfeae98 --- /dev/null +++ b/lib/settings/select_server.dart @@ -0,0 +1,421 @@ +import "package:flutter/material.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"; +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 Icon(TablerIcons.circle_check, color: COLOR_SUCCESS); + } else if (InvenTreeAPI().isConnecting()) { + return Spinner(icon: TablerIcons.loader_2, color: COLOR_PROGRESS); + } else { + 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( + 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: Icon(TablerIcons.server), + ), + ), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + _editProfile(context, userProfile: profile); + }, + child: ListTile( + title: Text(L10().profileEdit), + leading: Icon(TablerIcons.edit), + ), + ), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + _logoutProfile(context, userProfile: profile); + }, + child: ListTile( + title: Text(L10().profileLogout), + leading: Icon(TablerIcons.logout), + ), + ), + Divider(), + SimpleDialogOption( + onPressed: () { + Navigator.of(context).pop(); + // Navigator.of(context, rootNavigator: true).pop(); + confirmationDialog( + L10().delete, + L10().profileDelete + "?", + color: Colors.red, + icon: TablerIcons.trash, + onAccept: () { + _deleteProfile(profile); + }, + ); + }, + child: ListTile( + 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))); + } + + return Scaffold( + key: _loginKey, + appBar: AppBar( + title: Text(L10().profileSelect), + backgroundColor: COLOR_APP_BAR, + actions: [ + IconButton( + icon: Icon(TablerIcons.circle_plus), + 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( + backgroundColor: COLOR_APP_BAR, + title: Text( + widget.profile == null ? L10().profileAdd : L10().profileEdit, + ), + actions: [ + IconButton( + icon: Icon(TablerIcons.circle_check), + 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), + ), + ), + ); + } +} diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index b1b07ae..3815127 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -1,74 +1,163 @@ -import "package:inventree/app_colors.dart"; -import "package:inventree/settings/app_settings.dart"; -import "package:inventree/settings/home_settings.dart"; -import "package:inventree/settings/login.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: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/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"; +import "package:inventree/widget/link_icon.dart"; + +// InvenTree settings view class InvenTreeSettingsWidget extends StatefulWidget { - // InvenTree settings view - @override _InvenTreeSettingsState createState() => _InvenTreeSettingsState(); - } - 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( key: _scaffoldKey, appBar: AppBar( title: Text(L10().settings), + backgroundColor: COLOR_APP_BAR, ), body: Center( child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: [ - ListTile( - title: Text(L10().server), - subtitle: Text(L10().configureServer), - leading: FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK), - onTap: _editServerSettings, - ), - ListTile( - title: Text(L10().homeScreen), - subtitle: Text(L10().homeScreenSettings), - leading: FaIcon(FontAwesomeIcons.home, color: COLOR_CLICK), - onTap: _editHomeScreenSettings, - ), - ListTile( - title: Text(L10().appSettings), - subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK), - onTap: _editAppSettings, - ), - ] - ).toList() - ) - ) + children: [ + ListTile( + title: Text(L10().server), + subtitle: Text(L10().configureServer), + leading: Icon(TablerIcons.server, color: COLOR_ACTION), + trailing: LinkIcon(), + 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), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeAppSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().homeScreen), + subtitle: Text(L10().homeScreenSettings), + leading: Icon(TablerIcons.home, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => HomeScreenSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().barcodes), + subtitle: Text(L10().barcodeSettings), + leading: Icon(TablerIcons.barcode, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeBarcodeSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().part), + subtitle: Text(L10().partSettings), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: LinkIcon(), + 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), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + InvenTreePurchaseOrderSettingsWidget(), + ), + ); + }, + ), + ListTile( + title: Text(L10().salesOrder), + subtitle: Text(L10().salesOrderSettings), + leading: Icon(TablerIcons.truck, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvenTreeSalesOrderSettingsWidget(), + ), + ); + }, + ), + Divider(), + ListTile( + title: Text(L10().about), + leading: Icon(TablerIcons.info_circle, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: _about, + ), + ], + ), + ), ); } - - Future _editServerSettings() async { - - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget())); - } - - Future _editHomeScreenSettings() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); - } - - Future _editAppSettings() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); - } - -} \ No newline at end of file +} diff --git a/lib/user_profile.dart b/lib/user_profile.dart index 251aa30..f53b412 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -1,28 +1,32 @@ - import "package:sembast/sembast.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/preferences.dart"; class UserProfile { - 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( + 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; @@ -32,11 +36,8 @@ class UserProfile { // Base address of the InvenTree server String server = ""; - // Username - String username = ""; - - // Password - String password = ""; + // API token + String token = ""; bool selected = false; @@ -46,95 +47,116 @@ 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}"; } } +/* + * Class for storing and managing user (server) profiles + */ class UserProfileDBManager { - final store = StoreRef("profiles"); 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 profiles = await getAllProfiles(); - final finder = Finder(filter: Filter.equals("name", name)); + for (var prf in profiles) { + if (name == prf.name) { + return true; + } + } - final profiles = await store.find(await _db, finder: finder); - - 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) { + 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 true; + } else { + debug("Adding new profile: '${profile.name}'"); } - int key = await store.add(await _db, profile.toJson()) as int; - - print("Added user profile <${key}> - '${profile.name}'"); + int? key = await store.add(await _db, profile.toJson()) as int?; // Record the key profile.key = key; + + return true; } - Future selectProfile(int key) async { - /* - * Mark the particular profile as selected - */ - - 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; + /* + * 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) { + 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 { + debug("deleteProfile: ${profile.name}"); + 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); - for (int idx = 0; idx < profiles.length; idx++) { + 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, - profiles[idx].value as Map, + profiles[idx].key! as int, + profiles[idx].value! as Map, profiles[idx].key == selected, ); } @@ -147,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); @@ -155,17 +176,103 @@ 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, - )); + 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, + ); + + // Don't add a new profile if we have added it previously + if (!added) { + await InvenTreeSettingsManager().setValue("demo_profile_added", true); + + UserProfile demoProfile = UserProfile( + name: "InvenTree Demo", + server: "https://demo.inventree.org", + ); + + await addProfile(demoProfile); + + profileList.add(demoProfile); } } 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) + */ + Future getProfileByName(String name) async { + final profiles = await getAllProfiles(); + + UserProfile? prf; + + for (UserProfile profile in profiles) { + if (profile.name == name) { + prf = profile; + break; + } + } + + return prf; + } + + /* + * 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/attachment_widget.dart b/lib/widget/attachment_widget.dart new file mode 100644 index 0000000..721909d --- /dev/null +++ b/lib/widget/attachment_widget.dart @@ -0,0 +1,278 @@ +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/l10.dart"; +import "package:inventree/app_colors.dart"; +import "package:inventree/widget/fields.dart"; +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. + * + * To allow use with different "types" of attachments, + * we pass a subclassed instance of the InvenTreeAttachment model. + */ +class AttachmentWidget extends StatefulWidget { + const AttachmentWidget( + this.modelType, + this.modelId, + this.imagePrefix, + this.hasUploadPermission, + ) : super(); + + final String modelType; + final int modelId; + final bool hasUploadPermission; + final String imagePrefix; + + @override + _AttachmentWidgetState createState() => _AttachmentWidgetState(); +} + +class _AttachmentWidgetState extends RefreshableState { + _AttachmentWidgetState(); + + List attachments = []; + + @override + String getAppBarTitle() => L10().attachments; + + @override + List appBarActions(BuildContext context) { + if (!widget.hasUploadPermission) return []; + + return [ + IconButton( + icon: Icon(TablerIcons.camera), + onPressed: () async { + InvenTreeAttachment() + .uploadImage( + widget.modelType, + widget.modelId, + prefix: widget.imagePrefix, + ) + .then((_) { + refresh(context); + }); + }, + ), + IconButton( + icon: Icon(TablerIcons.file_upload), + onPressed: () async { + FilePickerDialog.pickFileFromDevice().then((File? file) { + upload(context, file).then((_) { + refresh(context); + }); + }); + }, + ), + ]; + } + + Future upload(BuildContext context, File? file) async { + if (file == null) return; + + showLoadingOverlay(); + + final bool result = await InvenTreeAttachment().uploadAttachment( + file, + widget.modelType, + widget.modelId, + ); + + hideLoadingOverlay(); + + if (result) { + showSnackIcon(L10().uploadSuccess, success: true); + } else { + showSnackIcon(L10().uploadFailed, success: false); + } + + 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 { + final bool result = await attachment.delete(); + + showSnackIcon( + result ? L10().deleteSuccess : L10().deleteFailed, + success: result, + ); + + refresh(context); + } + + /* + * Display an option context menu for the selected attachment + */ + Future showOptionsMenu( + BuildContext context, + InvenTreeAttachment attachment, + ) async { + OneContext().showDialog( + builder: (BuildContext ctx) { + return SimpleDialog( + title: Text(L10().attachments), + children: [ + Divider(), + SimpleDialogOption( + onPressed: () async { + OneContext().popDialog(); + editAttachment(context, attachment); + }, + child: ListTile( + title: Text(L10().edit), + leading: Icon(TablerIcons.edit), + ), + ), + SimpleDialogOption( + onPressed: () async { + OneContext().popDialog(); + deleteAttachment(context, attachment); + }, + child: ListTile( + title: Text(L10().delete), + leading: Icon(TablerIcons.trash, color: COLOR_DANGER), + ), + ), + ], + ); + }, + ); + } + + @override + Future request(BuildContext context) async { + Map filters = {}; + + filters["model_type"] = widget.modelType; + filters["model_id"] = widget.modelId.toString(); + + List _attachments = []; + + InvenTreeAttachment().list(filters: filters).then((var results) { + for (var result in results) { + if (result is InvenTreeAttachment) { + _attachments.add(result); + } + } + + if (mounted) { + setState(() { + attachments = _attachments; + }); + } + }); + } + + @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.hasLink) { + tiles.add( + ListTile( + title: Text(attachment.link), + subtitle: Text(attachment.comment), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () async { + attachment.openLink(); + }, + onLongPress: () { + showOptionsMenu(context, attachment); + }, + ), + ); + } + } + + if (tiles.isEmpty) { + tiles.add( + ListTile( + leading: Icon(TablerIcons.file_x, color: COLOR_WARNING), + title: Text(L10().attachmentNone), + ), + ); + } + + 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/back.dart b/lib/widget/back.dart index 04f0325..f5d342a 100644 --- a/lib/widget/back.dart +++ b/lib/widget/back.dart @@ -1,18 +1,15 @@ +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( onLongPress: () { // Display the menu key.currentState!.openDrawer(); - print("hello?"); }, child: IconButton( icon: BackButtonIcon(), @@ -23,4 +20,4 @@ Widget backButton(BuildContext context, GlobalKey key) { }, ), ); -} \ No newline at end of file +} diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart deleted file mode 100644 index 8cd5081..0000000 --- a/lib/widget/category_display.dart +++ /dev/null @@ -1,388 +0,0 @@ -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/part.dart"; -import "package:inventree/widget/part_list.dart"; -import "package:inventree/widget/progress.dart"; -import "package:inventree/widget/snacks.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/widget/part_detail.dart"; -import "package:inventree/widget/refreshable_state.dart"; - - -class CategoryDisplayWidget extends StatefulWidget { - - const CategoryDisplayWidget(this.category, {Key? key}) : super(key: key); - - final InvenTreePartCategory? category; - - @override - _CategoryDisplayState createState() => _CategoryDisplayState(category); -} - - -class _CategoryDisplayState extends RefreshableState { - - _CategoryDisplayState(this.category); - - @override - String getAppBarTitle(BuildContext context) => L10().partCategory; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - if ((category != null) && InvenTreeAPI().checkPermission("part_category", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { - _editCategoryDialog(context); - }, - ) - ); - } - - return actions; - - } - - void _editCategoryDialog(BuildContext context) { - final _cat = category; - - // Cannot edit top-level category - if (_cat == null) { - return; - } - - _cat.editForm( - context, - L10().editCategory, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().categoryUpdated, success: true); - } - ); - } - - // The local InvenTreePartCategory object - final InvenTreePartCategory? category; - - List _subcategories = []; - - @override - Future onBuild(BuildContext context) async { - refresh(context); - } - - @override - Future request(BuildContext context) async { - - int pk = category?.pk ?? -1; - - // Update the category - if (category != null) { - final bool result = await category?.reload() ?? false; - - if (!result) { - Navigator.of(context).pop(); - } - } - - // Request a list of sub-categories under this one - await InvenTreePartCategory().list(filters: {"parent": "$pk"}).then((var cats) { - _subcategories.clear(); - - for (var cat in cats) { - if (cat is InvenTreePartCategory) { - _subcategories.add(cat); - } - } - - // Update state - setState(() {}); - }); - } - - Widget getCategoryDescriptionCard({bool extra = true}) { - if (category == null) { - return Card( - child: ListTile( - title: Text(L10().partCategoryTopLevel) - ) - ); - } else { - - List children = [ - ListTile( - title: Text("${category?.name}", - style: TextStyle(fontWeight: FontWeight.bold) - ), - subtitle: Text("${category?.description}"), - ), - ]; - - if (extra) { - children.add( - ListTile( - title: Text(L10().parentCategory), - subtitle: Text("${category?.parentpathstring}"), - leading: FaIcon( - FontAwesomeIcons.levelUpAlt, - color: COLOR_CLICK, - ), - onTap: () { - if (category == null || ((category?.parentId ?? 0) < 0)) { - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); - } else { - // TODO - Refactor this code into the InvenTreePart class - InvenTreePartCategory().get(category?.parentId ?? -1).then((var cat) { - if (cat is InvenTreePartCategory) { - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(cat))); - } - }); - } - }, - ) - ); - } - - return Card( - 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.shapes), - label: L10().parts, - ), - // TODO - Add the "actions" item back in - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions - ), - ] - ); - } - - List detailTiles() { - List tiles = [ - getCategoryDescriptionCard(), - ListTile( - title: Text( - L10().subcategories, - style: TextStyle(fontWeight: FontWeight.bold) - ), - trailing: _subcategories.isNotEmpty ? Text("${_subcategories.length}") : null, - ), - ]; - - if (loading) { - tiles.add(progressIndicator()); - } else if (_subcategories.isEmpty) { - tiles.add(ListTile( - title: Text(L10().noSubcategories), - subtitle: Text( - L10().noSubcategoriesAvailable, - style: TextStyle(fontStyle: FontStyle.italic) - ) - )); - } else { - tiles.add(SubcategoryList(_subcategories)); - } - - return tiles; - } - - Future _newCategory(BuildContext context) async { - - int pk = category?.pk ?? -1; - - InvenTreePartCategory().createForm( - context, - L10().categoryCreate, - data: { - "parent": (pk > 0) ? pk : null, - }, - onSuccess: (result) async { - - Map data = result as Map; - - if (data.containsKey("pk")) { - var cat = InvenTreePartCategory.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(cat) - ) - ); - } else { - refresh(context); - } - } - ); - } - - Future _newPart() async { - - int pk = category?.pk ?? -1; - - InvenTreePart().createForm( - context, - L10().partCreate, - data: { - "category": (pk > 0) ? pk : null - }, - onSuccess: (result) async { - - Map data = result as Map; - - if (data.containsKey("pk")) { - var part = InvenTreePart.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartDetailWidget(part) - ) - ); - } - } - ); - } - - 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 (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.userTimes), - ) - ); - } - - return tiles; - } - - int partCount = 0; - - @override - Widget getBody(BuildContext context) { - - switch (tabIndex) { - case 0: - return ListView( - children: detailTiles() - ); - case 1: - return PaginatedPartList( - { - "category": "${category?.pk ?? 'null'}" - }, - ); - case 2: - return ListView( - children: actionTiles(context) - ); - default: - return ListView(); - } - } -} - - -/* - * Builder for displaying a list of PartCategory objects - */ -class SubcategoryList extends StatelessWidget { - - const SubcategoryList(this._categories); - - final List _categories; - - void _openCategory(BuildContext context, int pk) { - - // Attempt to load the sub-category. - InvenTreePartCategory().get(pk).then((var cat) { - if (cat is InvenTreePartCategory) { - - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(cat))); - } - }); - } - - Widget _build(BuildContext context, int index) { - InvenTreePartCategory cat = _categories[index]; - - return ListTile( - title: Text("${cat.name}"), - subtitle: Text("${cat.description}"), - trailing: Text("${cat.partcount}"), - onTap: () { - _openCategory(context, cat.pk); - } - ); - } - - @override - Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - separatorBuilder: (_, __) => const Divider(height: 3), - itemBuilder: _build, itemCount: _categories.length); - } -} diff --git a/lib/widget/category_list.dart b/lib/widget/category_list.dart deleted file mode 100644 index 8bb2465..0000000 --- a/lib/widget/category_list.dart +++ /dev/null @@ -1,80 +0,0 @@ -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/paginator.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/l10.dart"; - -class PartCategoryList extends StatefulWidget { - - const PartCategoryList(this.filters); - - final Map filters; - - @override - _PartCategoryListState createState() => _PartCategoryListState(filters); - -} - - -class _PartCategoryListState extends RefreshableState { - - _PartCategoryListState(this.filters); - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => L10().partCategories; - - @override - Widget getBody(BuildContext context) { - return PaginatedPartCategoryList(filters); - } -} - - -class PaginatedPartCategoryList extends StatefulWidget { - - const PaginatedPartCategoryList(this.filters); - - final Map filters; - - @override - _PaginatedPartCategoryListState createState() => _PaginatedPartCategoryListState(filters); -} - - -class _PaginatedPartCategoryListState extends PaginatedSearchState { - - _PaginatedPartCategoryListState(Map filters) : super(filters); - - @override - 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( - title: Text(category.name), - subtitle: Text(category.pathstring), - trailing: Text("${category.partcount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(category) - ) - ); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/company/company_detail.dart b/lib/widget/company/company_detail.dart new file mode 100644 index 0000000..9a6d233 --- /dev/null +++ b/lib/widget/company/company_detail.dart @@ -0,0 +1,437 @@ +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"; +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/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/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"; + +/* + * 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; + + int outstandingPurchaseOrders = 0; + int outstandingSalesOrders = 0; + + int parameterCount = 0; + int attachmentCount = 0; + + @override + String getAppBarTitle() { + String title = L10().company; + + if (widget.company.name.isNotEmpty) { + title += " - ${widget.company.name}"; + } + + return title; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (InvenTreeCompany().canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().companyEdit, + onPressed: () { + editCompany(context); + }, + ), + ); + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (widget.company.isCustomer && InvenTreeSalesOrder().canCreate) { + 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); + }, + ), + ); + } + + 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); + order.goToDetailPage(context); + } + }, + ); + } + + 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); + order.goToDetailPage(context); + } + }, + ); + } + + @override + Future request(BuildContext context) async { + final bool result = await widget.company.reload(); + + if (!result || widget.company.pk <= 0) { + // Company could not be loaded for some reason + Navigator.of(context).pop(); + return; + } + + 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; + }); + } + }); + + 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) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } + + Future editCompany(BuildContext context) async { + widget.company.editForm( + context, + L10().companyEdit, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().companyUpdated, success: true); + }, + ); + } + + /* + * Construct a list of tiles to display for this Company instance + */ + @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), + ), + ), + ); + + 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), + ), + ); + } + + if (widget.company.website.isNotEmpty) { + tiles.add( + ListTile( + 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); + }, + ), + ); + + sep = true; + } + + if (widget.company.email.isNotEmpty) { + tiles.add( + ListTile( + 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}"); + }, + ), + ); + + sep = true; + } + + if (widget.company.phone.isNotEmpty) { + tiles.add( + ListTile( + 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}"); + }, + ), + ); + + sep = true; + } + + // External link + if (widget.company.hasLink) { + tiles.add( + ListTile( + title: Text(L10().link), + subtitle: Text("${widget.company.link}"), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + trailing: LinkIcon(external: true), + onTap: () { + widget.company.openLink(); + }, + ), + ); + + sep = true; + } + + if (sep) { + tiles.add(Divider()); + } + + if (widget.company.isSupplier) { + if (supplierPartCount > 0) { + tiles.add( + ListTile( + title: Text(L10().supplierParts), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(text: supplierPartCount.toString()), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SupplierPartList({ + "supplier": widget.company.pk.toString(), + }), + ), + ); + }, + ), + ); + } + + tiles.add( + ListTile( + title: Text(L10().purchaseOrders), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), + trailing: LinkIcon(text: "${outstandingPurchaseOrders}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderListWidget( + filters: {"supplier": "${widget.company.pk}"}, + ), + ), + ); + }, + ), + ); + + // TODO: Display "supplied parts" count (click through to list of supplier parts) + /* + tiles.add( + ListTile( + title: Text(L10().suppliedParts), + leading: Icon(TablerIcons.box), + trailing: LargeText("${company.partSuppliedCount}"), + ) + ); + */ + } + + if (widget.company.isManufacturer) { + // TODO - Add list of manufacturer parts + } + + if (widget.company.isCustomer) { + tiles.add( + ListTile( + title: Text(L10().salesOrders), + leading: Icon(TablerIcons.truck, color: COLOR_ACTION), + trailing: LinkIcon(text: "${outstandingSalesOrders}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget( + filters: {"customer": widget.company.pk.toString()}, + ), + ), + ); + }, + ), + ); + } + + if (widget.company.notes.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.company.notes), + leading: Icon(TablerIcons.note), + onTap: null, + ), + ); + } + + 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, + widget.company.pk, + widget.company.name, + attachmentCount, + widget.company.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + + return tiles; + } +} diff --git a/lib/widget/company/company_list.dart b/lib/widget/company/company_list.dart new file mode 100644 index 0000000..69b851d --- /dev/null +++ b/lib/widget/company/company_list.dart @@ -0,0 +1,135 @@ +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/l10.dart"; + +import "package:inventree/inventree/company.dart"; +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); + + final String title; + + final Map filters; + + @override + _CompanyListWidgetState createState() => _CompanyListWidgetState(); +} + +class _CompanyListWidgetState extends RefreshableState { + _CompanyListWidgetState(); + + @override + String getAppBarTitle() => widget.title; + + Future _addCompany(BuildContext context) async { + InvenTreeCompany().createForm( + context, + L10().companyAdd, + data: widget.filters, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var company = InvenTreeCompany.fromJson(data); + company.goToDetailPage(context); + } + }, + ); + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreeAPI().checkPermission("company", "add")) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().companyAdd, + onTap: () { + _addCompany(context); + }, + ), + ); + } + + return actions; + } + + @override + Widget getBody(BuildContext context) { + return PaginatedCompanyList(widget.title, widget.filters); + } +} + +class PaginatedCompanyList extends PaginatedSearchWidget { + const PaginatedCompanyList(this.companyTitle, Map filters) + : super(filters: filters); + + final String companyTitle; + + @override + String get searchTitle => companyTitle; + + @override + _CompanyListState createState() => _CompanyListState(); +} + +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 { + 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( + title: Text(company.name), + subtitle: Text(company.description), + leading: InvenTreeAPI().getThumbnail(company.image), + onTap: () async { + company.goToDetailPage(context); + }, + ); + } +} diff --git a/lib/widget/company/manufacturer_part_detail.dart b/lib/widget/company/manufacturer_part_detail.dart new file mode 100644 index 0000000..57a7e48 --- /dev/null +++ b/lib/widget/company/manufacturer_part_detail.dart @@ -0,0 +1,233 @@ +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"; +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"; +import "package:inventree/widget/progress.dart"; + +/* + * Detail widget for viewing a single ManufacturerPart instance + */ +class ManufacturerPartDetailWidget extends StatefulWidget { + const ManufacturerPartDetailWidget(this.manufacturerPart, {Key? key}) + : super(key: key); + + final InvenTreeManufacturerPart manufacturerPart; + + @override + _ManufacturerPartDisplayState createState() => + _ManufacturerPartDisplayState(); +} + +class _ManufacturerPartDisplayState + extends RefreshableState { + _ManufacturerPartDisplayState(); + + int parameterCount = 0; + int attachmentCount = 0; + + @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(); + 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 { + 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 = []; + + // 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) { + part.goToDetailPage(context); + } + }, + ), + ); + + // 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) { + supplier.goToDetailPage(context); + } + }, + ), + ); + + // 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.hasLink) { + tiles.add( + ListTile( + title: Text(widget.manufacturerPart.link), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + onTap: () async { + widget.manufacturerPart.openLink(); + }, + ), + ); + } + + 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 new file mode 100644 index 0000000..ed60748 --- /dev/null +++ b/lib/widget/company/supplier_part_detail.dart @@ -0,0 +1,350 @@ +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"; +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/parameter_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/company/manufacturer_part_detail.dart"; +import "package:inventree/widget/stock/stock_list.dart"; + +/* + * Detail widget for viewing a single SupplierPart instance + */ +class SupplierPartDetailWidget extends StatefulWidget { + const SupplierPartDetailWidget(this.supplierPart, {Key? key}) + : super(key: key); + + final InvenTreeSupplierPart supplierPart; + + @override + _SupplierPartDisplayState createState() => _SupplierPartDisplayState(); +} + +class _SupplierPartDisplayState + extends RefreshableState { + _SupplierPartDisplayState(); + + int parameterCount = 0; + int attachmentCount = 0; + + @override + 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); + }, + ); + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (widget.supplierPart.canEdit) { + actions.add( + customBarcodeAction( + context, + this, + widget.supplierPart.customBarcode, + "supplierpart", + widget.supplierPart.pk, + ), + ); + } + + return actions; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.supplierPart.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + 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(); + + 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; + }); + } + }); + } + + /* + * Build a set of tiles to display for this SupplierPart + */ + @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.supplierPart.partName), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + showLoadingOverlay(); + final part = await InvenTreePart().get(widget.supplierPart.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + }, + ), + ); + + if (!widget.supplierPart.active) { + tiles.add( + ListTile( + title: Text(L10().inactive, style: TextStyle(color: COLOR_DANGER)), + subtitle: Text( + L10().inactiveDetail, + style: TextStyle(color: COLOR_DANGER), + ), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + ), + ); + } + + // 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( + title: Text(L10().supplier), + subtitle: Text(widget.supplierPart.supplierName), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + showLoadingOverlay(); + var supplier = await InvenTreeCompany().get( + widget.supplierPart.supplierId, + ); + hideLoadingOverlay(); + + if (supplier is InvenTreeCompany) { + supplier.goToDetailPage(context); + } + }, + ), + ); + + // SKU (part number) + tiles.add( + ListTile( + title: Text(L10().supplierPartNumber), + subtitle: Text(widget.supplierPart.SKU), + leading: Icon(TablerIcons.hash), + ), + ); + + // Manufacturer information + if (widget.supplierPart.manufacturerPartId > 0) { + tiles.add( + ListTile( + title: Text(L10().manufacturer), + subtitle: Text(widget.supplierPart.manufacturerName), + leading: Icon(TablerIcons.building_factory_2, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + showLoadingOverlay(); + var supplier = await InvenTreeCompany().get( + widget.supplierPart.manufacturerId, + ); + hideLoadingOverlay(); + + if (supplier is InvenTreeCompany) { + supplier.goToDetailPage(context); + } + }, + ), + ); + + tiles.add( + ListTile( + title: Text(L10().manufacturerPart), + subtitle: Text(widget.supplierPart.MPN), + leading: Icon(TablerIcons.hash, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + showLoadingOverlay(); + var manufacturerPart = await InvenTreeManufacturerPart().get( + widget.supplierPart.manufacturerPartId, + ); + hideLoadingOverlay(); + + if (manufacturerPart is InvenTreeManufacturerPart) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ManufacturerPartDetailWidget(manufacturerPart), + ), + ); + } + }, + ), + ); + } + + // Packaging + 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, + leading: Icon(TablerIcons.package), + trailing: widget.supplierPart.pack_quantity.isNotEmpty + ? LargeText(widget.supplierPart.pack_quantity) + : null, + ), + ); + } + + if (widget.supplierPart.hasLink) { + tiles.add( + ListTile( + title: Text(L10().link), + subtitle: Text(widget.supplierPart.link), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + trailing: LinkIcon(external: true), + onTap: () async { + widget.supplierPart.openLink(); + }, + ), + ); + } + + if (widget.supplierPart.note.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().notes), + subtitle: Text(widget.supplierPart.note), + leading: Icon(TablerIcons.pencil), + ), + ); + } + + 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/company/supplier_part_list.dart b/lib/widget/company/supplier_part_list.dart new file mode 100644 index 0000000..c820a67 --- /dev/null +++ b/lib/widget/company/supplier_part_list.dart @@ -0,0 +1,99 @@ +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"; + +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/refreshable_state.dart"; + +/* + * Widget for displaying a list of Supplier Part instances + */ +class SupplierPartList extends StatefulWidget { + const SupplierPartList(this.filters); + + final Map filters; + + @override + _SupplierPartListState createState() => _SupplierPartListState(); +} + +class _SupplierPartListState extends RefreshableState { + @override + String getAppBarTitle() => L10().supplierParts; + + @override + Widget getBody(BuildContext context) { + return PaginatedSupplierPartList(widget.filters); + } +} + +class PaginatedSupplierPartList extends PaginatedSearchWidget { + const PaginatedSupplierPartList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().supplierParts; + + @override + _PaginatedSupplierPartListState createState() => + _PaginatedSupplierPartListState(); +} + +class _PaginatedSupplierPartListState + extends PaginatedSearchState { + _PaginatedSupplierPartListState() : super(); + + @override + String get prefix => "supplierpart_"; + + @override + Map get orderingOptions => {}; + + @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 { + final page = await InvenTreeSupplierPart().listPaginated( + limit, + offset, + filters: params, + ); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeSupplierPart supplierPart = model as InvenTreeSupplierPart; + + return ListTile( + title: Text(supplierPart.SKU), + subtitle: Text(supplierPart.partName), + leading: InvenTreeAPI().getThumbnail(supplierPart.supplierImage), + trailing: InvenTreeAPI().getThumbnail(supplierPart.partImage), + onTap: () { + supplierPart.goToDetailPage(context); + }, + ); + } +} diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart deleted file mode 100644 index b7ac259..0000000 --- a/lib/widget/company_detail.dart +++ /dev/null @@ -1,222 +0,0 @@ - -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/widget/purchase_order_list.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:flutter/material.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/widget/snacks.dart"; - - -class CompanyDetailWidget extends StatefulWidget { - - const CompanyDetailWidget(this.company, {Key? key}) : super(key: key); - - final InvenTreeCompany company; - - @override - _CompanyDetailState createState() => _CompanyDetailState(company); - -} - - -class _CompanyDetailState extends RefreshableState { - - _CompanyDetailState(this.company); - - final InvenTreeCompany company; - - List outstandingOrders = []; - - @override - String getAppBarTitle(BuildContext context) => L10().company; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: () async { - company.goToInvenTreePage(); - }, - ) - ); - - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { - editCompany(context); - } - ) - ); - - return actions; - - } - - @override - Future request(BuildContext context) async { - await company.reload(); - - if (company.isSupplier) { - outstandingOrders = await company.getPurchaseOrders(outstanding: true); - } - } - - Future editCompany(BuildContext context) async { - - company.editForm( - context, - L10().companyEdit, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().companyUpdated, success: true); - } - ); - } - - List _companyTiles() { - - List tiles = []; - - bool sep = false; - - tiles.add(Card( - child: ListTile( - title: Text("${company.name}"), - subtitle: Text("${company.description}"), - leading: InvenTreeAPI().getImage(company.image, width: 40, height: 40), - ), - )); - - if (company.website.isNotEmpty) { - tiles.add(ListTile( - title: Text("${company.website}"), - leading: FaIcon(FontAwesomeIcons.globe), - onTap: () { - // TODO - Open website - }, - )); - - sep = true; - } - - if (company.email.isNotEmpty) { - tiles.add(ListTile( - title: Text("${company.email}"), - leading: FaIcon(FontAwesomeIcons.at), - onTap: () { - // TODO - Open email - }, - )); - - sep = true; - } - - if (company.phone.isNotEmpty) { - tiles.add(ListTile( - title: Text("${company.phone}"), - leading: FaIcon(FontAwesomeIcons.phone), - onTap: () { - // TODO - Call phone number - }, - )); - - sep = true; - } - - // External link - if (company.link.isNotEmpty) { - tiles.add(ListTile( - title: Text("${company.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), - onTap: () { - company.openLink(); - }, - )); - - sep = true; - } - - if (sep) { - tiles.add(Divider()); - } - - if (company.isSupplier) { - // TODO - Add list of supplier parts - // TODO - Add list of purchase orders - - tiles.add(Divider()); - - tiles.add( - ListTile( - title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart, color: COLOR_CLICK), - trailing: Text("${outstandingOrders.length}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PurchaseOrderListWidget( - filters: { - "supplier": "${company.pk}" - } - ) - ) - ); - } - ) - ); - - // TODO: Display "supplied parts" count (click through to list of supplier parts) - /* - tiles.add( - ListTile( - title: Text(L10().suppliedParts), - leading: FaIcon(FontAwesomeIcons.shapes), - trailing: Text("${company.partSuppliedCount}"), - ) - ); - */ - } - - if (company.isManufacturer) { - // TODO - Add list of manufacturer parts - } - - if (company.isCustomer) { - - // TODO - Add list of sales orders - - tiles.add(Divider()); - } - - if (company.notes.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote), - onTap: null, - )); - } - - 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 deleted file mode 100644 index 1496826..0000000 --- a/lib/widget/company_list.dart +++ /dev/null @@ -1,88 +0,0 @@ - -import "package:flutter/material.dart"; - -import "package:inventree/api.dart"; -import "package:inventree/inventree/company.dart"; -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"; - - -class CompanyListWidget extends StatefulWidget { - - const CompanyListWidget(this.title, this.filters, {Key? key}) : super(key: key); - - final String title; - - final Map filters; - - @override - _CompanyListWidgetState createState() => _CompanyListWidgetState(title, filters); -} - - -class _CompanyListWidgetState extends RefreshableState { - - _CompanyListWidgetState(this.title, this.filters); - - final String title; - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => title; - - @override - Widget getBody(BuildContext context) { - - return PaginatedCompanyList(filters); - - } - -} - - -class PaginatedCompanyList extends StatefulWidget { - - const PaginatedCompanyList(this.filters, {this.onTotalChanged}); - - final Map filters; - - final Function(int)? onTotalChanged; - - @override - _CompanyListState createState() => _CompanyListState(filters); -} - -class _CompanyListState extends PaginatedSearchState { - - _CompanyListState(Map filters) : super(filters); - - @override - 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( - title: Text(company.name), - subtitle: Text(company.description), - leading: InvenTreeAPI().getImage( - company.image, - width: 40, - height: 40 - ), - onTap: () async { - Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyDetailWidget(company))); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 357983b..feb267e 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -1,25 +1,89 @@ - -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:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; -Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { +import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; - String _accept = acceptText ?? L10().ok; - String _reject = rejectText ?? L10().cancel; +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: () { + OneContext().popDialog(); + if (onSelected != null) { + onSelected(idx); + } + }, + ), + ); + } + + if (!hasContext()) { + return; + } 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(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 { + String _accept = acceptText ?? L10().ok; + String _reject = rejectText ?? L10().cancel; + + if (!hasContext()) { + return; + } + + 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: Icon(icon, color: color), ), - content: Text(text), + content: text.isEmpty ? Text(text) : null, actions: [ TextButton( child: Text(_reject), @@ -30,7 +94,7 @@ Future confirmationDialog(String title, String text, {IconData icon = Font if (onReject != null) { onReject(); } - } + }, ), TextButton( child: Text(_accept), @@ -42,200 +106,203 @@ Future confirmationDialog(String title, String text, {IconData icon = Font onAccept(); } }, - ) - ] + ), + ], ); - } + }, ); } +/* + * Construct an error dialog showing information to the user + * + * @title = Title to be displayed at the top of the dialog + * @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 { + List children = []; -Future showInfoDialog(String title, String description, {IconData icon = FontAwesomeIcons.info, String? info, Function()? onDismissed}) async { + if (description.isNotEmpty) { + 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) + if (response.data is Map) { + for (String field in response.asMap().keys) { + dynamic error = response.data[field]; - String _info = info ?? L10().info; + if (error is List) { + for (int ii = 0; ii < error.length; ii++) { + children.add( + ListTile( + title: Text(field), + subtitle: Text(error[ii].toString()), + ), + ); + } + } else { + children.add( + ListTile( + title: Text(field), + subtitle: Text(response.data[field].toString()), + ), + ); + } + } + } else { + children.add( + ListTile( + title: Text(L10().responseInvalid), + subtitle: Text(response.data.toString()), + ), + ); + } + default: + // Unhandled server response + children.add( + ListTile( + title: Text(L10().statusCode), + subtitle: Text(response.statusCode.toString()), + ), + ); - 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(); + children.add( + ListTile( + title: Text(L10().responseData), + subtitle: Text(response.data.toString()), + ), + ); } - }); + } + + if (!hasContext()) { + return; + } + + OneContext() + .showDialog( + builder: (context) => SimpleDialog( + title: ListTile(title: Text(title), leading: Icon(icon)), + children: children, + ), + ) + .then((value) { + if (onDismissed != null) { + onDismissed(); + } + }); } -Future showErrorDialog(String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String? error, Function? onDismissed}) async { +/* + * Display a message indicating the nature of a server / API error + */ +Future showServerError( + String url, + String title, + String description, +) async { + if (!hasContext()) { + return; + } - String _error = error ?? L10().error; - - OneContext().showDialog( - builder: (context) => SimpleDialog( - title: ListTile( - title: Text(_error), - leading: FaIcon(icon), - ), - children: [ - ListTile( - title: Text(title), - subtitle: Text(description), - ) - ], - ) - ).then((value) { - if (onDismissed != null) { - onDismissed(); - } - }); -} - -Future showServerError(String title, String description) async { + // We ignore error messages for certain URLs + if (url.contains("notifications")) { + return; + } if (title.isEmpty) { title = L10().serverError; } // 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) { - final player = AudioCache(); - player.play("sounds/server_error.mp3"); + playAudioFile("sounds/server_error.mp3"); } + description += "\nURL: $url"; + showSnackIcon( title, success: false, actionText: L10().details, onAction: () { showErrorDialog( - title, - description, - error: L10().serverError, - icon: FontAwesomeIcons.server + title, + description: description, + icon: TablerIcons.server, ); - } + }, ); } -Future showStatusCodeError(int status) async { +/* + * Displays an error indicating that the server returned an unexpected status code + */ +Future showStatusCodeError( + String url, + int status, { + String details = "", +}) async { + String msg = statusCodeToString(status); + String extra = url + "\n" + "${L10().statusCode}: ${status}"; - String msg = L10().responseInvalid; - String extra = "${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; } - showServerError( - msg, - extra, - ); + showServerError(url, msg, extra); } -Future showTimeoutError() async { - await showServerError(L10().timeout, L10().noResponse); +/* + * 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}"; + } } -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 +/* + * 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); +} diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 871b511..9f30446 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -1,16 +1,100 @@ -import "package:inventree/api.dart"; -import "package:inventree/barcode.dart"; +import "package:adaptive_theme/adaptive_theme.dart"; import "package:flutter/material.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/settings/about.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/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:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/widget/search.dart"; -import "package:package_info_plus/package_info_plus.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/order/purchase_order_list.dart"; +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); final BuildContext context; @@ -20,6 +104,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. @@ -32,90 +120,203 @@ class InvenTreeDrawer extends StatelessWidget { } } - void _search() { - - if (!InvenTreeAPI().checkConnection(context)) return; - + // Load "parts" page + void _parts() { _closeDrawer(); - Navigator.push( + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)), + ); + } + } + + // Load "stock" page + void _stock() { + _closeDrawer(); + + 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) => SearchWidget() - ) + builder: (context) => SalesOrderListWidget(filters: {}), + ), + ); + } + } + + // Load "purchase orders" page + void _purchaseOrders() { + _closeDrawer(); + + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PurchaseOrderListWidget(filters: {}), + ), + ); + } + } + + // Load notifications screen + void _notifications() { + _closeDrawer(); + + if (_checkConnection()) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NotificationWidget()), + ); + } + } + + // Load settings widget + void _settings() { + _closeDrawer(); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget()), ); } - /* - * Launch the camera to scan a QR code. - * Upon successful scan, data are passed off to be decoded. - */ - Future _scan() async { - if (!InvenTreeAPI().checkConnection(context)) return; - - _closeDrawer(); - scanQrCode(context); + // 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); + } } - /* - * Load settings widget - */ - void _settings() { - _closeDrawer(); - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeSettingsWidget())); - } + // Construct list of tiles to display in the "drawer" menu + List drawerTiles(BuildContext context) { + List tiles = []; - /* - * Load "About" widget - */ - Future _about() async { - _closeDrawer(); + // "Home" access + tiles.add( + ListTile( + leading: Image.asset("assets/image/logo_transparent.png", height: 24), + title: Text( + L10().appTitle, + style: TextStyle(fontWeight: FontWeight.bold), + ), + onTap: _home, + ), + ); - PackageInfo.fromPlatform().then((PackageInfo info) { - Navigator.push(context, - MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info))); - }); + tiles.add(Divider()); + + if (InvenTreePart().canView) { + tiles.add( + ListTile( + title: Text(L10().parts), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + onTap: _parts, + ), + ); + } + + if (InvenTreeStockLocation().canView) { + tiles.add( + ListTile( + title: Text(L10().stock), + leading: Icon(TablerIcons.package, color: COLOR_ACTION), + onTap: _stock, + ), + ); + } + + if (InvenTreePurchaseOrder().canView) { + tiles.add( + ListTile( + title: Text(L10().purchaseOrders), + leading: Icon(TablerIcons.shopping_cart, color: COLOR_ACTION), + onTap: _purchaseOrders, + ), + ); + } + + if (InvenTreeSalesOrder().canView) { + tiles.add( + ListTile( + title: Text(L10().salesOrders), + leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), + onTap: _salesOrders, + ), + ); + } + + if (tiles.length > 2) { + tiles.add(Divider()); + } + + int notification_count = InvenTreeAPI().notification_counter; + + tiles.add( + ListTile( + leading: Icon(TablerIcons.bell, color: COLOR_ACTION), + trailing: notification_count > 0 + ? Text(notification_count.toString()) + : null, + title: Text(L10().notifications), + onTap: _notifications, + ), + ); + + tiles.add(Divider()); + + tiles.add( + ListTile( + onTap: () { + 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.palette, color: COLOR_ACTION), + trailing: _getThemeModeIcon(AdaptiveTheme.of(context).mode), + ), + ); + + tiles.add( + ListTile( + title: Text(L10().settings), + leading: Icon(Icons.settings, color: COLOR_ACTION), + onTap: _settings, + ), + ); + + return tiles; } @override Widget build(BuildContext context) { - - return Drawer( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: [ - ListTile( - leading: FaIcon(FontAwesomeIcons.home), - 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.search), - onTap: _search, - ), - ListTile( - title: Text(L10().settings), - leading: Icon(Icons.settings), - onTap: _settings, - ), - ListTile( - title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.infoCircle), - onTap: _about, - ) - ] - ).toList(), - ) - ); + return Drawer(child: ListView(children: drawerTiles(context))); } -} \ No newline at end of file +} diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index c50a20e..406c0fe 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -3,17 +3,14 @@ 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"; 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,26 +64,19 @@ 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( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.fileUpload), + leading: Icon(TablerIcons.arrow_up), title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { - // Close the dialog OneContext().popDialog(); @@ -101,14 +93,14 @@ class FilePickerDialog { } } }, - ) + ), ); if (allowImages) { actions.add( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.camera), + leading: Icon(TablerIcons.camera), title: Text(L10().takePicture), ), onPressed: () async { @@ -122,96 +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, Function(bool?)? onSaved, - TextStyle? labelStyle, - String? helperText, - TextStyle? helperStyle, - }) : - super( - onSaved: onSaved, - initialValue: initial, - builder: (FormFieldState state) { - return CheckboxListTile( - //dense: state.hasError, - title: label != null ? Text(label, style: labelStyle) : null, - value: state.value, - 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 cea5773..15c4d3f 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -1,166 +1,220 @@ +import "dart:async"; +import "dart:math"; + import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; - -import "package:inventree/app_colors.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/location_display.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/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/order/so_shipment_list.dart"; + +import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/drawer.dart"; - -import "package:inventree/app_settings.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/company_list.dart"; class InvenTreeHomePage extends StatefulWidget { - const InvenTreeHomePage({Key? key}) : super(key: key); @override _InvenTreeHomePageState createState() => _InvenTreeHomePageState(); } -class _InvenTreeHomePageState extends State { - +class _InvenTreeHomePageState extends State + with BaseWidgetProperties { _InvenTreeHomePageState() : super() { - // Load display settings _loadSettings(); // Initially load the profile and attempt server connection _loadProfile(); + InvenTreeAPI().registerCallback(() { + if (mounted) { + setState(() { + // Reload the widget + }); + } + }); } - bool homeShowPo = true; - bool homeShowSubscribed = true; - bool homeShowManufacturers = true; - bool homeShowCustomers = true; - bool homeShowSuppliers = true; + final homeKey = GlobalKey(); - final GlobalKey<_InvenTreeHomePageState> _homeKey = GlobalKey<_InvenTreeHomePageState>(); + bool homeShowPo = false; + bool homeShowSo = false; + bool homeShowShipments = false; + bool homeShowSubscribed = false; + bool homeShowManufacturers = false; + bool homeShowCustomers = false; + bool homeShowSuppliers = false; // Selected user profile UserProfile? _profile; - void _search(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + void _showParts(BuildContext context) { + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, - MaterialPageRoute( - builder: (context) => SearchWidget() - ) + MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)), ); - - } - - void _scan(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; - - scanQrCode(context); - } - - void _showParts(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) 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(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, - MaterialPageRoute( - builder: (context) => PartList({ - "starred": "true" - }) - ) + MaterialPageRoute(builder: (context) => PartList({"starred": "true"})), ); } void _showStock(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocationDisplayWidget(null)), + ); } void _showPurchaseOrders(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; + if (!InvenTreeAPI().checkConnection()) return; Navigator.push( context, MaterialPageRoute( - builder: (context) => PurchaseOrderListWidget(filters: {}) - ) + builder: (context) => PurchaseOrderListWidget(filters: {}), + ), ); } + void _showSalesOrders(BuildContext context) { + if (!InvenTreeAPI().checkConnection()) return; - void _showSuppliers(BuildContext context) { - if (!InvenTreeAPI().checkConnection(context)) return; - - Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"}))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SalesOrderListWidget(filters: {}), + ), + ); } + 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; + + 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"}))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + CompanyListWidget(L10().customers, {"is_customer": "true"}), + ), + ); } void _selectProfile() { Navigator.push( - context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget()) + 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; - homeShowSubscribed = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SUBSCRIBED, true) as bool; - homeShowPo = await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_PO, 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; + homeShowShipments = + await InvenTreeSettingsManager().getValue(INV_HOME_SHOW_SHIPMENTS, true) + as bool; - setState(() { - }); + 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(() {}); } - 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().then((result) { - setState(() {}); + InvenTreeAPI().connectToServer(_profile!).then((result) { + if (mounted) { + setState(() {}); + } }); } } @@ -168,207 +222,317 @@ class _InvenTreeHomePageState extends State { setState(() {}); } - - 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 = "", + Widget? trailing, + }) { bool connected = InvenTreeAPI().isConnected(); bool allowed = true; if (role.isNotEmpty || permission.isNotEmpty) { - allowed = InvenTreeAPI().checkPermission(role, permission); + allowed = InvenTreeAPI().checkRole(role, permission); } return GestureDetector( child: Card( - margin: EdgeInsets.symmetric( - vertical: 12, - horizontal: 12 - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FaIcon( + margin: EdgeInsets.all(5), + child: Align( + child: ListTile( + leading: Icon( icon, - color: connected && allowed ? COLOR_CLICK : Colors.grey, + color: connected && allowed ? COLOR_ACTION : Colors.grey, ), - Divider( - height: 15, - thickness: 0, - color: Colors.transparent, - ), - Text( - label, - textAlign: TextAlign.center, - ), - ] - ) + title: Text(label), + trailing: trailing, + ), + alignment: Alignment.center, + ), ), onTap: () { - if (!allowed) { showSnackIcon( L10().permissionRequired, - icon: FontAwesomeIcons.exclamationCircle, + icon: TablerIcons.exclamation_circle, success: false, ); - return; } if (callback != null) { callback(); } - }, ); } - List getGridTiles(BuildContext context) { - + /* + * Constructs a list of tiles for the main screen + */ + List getListTiles(BuildContext context) { List tiles = []; - // Barcode scanner - tiles.add(_iconButton( - context, - L10().scanBarcode, - Icons.qr_code_scanner, - callback: () { - _scan(context); - } - )); - - // Search widget - tiles.add(_iconButton( - context, - L10().search, - FontAwesomeIcons.search, - callback: () { - _search(context); - } - )); - // Parts - tiles.add(_iconButton( - context, - L10().parts, - FontAwesomeIcons.shapes, - callback: () { - _showParts(context); - } - )); + if (InvenTreePart().canView) { + tiles.add( + _listTile( + context, + L10().parts, + TablerIcons.box, + callback: () { + _showParts(context); + }, + ), + ); + } // Starred parts - if (homeShowSubscribed) { - tiles.add(_iconButton( - context, - L10().partsStarred, - FontAwesomeIcons.bell, - callback: () { - _showStarredParts(context); - } - )); + if (homeShowSubscribed && InvenTreePart().canView) { + tiles.add( + _listTile( + context, + L10().partsStarred, + TablerIcons.bell, + callback: () { + _showStarredParts(context); + }, + ), + ); } // Stock button - tiles.add(_iconButton( - context, - L10().stock, - FontAwesomeIcons.boxes, - callback: () { - _showStock(context); - } - )); + if (InvenTreeStockItem().canView) { + tiles.add( + _listTile( + context, + L10().stock, + TablerIcons.package, + callback: () { + _showStock(context); + }, + ), + ); + } - // Purchase orderes - if (homeShowPo) { - tiles.add(_iconButton( + // Purchase orders + if (homeShowPo && InvenTreePurchaseOrder().canView) { + tiles.add( + _listTile( context, L10().purchaseOrders, - FontAwesomeIcons.shoppingCart, + TablerIcons.shopping_cart, callback: () { _showPurchaseOrders(context); - } - )); + }, + ), + ); + } + + if (homeShowSo && InvenTreeSalesOrder().canView) { + tiles.add( + _listTile( + context, + L10().salesOrders, + TablerIcons.truck_delivery, + callback: () { + _showSalesOrders(context); + }, + ), + ); + } + + if (homeShowShipments && InvenTreeSalesOrderShipment().canView) { + tiles.add( + _listTile( + context, + L10().shipmentsPending, + TablerIcons.cube_send, + callback: () { + _showPendingShipments(context); + }, + ), + ); } // Suppliers - if (homeShowSuppliers) { - tiles.add(_iconButton( + if (homeShowSuppliers && InvenTreePurchaseOrder().canView) { + tiles.add( + _listTile( context, L10().suppliers, - FontAwesomeIcons.building, + TablerIcons.building, callback: () { _showSuppliers(context); - } - )); + }, + ), + ); } + // TODO: Add these tiles back in once the features are fleshed out + /* + + // Manufacturers if (homeShowManufacturers) { - tiles.add(_iconButton( + tiles.add(_listTile( context, L10().manufacturers, - FontAwesomeIcons.industry, + TablerIcons.building_factory_2, callback: () { _showManufacturers(context); } )); } - + */ // Customers if (homeShowCustomers) { - tiles.add(_iconButton( + tiles.add( + _listTile( context, L10().customers, - FontAwesomeIcons.userTie, + TablerIcons.building_store, callback: () { _showCustomers(context); - } - )); + }, + ), + ); } - // Settings - tiles.add(_iconButton( - context, - L10().settings, - FontAwesomeIcons.cogs, - callback: () { - _showSettings(context); - } - )); - return tiles; } - @override - Widget build(BuildContext context) { + /* + * If the app is not connected to an InvenTree server, + * display a connection status widget + */ + Widget _connectionStatusWidget(BuildContext context) { + String? serverAddress = InvenTreeAPI().serverAddress; + bool validAddress = serverAddress != null; + bool connecting = + !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); - return Scaffold( - key: _homeKey, - appBar: AppBar( - title: Text(L10().appTitle), - actions: [ - IconButton( - icon: FaIcon( - FontAwesomeIcons.server, - color: InvenTreeAPI().isConnected() ? COLOR_SUCCESS : COLOR_DANGER, - ), - onPressed: _selectProfile, - ) - ], - ), - drawer: InvenTreeDrawer(context), - body: ListView( + 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; + + if (!validAddress) { + title = L10().serverNotSelected; + } else if (connecting) { + title = L10().serverConnecting; + subtitle = serverAddress; + leading = Spinner(icon: TablerIcons.loader_2, color: COLOR_PROGRESS); + } + + return Center( + child: Column( children: [ - GridView.extent( - maxCrossAxisExtent: 140, - shrinkWrap: true, - physics: ClampingScrollPhysics(), - children: getGridTiles(context), + Spacer(), + Image.asset( + "assets/image/logo_transparent.png", + color: Colors.white.withValues(alpha: 0.05), + colorBlendMode: BlendMode.modulate, + scale: 0.5, + ), + Spacer(), + ListTile( + title: Text(title), + subtitle: Text(subtitle), + trailing: trailing, + leading: leading, + onTap: _selectProfile, ), ], ), ); } + + /* + * Return the main body widget for display + */ + @override + Widget getBody(BuildContext context) { + if (!InvenTreeAPI().isConnected()) { + return _connectionStatusWidget(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 + Widget build(BuildContext context) { + var connected = InvenTreeAPI().isConnected(); + var connecting = !connected && InvenTreeAPI().isConnecting(); + + return Scaffold( + key: homeKey, + appBar: AppBar( + 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: 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, + ), + ], + ), + drawer: InvenTreeDrawer(context), + body: getBody(context), + bottomNavigationBar: InvenTreeAPI().isConnected() + ? buildBottomAppBar(context, homeKey) + : null, + ); + } } 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/location_display.dart b/lib/widget/location_display.dart deleted file mode 100644 index 75554e1..0000000 --- a/lib/widget/location_display.dart +++ /dev/null @@ -1,471 +0,0 @@ -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/inventree/stock.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/l10.dart"; -import "package:inventree/widget/stock_list.dart"; - - -class LocationDisplayWidget extends StatefulWidget { - - LocationDisplayWidget(this.location, {Key? key}) : super(key: key); - - final InvenTreeStockLocation? location; - - final String title = L10().stockLocation; - - @override - _LocationDisplayState createState() => _LocationDisplayState(location); -} - -class _LocationDisplayState extends RefreshableState { - - _LocationDisplayState(this.location); - - final InvenTreeStockLocation? location; - - @override - String getAppBarTitle(BuildContext context) { return L10().stockLocation; } - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - /* - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.search), - onPressed: () { - - Map filters = {}; - - if (location != null) { - filters["location"] = "${location.pk}"; - } - - showSearch( - context: context, - delegate: StockSearchDelegate(context, filters: filters) - ); - } - ), - ); - */ - - if ((location != null) && (InvenTreeAPI().checkPermission("stock_location", "change"))) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { _editLocationDialog(context); }, - ) - ); - } - - return actions; - } - - void _editLocationDialog(BuildContext context) { - - final _loc = location; - - if (_loc == null) { - return; - } - - _loc.editForm( - context, - L10().editLocation, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().locationUpdated, success: true); - } - ); - } - - List _sublocations = []; - - String _locationFilter = ""; - - List get sublocations { - - if (_locationFilter.isEmpty || _sublocations.isEmpty) { - return _sublocations; - } else { - return _sublocations.where((loc) => loc.filter(_locationFilter)).toList(); - } - } - - @override - Future onBuild(BuildContext context) async { - refresh(context); - } - - @override - Future request(BuildContext context) async { - - int pk = location?.pk ?? -1; - - // Reload location information - if (location != null) { - final bool result = await location?.reload() ?? false; - - if (!result) { - Navigator.of(context).pop(); - } - } - - // Request a list of sub-locations under this one - await InvenTreeStockLocation().list(filters: {"parent": "$pk"}).then((var locs) { - _sublocations.clear(); - - for (var loc in locs) { - if (loc is InvenTreeStockLocation) { - _sublocations.add(loc); - } - } - }); - - setState(() {}); - } - - Future _newLocation(BuildContext context) async { - - int pk = location?.pk ?? -1; - - InvenTreeStockLocation().createForm( - 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); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc) - ) - ); - } - } - ); - } - - Future _newStockItem(BuildContext context) async { - - int pk = location?.pk ?? -1; - - if (location != null && pk <= 0) { - return; - } - - InvenTreeStockItem().createForm( - context, - L10().stockItemCreate, - data: { - "location": location != null ? pk : null, - }, - onSuccess: (result) async { - - Map data = result as Map; - - if (data.containsKey("pk")) { - var item = InvenTreeStockItem.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockDetailWidget(item) - ) - ); - } - } - ); - - } - - Widget locationDescriptionCard({bool includeActions = true}) { - if (location == null) { - return Card( - child: ListTile( - title: Text(L10().stockTopLevel), - ) - ); - } else { - - List children = [ - ListTile( - title: Text("${location!.name}"), - subtitle: Text("${location!.description}"), - trailing: Text("${location!.itemcount}"), - ), - ]; - - if (includeActions) { - children.add( - ListTile( - title: Text(L10().parentLocation), - subtitle: Text("${location!.parentpathstring}"), - leading: FaIcon(FontAwesomeIcons.levelUpAlt, color: COLOR_CLICK), - onTap: () { - - int parent = location?.parentId ?? -1; - - if (parent < 0) { - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); - } else { - - InvenTreeStockLocation().get(parent).then((var loc) { - if (loc is InvenTreeStockLocation) { - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); - } - }); - } - }, - ) - ); - } - - return Card( - 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.boxes), - label: L10().stock, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions, - ) - ] - ); - } - - int stockItemCount = 0; - - Widget getSelectedWidget(int index) { - - // Construct filters for paginated stock list - Map filters = {}; - - if (location != null) { - filters["location"] = "${location!.pk}"; - } - - switch (index) { - case 0: - return ListView( - children: detailTiles(), - ); - case 1: - return PaginatedStockItemList(filters); - case 2: - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: actionTiles() - ).toList() - ); - default: - return ListView(); - } - } - - @override - Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); - } - - -List detailTiles() { - List tiles = [ - locationDescriptionCard(), - ListTile( - title: Text( - L10().sublocations, - style: TextStyle(fontWeight: FontWeight.bold), - ), - trailing: sublocations.isNotEmpty ? Text("${sublocations.length}") : null, - ), - ]; - - if (loading) { - tiles.add(progressIndicator()); - } else if (_sublocations.isNotEmpty) { - tiles.add(SublocationList(_sublocations)); - } else { - tiles.add(ListTile( - title: Text(L10().sublocationNone), - subtitle: Text( - L10().sublocationNoneDetail, - style: TextStyle(fontStyle: FontStyle.italic) - ) - )); - } - - return tiles; - } - - - List actionTiles() { - List tiles = []; - - tiles.add(locationDescriptionCard(includeActions: false)); - - if (InvenTreeAPI().checkPermission("stock", "add")) { - - tiles.add( - ListTile( - title: Text(L10().locationCreate), - subtitle: Text(L10().locationCreateDetail), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - onTap: () async { - _newLocation(context); - }, - ) - ); - - tiles.add( - ListTile( - title: Text(L10().stockItemCreate), - subtitle: Text(L10().stockItemCreateDetail), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - onTap: () async { - _newStockItem(context); - }, - ) - ); - - } - - if (location != null) { - // Stock adjustment actions - if (InvenTreeAPI().checkPermission("stock", "change")) { - // Scan items into location - tiles.add( - ListTile( - title: Text(L10().barcodeScanInItems), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code), - onTap: () { - - var _loc = location; - - if (_loc != null) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => - InvenTreeQRView( - StockLocationScanInItemsHandler(_loc))) - ).then((value) { - refresh(context); - }); - } - }, - ) - ); - } - } - - // Move location into another location - // TODO: Implement this! - /* - tiles.add( - ListTile( - title: Text("Move Stock Location"), - leading: FaIcon(FontAwesomeIcons.sitemap), - trailing: Icon(Icons.qr_code), - ) - ); - */ - - if (tiles.length <= 1) { - tiles.add( - ListTile( - title: Text( - L10().actionsNone, - style: TextStyle( - fontStyle: FontStyle.italic - ), - ) - ) - ); - } - - return tiles; - } - -} - - - -class SublocationList extends StatelessWidget { - - const SublocationList(this._locations); - - final List _locations; - - void _openLocation(BuildContext context, int pk) { - - InvenTreeStockLocation().get(pk).then((var loc) { - if (loc is InvenTreeStockLocation) { - - Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); - } - }); - } - - Widget _build(BuildContext context, int index) { - InvenTreeStockLocation loc = _locations[index]; - - return ListTile( - title: Text("${loc.name}"), - subtitle: Text("${loc.description}"), - trailing: Text("${loc.itemcount}"), - onTap: () { - _openLocation(context, loc.pk); - }, - ); - } - - @override - Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - itemBuilder: _build, - separatorBuilder: (_, __) => const Divider(height: 3), - itemCount: _locations.length - ); - } -} diff --git a/lib/widget/location_list.dart b/lib/widget/location_list.dart deleted file mode 100644 index 42c8792..0000000 --- a/lib/widget/location_list.dart +++ /dev/null @@ -1,81 +0,0 @@ -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/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; - - @override - _StockLocationListState createState() => _StockLocationListState(filters); -} - - -class _StockLocationListState extends RefreshableState { - - _StockLocationListState(this.filters); - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => L10().stockLocations; - - @override - Widget getBody(BuildContext context) { - return PaginatedStockLocationList(filters); - } -} - - -class PaginatedStockLocationList extends StatefulWidget { - - const PaginatedStockLocationList(this.filters); - - final Map filters; - - @override - _PaginatedStockLocationListState createState() => _PaginatedStockLocationListState(filters); -} - - -class _PaginatedStockLocationListState extends PaginatedSearchState { - - _PaginatedStockLocationListState(Map filters) : super(filters); - - @override - 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( - title: Text(location.name), - subtitle: Text(location.pathstring), - trailing: Text("${location.itemcount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LocationDisplayWidget(location) - ) - ); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/notes_widget.dart b/lib/widget/notes_widget.dart new file mode 100644 index 0000000..196eb91 --- /dev/null +++ b/lib/widget/notes_widget.dart @@ -0,0 +1,70 @@ +import "package:flutter/material.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"; +import "package:inventree/l10.dart"; + +/* + * 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 NotesWidget(this.model, {Key? key}) : super(key: key); + + final InvenTreeModel model; + + @override + _NotesState createState() => _NotesState(); +} + +/* + * Class representing the state of the NotesWidget + */ +class _NotesState extends RefreshableState { + _NotesState(); + + @override + Future request(BuildContext context) async { + await widget.model.reload(); + } + + @override + String getAppBarTitle() => L10().editNotes; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.model.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().edit, + onPressed: () { + widget.model.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: widget.model.notes); + } +} diff --git a/lib/widget/notifications.dart b/lib/widget/notifications.dart new file mode 100644 index 0000000..d29b8c9 --- /dev/null +++ b/lib/widget/notifications.dart @@ -0,0 +1,101 @@ +import "package:flutter/material.dart"; + +import "package:flutter_tabler_icons/flutter_tabler_icons.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 { + @override + _NotificationState createState() => _NotificationState(); +} + +class _NotificationState extends RefreshableState { + _NotificationState() : super(); + + List notifications = []; + + bool isDismissing = false; + + @override + String getAppBarTitle() => L10().notifications; + + @override + Future request(BuildContext context) async { + final results = await InvenTreeNotification().list(); + + notifications.clear(); + + for (InvenTreeModel n in results) { + if (n is InvenTreeNotification) { + notifications.add(n); + } + } + } + + /* + * Dismiss an individual notification entry (mark it as "read") + */ + Future dismissNotification( + BuildContext context, + InvenTreeNotification notification, + ) async { + if (mounted) { + setState(() { + isDismissing = true; + }); + } else { + return; + } + + await notification.dismiss(); + + if (mounted) { + refresh(context); + + setState(() { + isDismissing = false; + }); + } + } + + /* + * Display an individual notification message + */ + @override + List getTiles(BuildContext context) { + List tiles = []; + + tiles.add( + ListTile( + title: Text(L10().notifications), + subtitle: notifications.isEmpty ? Text(L10().notificationsEmpty) : null, + leading: notifications.isEmpty + ? Icon(TablerIcons.bell_exclamation) + : Icon(TablerIcons.bell), + trailing: Text("${notifications.length}"), + ), + ); + + for (var notification in notifications) { + tiles.add( + ListTile( + title: Text(notification.name), + subtitle: Text(notification.message), + trailing: IconButton( + icon: Icon(TablerIcons.bookmark), + 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 new file mode 100644 index 0000000..490f833 --- /dev/null +++ b/lib/widget/order/extra_line_detail.dart @@ -0,0 +1,117 @@ +import "package:flutter/material.dart"; +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"; + +import "package:inventree/inventree/orders.dart"; + +class ExtraLineDetailWidget extends StatefulWidget { + const ExtraLineDetailWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreeExtraLineItem item; + + @override + _ExtraLineDetailWidgetState createState() => _ExtraLineDetailWidgetState(); +} + +class _ExtraLineDetailWidgetState + extends RefreshableState { + _ExtraLineDetailWidgetState(); + + @override + String getAppBarTitle() => L10().extraLineItem; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.item.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + onPressed: () { + _editLineItem(context); + }, + ), + ); + } + + return actions; + } + + // Function to request data for this page + @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); + }, + ); + } + + @override + List getTiles(BuildContext context) { + List tiles = []; + + tiles.add( + ListTile( + title: Text(L10().reference), + subtitle: Text(widget.item.reference), + leading: Icon(TablerIcons.hash), + ), + ); + + tiles.add( + ListTile( + title: Text(L10().description), + subtitle: Text(widget.item.description), + leading: Icon(TablerIcons.info_circle), + ), + ); + + tiles.add( + ListTile( + title: Text(L10().quantity), + trailing: LargeText(widget.item.quantity.toString()), + leading: Icon(TablerIcons.progress), + ), + ); + + tiles.add( + ListTile( + title: Text(L10().unitPrice), + 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), + leading: Icon(TablerIcons.note), + ), + ); + } + + return tiles; + } +} diff --git a/lib/widget/order/po_extra_line_list.dart b/lib/widget/order/po_extra_line_list.dart new file mode 100644 index 0000000..b9d953f --- /dev/null +++ b/lib/widget/order/po_extra_line_list.dart @@ -0,0 +1,122 @@ +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/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"; + +class POExtraLineListWidget extends StatefulWidget { + const POExtraLineListWidget(this.order, {this.filters = const {}, Key? key}) + : super(key: key); + + final InvenTreePurchaseOrder order; + + final Map filters; + + @override + _PurchaseOrderExtraLineListWidgetState createState() => + _PurchaseOrderExtraLineListWidgetState(); +} + +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; + + InvenTreePOExtraLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().lineItemUpdated, success: true); + }, + ); + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (widget.order.canEdit) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().lineItemAdd, + onTap: () { + _addLineItem(context); + }, + ), + ); + } + + return actions; + } + + @override + Widget getBody(BuildContext context) { + return PaginatedPOExtraLineList(widget.filters); + } +} + +class PaginatedPOExtraLineList extends PaginatedSearchWidget { + const PaginatedPOExtraLineList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().extraLineItems; + + @override + _PaginatedPOExtraLineListState createState() => + _PaginatedPOExtraLineListState(); +} + +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, + ); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreePOExtraLineItem line = model as InvenTreePOExtraLineItem; + + return ListTile( + title: Text(line.reference), + subtitle: Text(line.description), + 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 new file mode 100644 index 0000000..16bac28 --- /dev/null +++ b/lib/widget/order/po_line_detail.dart @@ -0,0 +1,259 @@ +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/helpers.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/l10.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/link_icon.dart"; + +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/snacks.dart"; + +/* + * Widget for displaying detail view of a single PurchaseOrderLineItem +*/ +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(); + + InvenTreeStockLocation? destination; + + @override + String getAppBarTitle() => L10().lineItem; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.item.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + 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: Icon(TablerIcons.transition_right, color: Colors.blue), + label: L10().receiveItem, + onTap: () async { + receiveLineItem(context); + }, + ), + ); + } + } + + return buttons; + } + + @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 + 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 { + widget.item.receive( + context, + onSuccess: () => { + showSnackIcon(L10().receivedItem, success: true), + refresh(context), + }, + ); + } + + @override + List getTiles(BuildContext context) { + List tiles = []; + + // Reference to the part + tiles.add( + ListTile( + title: Text(L10().internalPart), + subtitle: Text(widget.item.partName), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: LinkIcon(image: api.getThumbnail(widget.item.partImage)), + onTap: () async { + showLoadingOverlay(); + var part = await InvenTreePart().get(widget.item.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + }, + ), + ); + + // Reference to the supplier part + tiles.add( + ListTile( + 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( + widget.item.supplierPartId, + ); + hideLoadingOverlay(); + + if (part is InvenTreeSupplierPart) { + part.goToDetailPage(context); + } + }, + ), + ); + + // Destination + if (destination != null) { + tiles.add( + ListTile( + title: Text(L10().destination), + subtitle: Text(destination!.name), + leading: Icon(TablerIcons.map_pin, color: COLOR_ACTION), + onTap: () => {destination!.goToDetailPage(context)}, + ), + ); + } + + // Received quantity + tiles.add( + ListTile( + title: Text(L10().received), + subtitle: ProgressBar(widget.item.progressRatio), + trailing: LargeText( + widget.item.progressString, + 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), + ), + ); + } + + // Pricing information + tiles.add( + ListTile( + title: Text(L10().unitPrice), + leading: Icon(TablerIcons.currency_dollar), + trailing: LargeText( + 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: Icon(TablerIcons.note), + ), + ); + } + + // External link + if (widget.item.hasLink) { + 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); + }, + ), + ); + } + + return tiles; + } +} diff --git a/lib/widget/order/po_line_list.dart b/lib/widget/order/po_line_list.dart new file mode 100644 index 0000000..7dbafd5 --- /dev/null +++ b/lib/widget/order/po_line_list.dart @@ -0,0 +1,110 @@ +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/link_icon.dart"; + +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/order/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) + : super(filters: filters); + + @override + String get searchTitle => L10().lineItems; + + @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(item.partName), + trailing: LargeText( + item.progressString, + color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, + ), + leading: InvenTreeAPI().getThumbnail(item.partImage), + onTap: () async { + showLoadingOverlay(); + 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/order/purchase_order_detail.dart b/lib/widget/order/purchase_order_detail.dart new file mode 100644 index 0000000..d309a4b --- /dev/null +++ b/lib/widget/order/purchase_order_detail.dart @@ -0,0 +1,632 @@ +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"; +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"; +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/link_icon.dart"; +import "package:inventree/widget/order/po_extra_line_list.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/parameter_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/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); + + final InvenTreePurchaseOrder order; + + @override + _PurchaseOrderDetailState createState() => _PurchaseOrderDetailState(); +} + +class _PurchaseOrderDetailState + extends RefreshableState { + _PurchaseOrderDetailState(); + + List lines = []; + int extraLineCount = 0; + + InvenTreeStockLocation? destination; + + int completedLines = 0; + int attachmentCount = 0; + int parameterCount = 0; + + bool showCameraShortcut = true; + bool supportProjectCodes = false; + + @override + String getAppBarTitle() { + String title = L10().purchaseOrder; + + if (widget.order.reference.isNotEmpty) { + title += " - ${widget.order.reference}"; + } + + return title; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.order.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().purchaseOrderEdit, + onPressed: () { + editOrder(context); + }, + ), + ); + } + + return actions; + } + + @override + 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.canCreate) { + if (widget.order.isPending) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().lineItemAdd, + onTap: () async { + _addLineItem(context); + }, + ), + ); + + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.send, color: Colors.blue), + label: L10().issueOrder, + onTap: () async { + _issueOrder(context); + }, + ), + ); + } + + 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( + child: Icon(TablerIcons.circle_x, color: Colors.red), + label: L10().cancelOrder, + onTap: () async { + _cancelOrder(context); + }, + ), + ); + } + } + + return actions; + } + + /// Add a new line item to this order + Future _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); + }, + ); + } + + /// Upload an image against the current PurchaseOrder + Future _uploadImage(BuildContext context) async { + InvenTreeAttachment() + .uploadImage( + InvenTreePurchaseOrder.MODEL_TYPE, + 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); + }); + }, + ); + } + + /// 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( + L10().cancelOrder, + "", + icon: TablerIcons.circle_x, + color: Colors.red, + acceptText: L10().cancel, + onAccept: () async { + widget.order.cancelOrder().then((dynamic) { + refresh(context); + }); + }, + ); + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (api.supportsBarcodePOReceiveEndpoint && widget.order.isPlaced) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().scanReceivedParts, + onTap: () async { + scanBarcode( + context, + handler: POReceiveBarcodeHandler(purchaseOrder: widget.order), + ).then((value) { + refresh(context); + }); + }, + ), + ); + } + + if (widget.order.isPending && api.supportsBarcodePOAddLineEndpoint) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: COLOR_SUCCESS), + label: L10().lineItemAdd, + onTap: () async { + scanBarcode( + context, + handler: POAllocateBarcodeHandler(purchaseOrder: widget.order), + ); + }, + ), + ); + } + + return actions; + } + + @override + Future request(BuildContext context) async { + await widget.order.reload(); + + await api.PurchaseOrderStatus.load(); + + lines = await widget.order.getLineItems(); + + showCameraShortcut = await InvenTreeSettingsManager().getBool( + INV_PO_SHOW_CAMERA, + true, + ); + supportProjectCodes = + api.supportsProjectCodes && + await api.getGlobalBooleanSetting( + "PROJECT_CODES_ENABLED", + backup: true, + ); + + completedLines = 0; + + for (var line in lines) { + if (line.isComplete) { + completedLines += 1; + } + } + + 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) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + + if (api.supportsPurchaseOrderDestination && + widget.order.destinationId > 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; + }); + } + } + + // Count number of "extra line items" against this order + InvenTreePOExtraLineItem() + .count(filters: {"order": widget.order.pk.toString()}) + .then((int value) { + if (mounted) { + setState(() { + extraLineCount = value; + }); + } + }); + } + + // Edit the currently displayed PurchaseOrder + Future editOrder(BuildContext context) async { + var fields = widget.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"); + } + + widget.order.editForm( + context, + L10().purchaseOrderEdit, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().purchaseOrderUpdated, success: true); + }, + ); + } + + Widget headerTile(BuildContext context) { + InvenTreeCompany? supplier = widget.order.supplier; + + return Card( + child: ListTile( + title: Text(widget.order.reference), + subtitle: Text(widget.order.description), + leading: supplier == null ? null : api.getThumbnail(supplier.thumbnail), + trailing: LargeText( + api.PurchaseOrderStatus.label(widget.order.status), + color: api.PurchaseOrderStatus.color(widget.order.status), + ), + ), + ); + } + + List orderTiles(BuildContext context) { + List tiles = []; + + InvenTreeCompany? supplier = widget.order.supplier; + + tiles.add(headerTile(context)); + + if (supportProjectCodes && widget.order.hasProjectCode) { + tiles.add( + ListTile( + title: Text(L10().projectCode), + subtitle: Text( + "${widget.order.projectCode} - ${widget.order.projectCodeDescription}", + ), + leading: Icon(TablerIcons.list), + ), + ); + } + + if (supplier != null) { + tiles.add( + ListTile( + title: Text(L10().supplier), + subtitle: Text(supplier.name), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + supplier.goToDetailPage(context); + }, + ), + ); + } + + if (widget.order.supplierReference.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().supplierReference), + subtitle: Text(widget.order.supplierReference), + leading: Icon(TablerIcons.hash), + ), + ); + } + + // Order destination + if (destination != null) { + tiles.add( + ListTile( + title: Text(L10().destination), + subtitle: Text(destination!.name), + leading: Icon(TablerIcons.map_pin, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () => {destination!.goToDetailPage(context)}, + ), + ); + } + + 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: LargeText( + "${completedLines} / ${widget.order.lineItemCount}", + color: lineColor, + ), + ), + ); + + // Extra line items + tiles.add( + ListTile( + title: Text(L10().extraLineItems), + leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), + trailing: LinkIcon(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: LargeText( + renderCurrency( + widget.order.totalPrice, + widget.order.totalPriceCurrency, + ), + ), + ), + ); + + if (widget.order.issueDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().issueDate), + trailing: LargeText(widget.order.issueDate), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.order.startDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().startDate), + trailing: LargeText(widget.order.startDate), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.order.targetDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().targetDate), + trailing: LargeText(widget.order.targetDate), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.order.completionDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().completionDate), + trailing: LargeText(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: LargeText(widget.order.responsibleName), + ), + ); + } + + // 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.order)), + ); + }, + ), + ); + + 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, + widget.order.pk, + widget.order.reference, + attachmentCount, + widget.order.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + + return tiles; + } + + @override + List getTabIcons(BuildContext context) { + return [ + Tab(text: L10().details), + Tab(text: L10().lineItems), + Tab(text: L10().received), + ]; + } + + @override + List getTabs(BuildContext context) { + return [ + ListView(children: orderTiles(context)), + PaginatedPOLineList({"order": widget.order.pk.toString()}), + // ListView(children: lineTiles(context)), + PaginatedStockItemList({"purchase_order": widget.order.pk.toString()}), + ]; + } +} diff --git a/lib/widget/order/purchase_order_list.dart b/lib/widget/order/purchase_order_list.dart new file mode 100644 index 0000000..85fc668 --- /dev/null +++ b/lib/widget/order/purchase_order_list.dart @@ -0,0 +1,187 @@ +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/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"; +import "package:inventree/api.dart"; +import "package:inventree/barcode/barcode.dart"; +import "package:inventree/barcode/purchase_order.dart"; +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); + + final Map filters; + + @override + _PurchaseOrderListWidgetState createState() => + _PurchaseOrderListWidgetState(); +} + +class _PurchaseOrderListWidgetState + extends RefreshableState { + _PurchaseOrderListWidgetState(); + + @override + String getAppBarTitle() => L10().purchaseOrders; + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreePurchaseOrder().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus), + label: L10().purchaseOrderCreate, + onTap: () { + _createPurchaseOrder(context); + }, + ), + ); + } + + return actions; + } + + // 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( + 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); + } + }, + ); + } + + @override + List 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(widget.filters); + } +} + +class PaginatedPurchaseOrderList extends PaginatedSearchWidget { + const PaginatedPurchaseOrderList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().purchaseOrders; + + @override + _PaginatedPurchaseOrderListState createState() => + _PaginatedPurchaseOrderListState(); +} + +class _PaginatedPurchaseOrderListState + extends PaginatedSearchState { + _PaginatedPurchaseOrderListState() : super(); + + @override + String get prefix => "po_"; + + @override + Map get orderingOptions => { + "reference": L10().reference, + "supplier__name": L10().supplier, + "status": L10().status, + "target_date": L10().targetDate, + }; + + @override + Map> get filterOptions => { + "outstanding": { + "label": L10().outstanding, + "help_text": L10().outstandingOrderDetail, + "tristate": true, + "default": true, + }, + "overdue": { + "label": L10().overdue, + "help_text": L10().overdueDetail, + "tristate": true, + }, + "assigned_to_me": { + "label": L10().assignedToMe, + "help_text": L10().assignedToMeDetail, + "tristate": true, + }, + }; + + @override + Future requestPage( + int limit, + int offset, + Map params, + ) async { + await InvenTreeAPI().PurchaseOrderStatus.load(); + 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), + trailing: LargeText( + InvenTreeAPI().PurchaseOrderStatus.label(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 new file mode 100644 index 0000000..79a3620 --- /dev/null +++ b/lib/widget/order/sales_order_detail.dart @@ -0,0 +1,558 @@ +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/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"; + +import "package:inventree/app_colors.dart"; +import "package:inventree/widget/attachment_widget.dart"; +import "package:inventree/widget/dialogs.dart"; +import "package:inventree/widget/notes_widget.dart"; +import "package:inventree/widget/snacks.dart"; +import "package:inventree/widget/progress.dart"; + +/* + * Widget for viewing a single SalesOrder instance + */ +class SalesOrderDetailWidget extends StatefulWidget { + const SalesOrderDetailWidget(this.order, {Key? key}) : super(key: key); + + final InvenTreeSalesOrder order; + + @override + _SalesOrderDetailState createState() => _SalesOrderDetailState(); +} + +class _SalesOrderDetailState extends RefreshableState { + _SalesOrderDetailState(); + + List lines = []; + int extraLineCount = 0; + + bool showCameraShortcut = true; + bool supportsProjectCodes = false; + int attachmentCount = 0; + int parameterCount = 0; + + @override + String getAppBarTitle() { + String title = L10().salesOrder; + + if (widget.order.reference.isNotEmpty) { + title += " - ${widget.order.reference}"; + } + + return title; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.order.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + onPressed: () { + editOrder(context); + }, + ), + ); + } + + 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(); + + fields["order"]?["value"] = widget.order.pk; + fields["order"]?["hidden"] = true; + + InvenTreeSOLineItem().createForm( + context, + L10().lineItemAdd, + fields: fields, + onSuccess: (result) async { + refresh(context); + }, + ); + } + + /// Upload an image for this order + Future _uploadImage(BuildContext context) async { + InvenTreeAttachment() + .uploadImage( + InvenTreeSalesOrder.MODEL_TYPE, + 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); + }); + }, + ); + } + + /// 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); + }); + }, + ); + } + + @override + 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( + 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); + }, + ), + ); + } + + // Add line item + 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( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().shipmentAdd, + onTap: () async { + _addShipment(context); + }, + ), + ); + } + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if ((widget.order.isInProgress || widget.order.isPending) && + InvenTreeSOLineItem().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(Icons.barcode_reader), + label: L10().lineItemAdd, + onTap: () async { + scanBarcode( + context, + handler: SOAddItemBarcodeHandler(salesOrder: widget.order), + ); + }, + ), + ); + + if (api.supportsBarcodeSOAllocateEndpoint) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.transition_right), + label: L10().allocateStock, + onTap: () async { + scanBarcode( + context, + handler: SOAllocateStockHandler(salesOrder: widget.order), + ); + }, + ), + ); + } + } + + 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", + backup: true, + ); + showCameraShortcut = await InvenTreeSettingsManager().getBool( + INV_SO_SHOW_CAMERA, + 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) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + + // 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; + }); + } + }); + } + + // 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: LargeText( + api.SalesOrderStatus.label(widget.order.status), + 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: Icon(TablerIcons.list), + ), + ); + } + + if (customer != null) { + tiles.add( + ListTile( + title: Text(L10().customer), + subtitle: Text(customer.name), + leading: Icon(TablerIcons.user, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + customer.goToDetailPage(context); + }, + ), + ); + } + + if (widget.order.customerReference.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().customerReference), + trailing: LargeText(widget.order.customerReference), + leading: Icon(TablerIcons.hash), + ), + ); + } + + Color lineColor = widget.order.complete ? COLOR_SUCCESS : COLOR_WARNING; + + // Line items progress + tiles.add( + ListTile( + title: Text(L10().lineItems), + subtitle: ProgressBar( + widget.order.completedLineItemCount.toDouble(), + maximum: widget.order.lineItemCount.toDouble(), + ), + leading: Icon(TablerIcons.clipboard_check), + trailing: LargeText( + "${widget.order.completedLineItemCount} / ${widget.order.lineItemCount}", + 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.cube_send), + trailing: LargeText( + "${widget.order.completedShipmentCount} / ${widget.order.shipmentCount}", + color: lineColor, + ), + ), + ); + } + + // Extra line items + tiles.add( + ListTile( + title: Text(L10().extraLineItems), + leading: Icon(TablerIcons.clipboard_list, color: COLOR_ACTION), + trailing: LinkIcon(text: extraLineCount.toString()), + onTap: () => { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SOExtraLineListWidget( + widget.order, + filters: {"order": widget.order.pk.toString()}, + ), + ), + ), + }, + ), + ); + + // TODO: total price + + if (widget.order.startDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().startDate), + trailing: LargeText(widget.order.startDate), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.order.targetDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().targetDate), + trailing: LargeText(widget.order.targetDate), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.order.shipmentDate.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().completionDate), + trailing: LargeText(widget.order.shipmentDate), + 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: LargeText(widget.order.responsibleName), + ), + ); + } + + // 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.order)), + ); + }, + ), + ); + + 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, + widget.order.pk, + widget.order.reference, + attachmentCount, + widget.order.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + + return tiles; + } + + @override + List getTabIcons(BuildContext context) { + return [ + Tab(text: L10().details), + Tab(text: L10().lineItems), + Tab(text: L10().shipments), + ]; + } + + @override + List getTabs(BuildContext context) { + return [ + ListView(children: orderTiles(context)), + PaginatedSOLineList({"order": widget.order.pk.toString()}), + PaginatedSOShipmentList({"order": widget.order.pk.toString()}), + ]; + } +} diff --git a/lib/widget/order/sales_order_list.dart b/lib/widget/order/sales_order_list.dart new file mode 100644 index 0000000..e05bcf5 --- /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: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"; +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: Icon(TablerIcons.circle_plus), + 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); + order.goToDetailPage(context); + } + }, + ); + } + + @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, + "default": true, + }, + "overdue": { + "label": L10().overdue, + "help_text": L10().overdueDetail, + "tristate": true, + }, + "assigned_to_me": { + "label": L10().assignedToMe, + "help_text": L10().assignedToMeDetail, + "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; + + // 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(subtitle), + leading: customer == null + ? null + : InvenTreeAPI().getThumbnail(customer.thumbnail), + trailing: LargeText( + InvenTreeAPI().SalesOrderStatus.label(order.status), + color: InvenTreeAPI().SalesOrderStatus.color(order.status), + ), + onTap: () async { + order.goToDetailPage(context); + }, + ); + } +} diff --git a/lib/widget/order/so_allocation_list.dart b/lib/widget/order/so_allocation_list.dart new file mode 100644 index 0000000..88699d0 --- /dev/null +++ b/lib/widget/order/so_allocation_list.dart @@ -0,0 +1,70 @@ +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; + InvenTreeStockLocation? location = allocation.location; + + return ListTile( + title: Text(part?.fullname ?? ""), + subtitle: Text(location?.pathstring ?? L10().locationNotSet), + onTap: () async { + stockItem?.goToDetailPage(context); + }, + leading: InvenTreeAPI().getThumbnail(allocation.part?.thumbnail ?? ""), + trailing: LargeText(stockItem?.serialOrQuantityDisplay() ?? ""), + ); + } +} diff --git a/lib/widget/order/so_extra_line_list.dart b/lib/widget/order/so_extra_line_list.dart new file mode 100644 index 0000000..06521e6 --- /dev/null +++ b/lib/widget/order/so_extra_line_list.dart @@ -0,0 +1,124 @@ +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/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"; +import "package:inventree/widget/snacks.dart"; + +class SOExtraLineListWidget extends StatefulWidget { + const SOExtraLineListWidget(this.order, {this.filters = const {}, Key? key}) + : super(key: key); + + final InvenTreeSalesOrder order; + + final Map filters; + + @override + _SalesOrderExtraLineListWidgetState createState() => + _SalesOrderExtraLineListWidgetState(); +} + +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); + }, + ); + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (widget.order.canEdit) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().lineItemAdd, + onTap: () { + _addLineItem(context); + }, + ), + ); + } + + return actions; + } + + @override + Widget getBody(BuildContext context) { + return PaginatedSOExtraLineList(widget.filters); + } +} + +class PaginatedSOExtraLineList extends PaginatedSearchWidget { + const PaginatedSOExtraLineList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().extraLineItems; + + @override + _PaginatedSOExtraLineListState createState() => + _PaginatedSOExtraLineListState(); +} + +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, + ); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeSOExtraLineItem line = model as InvenTreeSOExtraLineItem; + + return ListTile( + title: Text(line.reference), + subtitle: Text(line.description), + 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 new file mode 100644 index 0000000..bc6fd6f --- /dev/null +++ b/lib/widget/order/so_line_detail.dart @@ -0,0 +1,262 @@ +/* + * 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:flutter_tabler_icons/flutter_tabler_icons.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"; +import "package:inventree/widget/link_icon.dart"; + +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/progress.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 { + const SoLineDetailWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreeSOLineItem item; + + @override + _SOLineDetailWidgetState createState() => _SOLineDetailWidgetState(); +} + +class _SOLineDetailWidgetState extends RefreshableState { + _SOLineDetailWidgetState(); + + InvenTreeSalesOrder? order; + + @override + String getAppBarTitle() => L10().lineItem; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.item.canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + onPressed: () { + _editLineItem(context); + }, + ), + ); + } + + return actions; + } + + Future _allocateStock(BuildContext context) async { + if (order == null) { + return; + } + + 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( + context, + L10().allocateStock, + order!.allocate_url, + fields, + method: "POST", + icon: TablerIcons.transition_right, + onSuccess: (data) async { + refresh(context); + }, + ); + } + + 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) { + List buttons = []; + + if (order != null && order!.isOpen) { + buttons.add( + SpeedDialChild( + child: Icon(TablerIcons.transition_right, color: Colors.blue), + label: L10().allocateStock, + onTap: () async { + _allocateStock(context); + }, + ), + ); + } + + return buttons; + } + + @override + List barcodeButtons(BuildContext context) { + 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, + ), + ); + }, + ), + ); + } + } + + return actions; + } + + @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 + List getTiles(BuildContext context) { + List tiles = []; + + // Reference to the part + tiles.add( + ListTile( + title: Text(L10().part), + subtitle: Text(widget.item.partName), + leading: Icon(TablerIcons.box, color: COLOR_ACTION), + trailing: LinkIcon(image: api.getThumbnail(widget.item.partImage)), + onTap: () async { + showLoadingOverlay(); + var part = await InvenTreePart().get(widget.item.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + }, + ), + ); + + // Available quantity + tiles.add( + ListTile( + title: Text(L10().availableStock), + leading: Icon(TablerIcons.packages), + trailing: LargeText(simpleNumberString(widget.item.availableStock)), + ), + ); + + // Allocated quantity + tiles.add( + ListTile( + leading: Icon(TablerIcons.clipboard_check), + title: Text(L10().allocated), + subtitle: ProgressBar(widget.item.allocatedRatio), + trailing: LargeText( + widget.item.allocatedString, + color: widget.item.isAllocated ? COLOR_SUCCESS : COLOR_WARNING, + ), + ), + ); + + // Shipped quantity + tiles.add( + ListTile( + title: Text(L10().shipped), + subtitle: ProgressBar(widget.item.progressRatio), + trailing: LargeText( + widget.item.progressString, + color: widget.item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, + ), + leading: Icon(TablerIcons.truck), + ), + ); + + // Reference + if (widget.item.reference.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().reference), + subtitle: Text(widget.item.reference), + 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), + ), + ); + } + + // External link + if (widget.item.hasLink) { + 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); + }, + ), + ); + } + + return tiles; + } +} diff --git a/lib/widget/order/so_line_list.dart b/lib/widget/order/so_line_list.dart new file mode 100644 index 0000000..acadfeb --- /dev/null +++ b/lib/widget/order/so_line_list.dart @@ -0,0 +1,95 @@ +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"; +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: LargeText( + item.progressString, + color: item.isComplete ? COLOR_SUCCESS : COLOR_WARNING, + ), + onTap: () async { + showLoadingOverlay(); + 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/order/so_shipment_detail.dart b/lib/widget/order/so_shipment_detail.dart new file mode 100644 index 0000000..34984df --- /dev/null +++ b/lib/widget/order/so_shipment_detail.dart @@ -0,0 +1,381 @@ +/* + * 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/attachment.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); + }); + } + + InvenTreeAttachment() + .countAttachments( + InvenTreeSalesOrderShipment.MODEL_TYPE, + widget.shipment.pk, + ) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + } + + /// Upload an image for this shipment + Future _uploadImage(BuildContext context) async { + InvenTreeAttachment() + .uploadImage( + InvenTreeSalesOrderShipment.MODEL_TYPE, + 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), + ), + ); + }, + ), + ); + + 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; + } + + @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 new file mode 100644 index 0000000..221d748 --- /dev/null +++ b/lib/widget/order/so_shipment_list.dart @@ -0,0 +1,100 @@ +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"; +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) + : 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; + + InvenTreeSalesOrder? order = shipment.order; + return ListTile( + 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.isShipped + ? LargeText(shipment.shipment_date ?? "") + : LargeText(L10().pending), + ); + } +} diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index c3343a7..123c7ab 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -1,31 +1,275 @@ +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: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"; import "package:inventree/inventree/sentry.dart"; -import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; +import "package:inventree/widget/refreshable_state.dart"; -class PaginatedSearchState extends State { +/* + * Abstract base widget class for rendering a PaginatedSearchState + */ +abstract class PaginatedSearchWidget extends StatefulWidget { + const PaginatedSearchWidget({this.filters = const {}, this.title = ""}); - PaginatedSearchState(this.filters); + final String title; + + String get searchTitle => title; final Map filters; +} +/* + * Generic stateful widget for displaying paginated data retrieved via the API + */ +abstract class PaginatedSearchState + extends State + with BaseWidgetProperties { static const _pageSize = 25; + bool showSearchWidget = false; + + // Prefix for storing and loading pagination options + // 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 => {}; + + // Return the boolean value of a particular boolean filter + Future getFilterValue(String key) async { + final String settings_key = "${prefix}filter_${key}"; + + Map opts = filterOptions[key] ?? {}; + + bool tristate = (opts["tristate"] ?? true) as bool; + 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 { + final String settings_key = "${prefix}filter_${key}"; + + if (value == null) { + await InvenTreeSettingsManager().removeValue(settings_key); + } else { + await InvenTreeSettingsManager().setValue(settings_key, value); + } + } + + // Construct the boolean filter options for this list + Future> constructFilters() async { + Map f = {}; + + for (String k in filterOptions.keys) { + dynamic value = await getFilterValue(k); + + // Skip null values + if (value == null) { + continue; + } + f[k] = value.toString(); + } + + return f; + } + + // Return a map of sorting options available for this list + // Should be overridden by an implementing subclass + Map get orderingOptions => {}; + + // Return the selected ordering "field" for this list widget + Future orderingField() async { + dynamic field = await InvenTreeSettingsManager().getValue( + "${prefix}ordering_field", + null, + ); + + 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; + } 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 == "+" ? "+" : "-"; + } + + // 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 _setOrderingOptions(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": L10().searchOrderingField, + "required": true, + "choices": _opts, + "value": _field, + }, + "ordering_order": { + "type": "choice", + "label": L10().searchOrderingDirection, + "required": true, + "value": _order, + "choices": [ + {"value": "+", "display_name": L10().searchOrderingAscending}, + {"value": "-", "display_name": L10().searchOrderingDescending}, + ], + }, + }; + + // Add in selected filter options + for (String key in filterOptions.keys) { + Map opts = filterOptions[key] ?? {}; + + // Determine field information + 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; + + dynamic v = await getFilterValue(key); + + // Prevent null value if not tristate + if (!tristate && v == null) { + v = false; + } + + Map filter = { + "type": "boolean", + "display_name": label, + "label": label, + "help_text": help_text, + "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 + launchApiForm( + context, + L10().filteringOptions, + "", + 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; + + // Save values to settings + await InvenTreeSettingsManager().setValue("${prefix}ordering_field", f); + await InvenTreeSettingsManager().setValue("${prefix}ordering_order", o); + + // Save boolean fields + for (String key in filterOptions.keys) { + await setFilterValue(key, data[key]); + } + + // Refresh data from the server + _pagingController.refresh(); + }, + ); + } + // Search query term String searchTerm = ""; int resultCount = 0; + String resultsString() { + if (resultCount <= 0) { + return noResultsText; + } else { + return "${resultCount} ${L10().results}"; + } + } + // Text controller final TextEditingController searchController = TextEditingController(); + // Debounce timer + Timer? _debounceTimer; + // Pagination controller - final PagingController _pagingController = PagingController(firstPageKey: 0); + final PagingController _pagingController = + PagingController(firstPageKey: 0); + + void refresh() { + _pagingController.refresh(); + } @override void initState() { @@ -42,24 +286,63 @@ class PaginatedSearchState extends State { super.dispose(); } - Future requestPage(int limit, int offset, Map params) async { - - print("Blank request page"); + /* + * 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; + Map params = widget.filters; - params["search"] = "${searchTerm}"; + // Include user search term + if (searchTerm.isNotEmpty) { + String _search = searchTerm; - final page = await requestPage( - _pageSize, - pageKey, - params - ); + // Include original search in search test + String original = params["original_search"] ?? ""; + + if (original.isNotEmpty) { + _search = "${original} ${_search}"; + } + + params["search"] = "${_search}"; + } else { + // Remove search term if it is empty + params.remove("search"); + } + + // Use custom query ordering if available + String o = await orderingString; + if (o.isNotEmpty) { + params["ordering"] = o; + } + + Map f = await constructFilters(); + + if (f.isNotEmpty) { + params.addAll(f); + } + + 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 + if (!mounted) { + return; + } int pageLength = page?.length ?? 0; int pageCount = page?.count ?? 0; @@ -70,7 +353,7 @@ class PaginatedSearchState extends State { if (page != null) { for (var result in page.results) { - items.add(result); + items.add(result); } } @@ -87,17 +370,45 @@ class PaginatedSearchState extends State { } catch (error, stackTrace) { _pagingController.error = error; - sentryReportError(error, stackTrace); + sentryReportError("paginator.fetchPage", error, stackTrace); } } + // Callback function when the search term is updated void updateSearchTerm() { - searchTerm = searchController.text; - _pagingController.refresh(); + if (searchTerm == searchController.text) { + // No change + return; + } + + // Debounce the search term + if (_debounceTimer?.isActive ?? false) { + _debounceTimer?.cancel(); + } + + if (searchController.text.isEmpty) { + // An empty search term evaluates immediately + searchTerm = ""; + _pagingController.refresh(); + + if (mounted) { + setState(() {}); + } + } else { + _debounceTimer = Timer(const Duration(milliseconds: 500), () { + searchTerm = searchController.text; + _pagingController.refresh(); + + if (mounted) { + setState(() {}); + } + }); + } } + // 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 ***"), @@ -105,94 +416,146 @@ 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) { - return Column( + Widget build(BuildContext context) { + List children = [buildTitleWidget(context), Divider()]; + + if (showSearchWidget) { + children.add(buildSearchInput(context)); + } + + 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), + ), + ], + ), + ), + ); + + return RefreshIndicator( + child: Column( mainAxisAlignment: MainAxisAlignment.start, - children: [ - PaginatedSearchWidget(searchController, updateSearchTerm, resultCount), - Expanded( - child: CustomScrollView( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - scrollDirection: Axis.vertical, - slivers: [ - // TODO - Search input - PagedSliverList.separated( - pagingController: _pagingController, - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (context, item, index) { - return buildItem(context, item); - }, - noItemsFoundIndicatorBuilder: (context) { - return NoResultsWidget(noResultsText); - } - ), - separatorBuilder: (context, item) => const Divider(height: 1), - ) - ] - ) - ) - ] + children: children, + ), + onRefresh: () async { + _pagingController.refresh(); + }, ); } -} + /* + * Build the title widget for this list + */ + Widget buildTitleWidget(BuildContext context) { + const double icon_size = 32; + List _icons = []; -class PaginatedSearchWidget extends StatelessWidget { + if (filterOptions.isNotEmpty || orderingOptions.isNotEmpty) { + _icons.add( + IconButton( + onPressed: () async { + _setOrderingOptions(context); + }, + icon: Icon(Icons.filter_alt, size: icon_size), + ), + ); + } - const PaginatedSearchWidget(this.controller, this.onChanged, this.results); + _icons.add( + IconButton( + onPressed: () { + setState(() { + showSearchWidget = !showSearchWidget; + }); + }, + icon: Icon( + showSearchWidget ? Icons.zoom_out : Icons.search, + size: icon_size, + ), + ), + ); - final Function onChanged; + // _icons.add(IconButton( + // onPressed: () async { + // updateSearchTerm(); + // }, + // icon: Icon(Icons.refresh, size: icon_size), + // )); - final int results; - - final TextEditingController controller; - - @override - Widget build(BuildContext context) { return ListTile( - leading: GestureDetector( - child: FaIcon(controller.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace), + 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( + trailing: GestureDetector( + child: Icon( + searchController.text.isEmpty + ? TablerIcons.search + : TablerIcons.backspace, + color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_ACTION, + ), onTap: () { - controller.clear(); - onChanged(); + if (searchController.text.isNotEmpty) { + searchController.clear(); + } + updateSearchTerm(); }, ), title: TextFormField( - controller: controller, + controller: searchController, onChanged: (value) { - onChanged(); + updateSearchTerm(); }, - decoration: InputDecoration( - hintText: L10().search, - ), - ), - trailing: Text( - "${results}", - style: TextStyle(fontWeight: FontWeight.bold), + 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(L10().noResults), - subtitle: Text(description), - leading: FaIcon(FontAwesomeIcons.exclamationCircle), + title: Text(description, style: TextStyle(fontStyle: FontStyle.italic)), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_WARNING), ); } - } diff --git a/lib/widget/parameter_widget.dart b/lib/widget/parameter_widget.dart new file mode 100644 index 0000000..8bcc360 --- /dev/null +++ b/lib/widget/parameter_widget.dart @@ -0,0 +1,192 @@ +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/widget/link_icon.dart"; +import "package:inventree/widget/paginator.dart"; +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/refreshable_state.dart"; + +/* + * Widget for displaying a list of parameters associated with a given Part instance + */ +class ParameterWidget extends StatefulWidget { + const ParameterWidget(this.modelType, this.modelId, this.editable) : super(); + + final String modelType; + final int modelId; + final bool editable; + + @override + _ParameterWidgetState createState() => _ParameterWidgetState(); +} + +class _ParameterWidgetState extends RefreshableState { + _ParameterWidgetState(); + + @override + String getAppBarTitle() { + return L10().parameters; + } + + @override + List appBarActions(BuildContext context) { + return []; + } + + @override + Widget getBody(BuildContext context) { + Map filters = { + "model_type": widget.modelType, + "model_id": widget.modelId.toString(), + }; + + return Column( + children: [ + Expanded(child: PaginatedParameterList(filters, widget.editable)), + ], + ); + } +} + +/* + * Widget for displaying a paginated list of Part parameters + */ +class PaginatedParameterList extends PaginatedSearchWidget { + const PaginatedParameterList(Map filters, this.editable) + : super(filters: filters); + + final bool editable; + + @override + String get searchTitle => L10().parameters; + + @override + _PaginatedParameterState createState() => _PaginatedParameterState(); +} + +class _PaginatedParameterState + extends PaginatedSearchState { + _PaginatedParameterState() : super(); + + @override + String get prefix => "parameters_"; + + @override + Map get orderingOptions => {}; + + @override + Map> get filterOptions => { + // TODO + }; + + @override + Future requestPage( + int limit, + int offset, + Map params, + ) async { + final page = await InvenTreeParameter().listPaginated( + limit, + offset, + filters: params, + ); + + return page; + } + + Future editParameter(InvenTreeParameter 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) { + InvenTreeParameter parameter = model as InvenTreeParameter; + + String title = parameter.name; + + if (parameter.units.isNotEmpty) { + title += " [${parameter.units}]"; + } + + return ListTile( + title: Text(title), + subtitle: Text(parameter.description), + trailing: parameter.is_checkbox + ? Switch( + value: parameter.as_bool, + onChanged: (bool value) { + if (widget.editable) { + showLoadingOverlay(); + parameter.update(values: {"data": value.toString()}).then(( + value, + ) async { + hideLoadingOverlay(); + updateSearchTerm(); + }); + } + }, + ) + : LargeText(parameter.value), + onTap: parameter.is_checkbox + ? null + : () async { + 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/bom_list.dart b/lib/widget/part/bom_list.dart new file mode 100644 index 0000000..5e17e53 --- /dev/null +++ b/lib/widget/part/bom_list.dart @@ -0,0 +1,178 @@ +import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; +import "package:inventree/l10.dart"; + +import "package:inventree/inventree/bom.dart"; +import "package:inventree/inventree/model.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"; + +/* + * 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); + + final InvenTreePart part; + + final bool isParentComponent; + + @override + _BillOfMaterialsState createState() => _BillOfMaterialsState(); +} + +class _BillOfMaterialsState extends RefreshableState { + _BillOfMaterialsState(); + + bool showFilterOptions = false; + + @override + String getAppBarTitle() { + if (widget.isParentComponent) { + return L10().billOfMaterials; + } else { + return L10().usedIn; + } + } + + @override + List appBarActions(BuildContext context) => [ + IconButton( + icon: Icon(TablerIcons.filter), + onPressed: () async { + setState(() { + showFilterOptions = !showFilterOptions; + }); + }, + ), + ]; + + @override + Widget getBody(BuildContext context) { + Map filters = {}; + + if (widget.isParentComponent) { + filters["part"] = widget.part.pk.toString(); + } else { + filters["uses"] = widget.part.pk.toString(); + } + + return Column( + children: [ + ListTile( + leading: InvenTreeAPI().getThumbnail(widget.part.thumbnail), + title: Text(widget.part.fullname), + subtitle: Text( + widget.isParentComponent + ? L10().billOfMaterials + : L10().usedInDetails, + ), + trailing: Text(L10().quantity), + ), + Divider(thickness: 1.25), + Expanded( + child: PaginatedBomList( + filters, + isParentPart: widget.isParentComponent, + ), + ), + ], + ); + } +} + +/* + * Create a paginated widget displaying a list of BomItem objects + */ +class PaginatedBomList extends PaginatedSearchWidget { + const PaginatedBomList( + Map filters, { + this.isParentPart = true, + }) : super(filters: filters); + + final bool isParentPart; + + @override + String get searchTitle => L10().parts; + + @override + _PaginatedBomListState createState() => _PaginatedBomListState(); +} + +class _PaginatedBomListState extends PaginatedSearchState { + _PaginatedBomListState() : super(); + + @override + String get prefix => "bom_"; + + @override + Map get orderingOptions => { + "quantity": L10().quantity, + "sub_part": L10().part, + }; + + @override + Map> get filterOptions => { + "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, + ); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeBomItem bomItem = model as InvenTreeBomItem; + + InvenTreePart? subPart = widget.isParentPart + ? bomItem.subPart + : bomItem.part; + + String title = subPart?.fullname ?? "error - no name"; + + return ListTile( + title: Text(title), + subtitle: Text(bomItem.reference), + trailing: Text( + simpleNumberString(bomItem.quantity), + style: TextStyle(fontWeight: FontWeight.bold), + ), + leading: InvenTreeAPI().getThumbnail(subPart?.thumbnail ?? ""), + onTap: subPart == null + ? null + : () async { + showLoadingOverlay(); + var part = await InvenTreePart().get(subPart.pk); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + }, + ); + } +} diff --git a/lib/widget/part/category_display.dart b/lib/widget/part/category_display.dart new file mode 100644 index 0000000..bb9464b --- /dev/null +++ b/lib/widget/part/category_display.dart @@ -0,0 +1,258 @@ +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/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"; +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; + + @override + _CategoryDisplayState createState() => _CategoryDisplayState(); +} + +class _CategoryDisplayState extends RefreshableState { + _CategoryDisplayState(); + + @override + String getAppBarTitle() => L10().partCategory; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (widget.category != null) { + if (InvenTreePartCategory().canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editCategory, + onPressed: () { + _editCategoryDialog(context); + }, + ), + ); + } + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreePart().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.box), + label: L10().partCreateDetail, + onTap: _newPart, + ), + ); + } + + if (InvenTreePartCategory().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.sitemap), + label: L10().categoryCreateDetail, + onTap: () { + _newCategory(context); + }, + ), + ); + } + + return actions; + } + + void _editCategoryDialog(BuildContext context) { + final _cat = widget.category; + + // Cannot edit top-level category + if (_cat == null) { + return; + } + + _cat.editForm( + context, + L10().editCategory, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().categoryUpdated, success: true); + }, + ); + } + + @override + Future onBuild(BuildContext context) async { + refresh(context); + } + + @override + Future request(BuildContext context) async { + // Update the category + if (widget.category != null) { + final bool result = await widget.category?.reload() ?? false; + + if (!result) { + Navigator.of(context).pop(); + } + } + } + + Widget getCategoryDescriptionCard({bool extra = true}) { + if (widget.category == null) { + return Card( + child: ListTile( + leading: Icon(TablerIcons.packages), + title: Text( + L10().partCategoryTopLevel, + style: TextStyle(fontStyle: FontStyle.italic), + ), + ), + ); + } else { + List children = [ + ListTile( + 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), + ), + ]; + + if (extra) { + children.add( + ListTile( + 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; + + 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); + } + } + }, + ), + ); + } + + return Card(child: Column(children: children)); + } + } + + @override + 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 + 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(filters, title: L10().subcategories), + flex: 10, + ), + ]; + + return tiles; + } + + // Construct the "parts" panel + List partsTiles() { + Map filters = { + "category": widget.category?.pk.toString() ?? "null", + }; + + 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}, + onSuccess: (result) async { + Map data = result as Map; + + if (data.containsKey("pk")) { + var cat = InvenTreePartCategory.fromJson(data); + cat.goToDetailPage(context).then((_) { + refresh(context); + }); + } else { + refresh(context); + } + }, + ); + } + + Future _newPart() async { + int pk = widget.category?.pk ?? -1; + + InvenTreePart().createForm( + context, + L10().partCreate, + 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 new file mode 100644 index 0000000..b90f2f6 --- /dev/null +++ b/lib/widget/part/category_list.dart @@ -0,0 +1,114 @@ +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"; + +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 + String getAppBarTitle() => L10().partCategories; + + @override + Widget getBody(BuildContext context) { + return PaginatedPartCategoryList(widget.filters); + } +} + +class PaginatedPartCategoryList extends PaginatedSearchWidget { + const PaginatedPartCategoryList( + Map filters, { + String title = "", + }) : super(filters: filters, title: title); + + @override + String get searchTitle => title.isNotEmpty ? title : L10().partCategories; + + @override + _PaginatedPartCategoryListState createState() => + _PaginatedPartCategoryListState(); +} + +class _PaginatedPartCategoryListState + extends PaginatedSearchState { + // _PaginatedPartCategoryListState(Map filters, bool searchEnabled) : super(filters, searchEnabled); + + @override + String get prefix => "category_"; + + @override + Map> get filterOptions => { + "cascade": { + "default": false, + "label": L10().includeSubcategories, + "help_text": L10().includeSubcategoriesDetail, + "tristate": false, + }, + }; + + @override + String get defaultOrdering => "pathstring"; + + @override + Map get orderingOptions { + Map options = { + "name": L10().name, + "pathstring": L10().path, + "level": L10().level, + }; + + // Note: API v69 changed 'parts' to 'part_count' + if (InvenTreeAPI().apiVersion >= 69) { + options["part_count"] = L10().parts; + } else { + options["parts"] = L10().parts; + } + + return options; + } + + @override + 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( + title: Text(category.name), + subtitle: Text(category.pathstring), + trailing: LargeText("${category.partcount}", size: 14), + leading: category.customIcon == null ? null : Icon(category.customIcon), + onTap: () { + category.goToDetailPage(context); + }, + ); + } +} 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_detail.dart b/lib/widget/part/part_detail.dart new file mode 100644 index 0000000..73a299f --- /dev/null +++ b/lib/widget/part/part_detail.dart @@ -0,0 +1,744 @@ +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/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"; + +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"; +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_pricing.dart"; +import "package:inventree/widget/progress.dart"; +import "package:inventree/widget/part/category_display.dart"; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/widget/part/part_image_widget.dart"; +import "package:inventree/widget/snacks.dart"; +import "package:inventree/widget/stock/stock_list.dart"; +import "package:inventree/widget/company/supplier_part_list.dart"; + +/* + * Widget for displaying a detail view of a single Part instance + */ +class PartDetailWidget extends StatefulWidget { + const PartDetailWidget(this.part, {Key? key}) : super(key: key); + + final InvenTreePart part; + + @override + _PartDisplayState createState() => _PartDisplayState(part); +} + +class _PartDisplayState extends RefreshableState { + _PartDisplayState(this.part); + + InvenTreePart part; + + InvenTreePart? parentPart; + + InvenTreeStockLocation? defaultLocation; + + bool allowLabelPrinting = false; + bool showBom = false; + bool showPricing = false; + + int parameterCount = 0; + int attachmentCount = 0; + int bomCount = 0; + int usedInCount = 0; + int variantCount = 0; + + InvenTreePartPricing? partPricing; + + @override + String getAppBarTitle() => L10().partDetails; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (InvenTreePart().canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editPart, + onPressed: () { + _editPartDialog(context); + }, + ), + ); + } + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (InvenTreePart().canEdit) { + actions.add( + customBarcodeAction( + context, + this, + widget.part.customBarcode, + "part", + widget.part.pk, + ), + ); + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreeStockItem().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.packages), + label: L10().stockItemCreate, + onTap: () { + _newStockItem(context); + }, + ), + ); + } + + if (allowLabelPrinting && api.supportsModernLabelPrinting) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.printer), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel(context, "part", widget.part.pk); + }, + ), + ); + } + + return actions; + } + + @override + Future onBuild(BuildContext context) async { + refresh(context); + + if (mounted) { + setState(() {}); + } + } + + @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, + ); + 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(); + return; + } + + // If the part points to a parent "template" part, request that too + int? templatePartId = part.variantOf; + + 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 + if (part.isTestable) { + part.getTestTemplates().then((value) { + if (mounted) { + setState(() {}); + } + }); + } + + // Request the number of attachments + 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) { + part.getPricing().then((InvenTreePartPricing? pricing) { + if (mounted) { + setState(() { + partPricing = pricing; + }); + } + }); + } + + // Request the number of BOM items + InvenTreePart().count(filters: {"in_bom_for": part.pk.toString()}).then(( + int value, + ) { + if (mounted) { + setState(() { + bomCount = value; + }); + } + }); + + // Request number of "used in" parts + InvenTreeBomItem().count(filters: {"uses": part.pk.toString()}).then(( + int value, + ) { + if (mounted) { + setState(() { + usedInCount = value; + }); + } + }); + + // Request the number of variant items + InvenTreePart().count(filters: {"variant_of": part.pk.toString()}).then(( + int value, + ) { + if (mounted) { + setState(() { + variantCount = value; + }); + } + }); + } + + 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); + }); + }, + ), + ), + ); + } + + /* + * Build a list of tiles to display under the part description + */ + List partTiles() { + List tiles = []; + + // Image / name / description + tiles.add(headerTile()); + + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + + if (!part.isActive) { + tiles.add( + ListTile( + title: Text(L10().inactive, style: TextStyle(color: COLOR_DANGER)), + subtitle: Text( + L10().inactiveDetail, + style: TextStyle(color: COLOR_DANGER), + ), + leading: Icon(TablerIcons.exclamation_circle, color: COLOR_DANGER), + ), + ); + } + + if (parentPart != null) { + tiles.add( + ListTile( + title: Text(L10().templatePart), + subtitle: Text(parentPart!.fullname), + leading: api.getImage(parentPart!.thumbnail, width: 32, height: 32), + trailing: LinkIcon(), + onTap: () { + parentPart?.goToDetailPage(context); + }, + ), + ); + } + + // Category information + if (part.categoryName.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().partCategory), + subtitle: Text("${part.categoryName}"), + leading: Icon(TablerIcons.sitemap, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + if (part.categoryId > 0) { + showLoadingOverlay(); + var cat = await InvenTreePartCategory().get(part.categoryId); + hideLoadingOverlay(); + + 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), + ), + ); + }, + ), + ); + } + + // 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: LinkIcon(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), + subtitle: Text(L10().stockDetails), + leading: Icon(TablerIcons.packages), + trailing: LargeText(part.stockString()), + ), + ); + + 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, + partPricing?.overallMax, + currency: partPricing?.currency, + ); + + tiles.add( + ListTile( + title: Text(L10().partPricing), + subtitle: Text( + pricing.isNotEmpty ? pricing : L10().noPricingAvailable, + ), + leading: Icon(TablerIcons.currency_dollar, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + PartPricingWidget(part: part, partPricing: partPricing), + ), + ); + }, + ), + ); + } + + // Tiles for "purchaseable" parts + if (part.isPurchaseable) { + // On order + tiles.add( + ListTile( + title: Text(L10().onOrder), + subtitle: Text(L10().onOrderDetails), + leading: Icon(TablerIcons.shopping_cart), + trailing: LargeText("${part.onOrderString}"), + 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: LinkIcon(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: LargeText("${simpleNumberString(part.building)}"), + onTap: () { + // TODO: List of active build orders? + }, + ), + ); + } + } + + if (part.isComponent) { + if (showBom && usedInCount > 0) { + tiles.add( + ListTile( + title: Text(L10().usedIn), + subtitle: Text(L10().usedInDetails), + leading: Icon(TablerIcons.stack_2, color: COLOR_ACTION), + trailing: LinkIcon(text: usedInCount.toString()), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + BillOfMaterialsWidget(part, isParentComponent: false), + ), + ); + }, + ), + ); + } + } + + // Keywords? + if (part.keywords.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${part.keywords}"), + leading: Icon(TablerIcons.tags), + ), + ); + } + + // External link? + if (part.hasLink) { + tiles.add( + 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), + subtitle: Text(L10().usedInDetails), + leading: Icon(TablerIcons.sitemap), + trailing: LargeText("${part.usedInCount}"), + onTap: () { + // TODO: Show assemblies which use this part + }, + ), + ); + } + + if (part.isPurchaseable) { + if (part.supplierCount > 0) { + tiles.add( + ListTile( + title: Text(L10().suppliers), + leading: Icon(TablerIcons.building_factory, color: COLOR_ACTION), + trailing: LinkIcon(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: LinkIcon(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NotesWidget(part)), + ); + }, + ), + ); + + 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, + part.pk, + L10().part, + attachmentCount, + part.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + + return tiles; + } + + // Return tiles for each stock item + List stockTiles() { + List tiles = []; + + tiles.add(headerTile()); + + tiles.add( + ListTile( + title: Text( + L10().stockItems, + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: part.stockItems.isEmpty + ? Text(L10().stockItemsNotAvailable) + : null, + trailing: part.stockItems.isNotEmpty + ? Text("${part.stockItems.length}") + : null, + ), + ); + + return tiles; + } + + /* + * 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 + fields.remove("serial"); + + // Hide the "part" field + fields["part"]?["hidden"] = true; + + int? default_location = part.defaultLocation; + + Map data = {"part": part.pk.toString()}; + + if (default_location != null) { + data["location"] = default_location; + } + + if (part.isTrackable) { + // read the next available serial number + showLoadingOverlay(); + 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"]; + } + + print( + "response: " + + response.statusCode.toString() + + response.data.toString(), + ); + } else { + // Cannot set serial numbers for non-trackable parts + fields.remove("serial_numbers"); + } + + print("data: ${data.toString()}"); + + InvenTreeStockItem().createForm( + context, + L10().stockItemCreate, + fields: fields, + data: data, + onSuccess: (result) async { + Map data = result as Map; + + 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)]; + + return icons; + } + + @override + List getTabs(BuildContext context) { + List tabs = [ + SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column(children: partTiles()), + ), + PaginatedStockItemList({"part": part.pk.toString()}), + ]; + return tabs; + } +} diff --git a/lib/widget/part/part_image_widget.dart b/lib/widget/part/part_image_widget.dart new file mode 100644 index 0000000..b40353c --- /dev/null +++ b/lib/widget/part/part_image_widget.dart @@ -0,0 +1,170 @@ +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"; + +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; + + @override + Future request(BuildContext context) async { + await part.reload(); + } + + @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 = [ + if (part.canEdit) ...[ + // Delete image button + if (part.jsondata["image"] != null) + IconButton( + icon: Icon(TablerIcons.trash), + tooltip: L10().deleteImageTooltip, + onPressed: _deleteImage, + ), + + // File upload with cropping + IconButton( + icon: Icon(TablerIcons.file_upload), + tooltip: L10().uploadImage, + onPressed: () async { + FilePickerDialog.pickFile( + onPicked: (File file) async { + await _processImageWithCropping(file); + }, + ); + }, + ), + ], + ]; + + return actions; + } + + @override + Widget getBody(BuildContext context) { + return Center(child: InvenTreeAPI().getImage(part.image)); + } +} diff --git a/lib/widget/part/part_list.dart b/lib/widget/part/part_list.dart new file mode 100644 index 0000000..040de2c --- /dev/null +++ b/lib/widget/part/part_list.dart @@ -0,0 +1,133 @@ +import "package:flutter/material.dart"; + +import "package:inventree/api.dart"; +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"; + +class PartList extends StatefulWidget { + const PartList(this.filters, {this.title = ""}); + + final String title; + + final Map filters; + + @override + _PartListState createState() => _PartListState(filters, title); +} + +class _PartListState extends RefreshableState { + _PartListState(this.filters, this.title); + + final String title; + + final Map filters; + + bool showFilterOptions = false; + + @override + String getAppBarTitle() => title.isNotEmpty ? title : L10().parts; + + @override + Widget getBody(BuildContext context) { + return PaginatedPartList(filters); + } +} + +class PaginatedPartList extends PaginatedSearchWidget { + const PaginatedPartList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().parts; + + @override + _PaginatedPartListState createState() => _PaginatedPartListState(); +} + +class _PaginatedPartListState extends PaginatedSearchState { + _PaginatedPartListState() : super(); + + @override + String get prefix => "part_"; + + @override + Map get orderingOptions => { + "name": L10().name, + "in_stock": L10().stock, + "IPN": L10().internalPartNumber, + }; + + @override + Map> get filterOptions => { + "cascade": { + "default": true, + "label": L10().includeSubcategories, + "help_text": L10().includeSubcategoriesDetail, + }, + "active": { + "label": L10().filterActive, + "help_text": L10().filterActiveDetail, + "tristate": true, + "default": true, + }, + "assembly": { + "label": L10().filterAssembly, + "help_text": L10().filterAssemblyDetail, + }, + "component": { + "label": L10().filterComponent, + "help_text": L10().filterComponentDetail, + }, + "is_template": { + "label": L10().filterTemplate, + "help_text": L10().filterTemplateDetail, + }, + "trackable": { + "label": L10().filterTrackable, + "help_text": L10().filterTrackableDetail, + }, + "virtual": { + "label": L10().filterVirtual, + "help_text": L10().filterVirtualDetail, + }, + "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, + ); + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreePart part = model as InvenTreePart; + + return ListTile( + title: Text(part.fullname), + subtitle: Text(part.description), + trailing: LargeText(part.stockString()), + leading: InvenTreeAPI().getThumbnail(part.thumbnail), + onTap: () { + part.goToDetailPage(context); + }, + ); + } +} diff --git a/lib/widget/part/part_pricing.dart b/lib/widget/part/part_pricing.dart new file mode 100644 index 0000000..342d1c1 --- /dev/null +++ b/lib/widget/part/part_pricing.dart @@ -0,0 +1,195 @@ +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/part_suppliers.dart b/lib/widget/part/part_suppliers.dart similarity index 74% rename from lib/widget/part_suppliers.dart rename to lib/widget/part/part_suppliers.dart index 9b1a278..0fa79ae 100644 --- a/lib/widget/part_suppliers.dart +++ b/lib/widget/part/part_suppliers.dart @@ -7,23 +7,18 @@ 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/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; @@ -38,36 +33,26 @@ 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 []; } Widget _supplierPartTile(BuildContext context, int index) { - 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 { var company = await InvenTreeCompany().get(_part.supplierId); if (company != null && company is InvenTreeCompany) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyDetailWidget(company) - ) - ); + company.goToDetailPage(context); } }, ); @@ -78,10 +63,9 @@ 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, ); } - -} \ No newline at end of file +} diff --git a/lib/widget/part_attachments_widget.dart b/lib/widget/part_attachments_widget.dart deleted file mode 100644 index 5fada01..0000000 --- a/lib/widget/part_attachments_widget.dart +++ /dev/null @@ -1,139 +0,0 @@ -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/widget/fields.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/widget/snacks.dart"; - -import "package:inventree/api.dart"; -import "package:inventree/l10.dart"; - -class PartAttachmentsWidget extends StatefulWidget { - - const PartAttachmentsWidget(this.part, {Key? key}) : super(key: key); - - final InvenTreePart part; - - @override - _PartAttachmentDisplayState createState() => _PartAttachmentDisplayState(part); -} - - -class _PartAttachmentDisplayState extends RefreshableState { - - _PartAttachmentDisplayState(this.part); - - final InvenTreePart part; - - List attachments = []; - - @override - String getAppBarTitle(BuildContext context) => L10().attachments; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - if (InvenTreeAPI().checkPermission("part", "change")) { - - // File upload - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), - onPressed: () async { - FilePickerDialog.pickFile( - onPicked: (File file) { - upload(file); - } - ); - }, - ) - ); - } - - return actions; - } - - Future upload(File file) async { - final bool result = await InvenTreePartAttachment().uploadAttachment( - file, - fields: { - "part": "${part.pk}" - } - ); - - if (result) { - showSnackIcon(L10().uploadSuccess, success: true); - } else { - showSnackIcon(L10().uploadFailed, success: false); - } - - refresh(context); - } - - @override - Future request(BuildContext context) async { - - await InvenTreePartAttachment().list( - filters: { - "part": "${part.pk}" - } - ).then((var results) { - - attachments.clear(); - - for (var result in results) { - if (result is InvenTreePartAttachment) { - attachments.add(result); - } - } - }); - - } - - @override - Widget getBody(BuildContext context) { - return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: attachmentTiles(context) - ).toList(), - ) - ); - } - - - List attachmentTiles(BuildContext context) { - - List tiles = []; - - 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 (tiles.isEmpty) { - tiles.add(ListTile( - title: Text(L10().attachmentNone), - subtitle: Text( - L10().attachmentNonePartDetail, - style: TextStyle(fontStyle: FontStyle.italic), - ), - )); - } - - return tiles; - - } - -} \ No newline at end of file diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart deleted file mode 100644 index b66f91a..0000000 --- a/lib/widget/part_detail.dart +++ /dev/null @@ -1,588 +0,0 @@ -import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.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/widget/part_attachments_widget.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"; -import "package:inventree/widget/stock_detail.dart"; -import "package:inventree/widget/stock_list.dart"; - - -class PartDetailWidget extends StatefulWidget { - - const PartDetailWidget(this.part, {Key? key}) : super(key: key); - - final InvenTreePart part; - - @override - _PartDisplayState createState() => _PartDisplayState(part); - -} - - -class _PartDisplayState extends RefreshableState { - - _PartDisplayState(this.part); - - InvenTreePart part; - - InvenTreePart? parentPart; - - @override - String getAppBarTitle(BuildContext context) => L10().partDetails; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - if (InvenTreeAPI().checkPermission("part", "view")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: _openInvenTreePage, - ), - ); - } - - if (InvenTreeAPI().checkPermission("part", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { - _editPartDialog(context); - }, - ) - ); - } - - return actions; - } - - Future _openInvenTreePage() async { - part.goToInvenTreePage(); - } - - @override - Future onBuild(BuildContext context) async { - refresh(context); - - setState(() { - - }); - } - - @override - Future request(BuildContext context) async { - - final bool result = await part.reload(); - - if (!result || part.pk == -1) { - // Part could not be loaded, for some reason - Navigator.of(context).pop(); - } - - // 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 { - parentPart = null; - } - } - - await part.getTestTemplates(); - } - - Future _toggleStar() async { - - if (InvenTreeAPI().checkPermission("part", "view")) { - await part.update(values: {"starred": "${!part.starred}"}); - refresh(context); - } - } - - 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: IconButton( - icon: FaIcon(part.starred ? FontAwesomeIcons.solidStar : FontAwesomeIcons.star, - color: part.starred ? COLOR_STAR : null, - ), - onPressed: _toggleStar, - ), - leading: GestureDetector( - child: InvenTreeAPI().getImage(part.thumbnail), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartImageWidget(part) - ) - ).then((value) { - refresh(context); - }); - }), - ), - ); - } - - /* - * Build a list of tiles to display under the part description - */ - List partTiles() { - - List tiles = []; - - // Image / name / description - tiles.add( - headerTile() - ); - - if (loading) { - tiles.add(progressIndicator()); - return tiles; - } - - if (!part.isActive) { - tiles.add( - ListTile( - title: Text( - L10().inactive, - style: TextStyle( - color: COLOR_DANGER - ) - ), - subtitle: Text( - L10().inactiveDetail, - style: TextStyle( - color: COLOR_DANGER - ) - ), - leading: FaIcon( - FontAwesomeIcons.exclamationCircle, - color: COLOR_DANGER - ), - ) - ); - } - - if (parentPart != null) { - tiles.add( - ListTile( - title: Text(L10().templatePart), - subtitle: Text(parentPart!.fullname), - leading: InvenTreeAPI().getImage( - parentPart!.thumbnail, - width: 32, - height: 32, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartDetailWidget(parentPart!)) - ); - } - ) - ); - } - - // Category information - if (part.categoryName.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().partCategory), - subtitle: Text("${part.categoryName}"), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - onTap: () { - if (part.categoryId > 0) { - InvenTreePartCategory().get(part.categoryId).then((var cat) { - - if (cat is InvenTreePartCategory) { - Navigator.push(context, MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(cat))); - } - }); - } - }, - ) - ); - } else { - tiles.add( - ListTile( - title: Text(L10().partCategory), - subtitle: Text(L10().partCategoryTopLevel), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) => CategoryDisplayWidget(null))); - }, - ) - ); - } - - tiles.add( - ListTile( - title: Text(L10().availableStock), - subtitle: Text(L10().stockDetails), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: Text(part.stockString()), - onTap: () { - setState(() { - tabIndex = 1; - }); - }, - ), - ); - - // Tiles for "purchaseable" parts - if (part.isPurchaseable) { - - // On order - tiles.add( - ListTile( - title: Text(L10().onOrder), - subtitle: Text(L10().onOrderDetails), - leading: FaIcon(FontAwesomeIcons.shoppingCart), - trailing: Text("${part.onOrderString}"), - onTap: () { - // TODO - Order views - }, - ) - ); - - } - - // Tiles for an "assembly" part - if (part.isAssembly) { - - if (part.bomItemCount > 0) { - tiles.add( - ListTile( - title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.thList), - trailing: Text("${part.bomItemCount}"), - onTap: () { - // TODO - } - ) - ); - } - - if (part.building > 0) { - tiles.add( - ListTile( - title: Text(L10().building), - leading: FaIcon(FontAwesomeIcons.tools), - trailing: Text("${simpleNumberString(part.building)}"), - onTap: () { - // TODO - }, - ) - ); - } - } - - // Keywords? - if (part.keywords.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${part.keywords}"), - leading: FaIcon(FontAwesomeIcons.key), - ) - ); - } - - // External link? - if (part.link.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${part.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), - onTap: () { - part.openLink(); - }, - ) - ); - } - - // Tiles for "component" part - if (part.isComponent && part.usedInCount > 0) { - - tiles.add( - ListTile( - title: Text(L10().usedIn), - subtitle: Text(L10().usedInDetails), - leading: FaIcon(FontAwesomeIcons.sitemap), - trailing: Text("${part.usedInCount}"), - onTap: () { - // TODO - }, - ) - ); - } - - if (part.isPurchaseable) { - tiles.add( - ListTile( - title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.industry), - trailing: Text("${part.supplierCount}"), - /* TODO: - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartSupplierWidget(part)) - ); - }, - */ - ) - ); - } - - - // TODO - Add request tests? - /* - if (part.isTrackable) { - tiles.add(ListTile( - title: Text(L10().testsRequired), - leading: FaIcon(FontAwesomeIcons.tasks), - trailing: Text("${part.testTemplateCount}"), - onTap: null, - ) - ); - } - */ - - // Notes field - tiles.add( - ListTile( - title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), - trailing: Text(""), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartNotesWidget(part)) - ); - }, - ) - ); - - tiles.add( - ListTile( - title: Text(L10().attachments), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), - trailing: Text(""), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PartAttachmentsWidget(part) - ) - ); - }, - ) - ); - - return tiles; - - } - - // Return tiles for each stock item - List stockTiles() { - List tiles = []; - - tiles.add(headerTile()); - - tiles.add( - ListTile( - title: Text( - L10().stockItems, - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: part.stockItems.isEmpty ? Text(L10().stockItemsNotAvailable) : null, - trailing: part.stockItems.isNotEmpty ? Text("${part.stockItems.length}") : null, - ) - ); - - return tiles; - } - - Future _newStockItem(BuildContext context) async { - - var fields = InvenTreeStockItem().formFields(); - - fields["part"]["hidden"] = true; - - int? default_location = part.defaultLocation; - - if (default_location != null) { - fields["location"]["value"] = default_location; - } - - InvenTreeStockItem().createForm( - context, - L10().stockItemCreate, - fields: fields, - data: { - "part": "${part.pk}", - }, - onSuccess: (result) async { - - Map data = result as Map; - - if (data.containsKey("pk")) { - var item = InvenTreeStockItem.fromJson(data); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockDetailWidget(item) - ) - ); - } - } - ); - - } - - List actionTiles(BuildContext context) { - List tiles = []; - - tiles.add(headerTile()); - - tiles.add( - ListTile( - title: Text(L10().stockItemCreate), - leading: FaIcon(FontAwesomeIcons.box), - onTap: () { - _newStockItem(context); - }, - ) - ); - - // TODO - Add this action back in once implemented - /* - tiles.add( - ListTile( - title: Text(L10().barcodeScanItem), - leading: FaIcon(FontAwesomeIcons.box), - trailing: Icon(Icons.qr_code), - onTap: () { - // TODO - }, - ), - ); - */ - - /* - // TODO: Implement part deletion - if (!part.isActive && InvenTreeAPI().checkPermission("part", "delete")) { - tiles.add( - ListTile( - title: Text(L10().deletePart), - subtitle: Text(L10().deletePartDetail), - leading: FaIcon(FontAwesomeIcons.trashAlt, color: COLOR_DANGER), - onTap: () { - // TODO - }, - ) - ); - } - */ - - 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}"} - ); - 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.infoCircle), - label: L10().details, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), - label: L10().stock - ), - // TODO - Add part actions - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.wrench), - label: L10().actions, - ), - ] - ); - } - - @override - Widget getBody(BuildContext context) { - return getSelectedWidget(tabIndex); - } -} diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart deleted file mode 100644 index a582dce..0000000 --- a/lib/widget/part_image_widget.dart +++ /dev/null @@ -1,78 +0,0 @@ -import "dart:io"; - -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/widget/fields.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); - - final InvenTreePart part; - - @override - _PartImageState createState() => _PartImageState(part); - -} - - -class _PartImageState extends RefreshableState { - - _PartImageState(this.part); - - final InvenTreePart part; - - @override - Future request(BuildContext context) async { - await part.reload(); - } - - @override - String getAppBarTitle(BuildContext context) => part.fullname; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - if (InvenTreeAPI().checkPermission("part", "change")) { - - // File upload - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.fileUpload), - onPressed: () async { - - FilePickerDialog.pickFile( - onPicked: (File file) async { - final result = await part.uploadImage(file); - - if (!result) { - showSnackIcon(L10().uploadFailed, success: false); - } - - refresh(context); - } - ); - - }, - ) - ); - } - - return actions; - } - - @override - Widget getBody(BuildContext context) { - return InvenTreeAPI().getImage(part.image); - } - -} \ No newline at end of file diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart deleted file mode 100644 index ca4d158..0000000 --- a/lib/widget/part_list.dart +++ /dev/null @@ -1,101 +0,0 @@ -import "package:flutter/material.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"; -import "package:inventree/api.dart"; -import "package:inventree/app_settings.dart"; -import "package:inventree/l10.dart"; - - -class PartList extends StatefulWidget { - - const PartList(this.filters); - - final Map filters; - - @override - _PartListState createState() => _PartListState(filters); -} - - -class _PartListState extends RefreshableState { - - _PartListState(this.filters); - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => L10().parts; - - @override - Widget getBody(BuildContext context) { - return PaginatedPartList(filters); - } - -} - - -class PaginatedPartList extends StatefulWidget { - - const PaginatedPartList(this.filters, {this.onTotalChanged}); - - final Map filters; - - final Function(int)? onTotalChanged; - - @override - _PaginatedPartListState createState() => _PaginatedPartListState(filters, onTotalChanged); -} - - -class _PaginatedPartListState extends PaginatedSearchState { - - _PaginatedPartListState(Map filters, this.onTotalChanged) : super(filters); - - Function(int)? onTotalChanged; - - @override - Future requestPage(int limit, int offset, Map params) async { - - final bool cascade = await InvenTreeSettingsManager().getBool(INV_PART_SUBCATEGORY, true); - - params["cascade"] = "${cascade}"; - - final page = await InvenTreePart().listPaginated(limit, offset, filters: params); - - return page; - } - - void _openPart(BuildContext context, int pk) { - // Attempt to load the part information - InvenTreePart().get(pk).then((var part) { - if (part is InvenTreePart) { - - Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); - } - }); - } - - @override - Widget buildItem(BuildContext context, InvenTreeModel model) { - - InvenTreePart part = model as InvenTreePart; - - return ListTile( - title: Text(part.fullname), - subtitle: Text(part.description), - trailing: Text(part.stockString()), - leading: InvenTreeAPI().getImage( - part.thumbnail, - width: 40, - height: 40, - ), - onTap: () { - _openPart(context, part.pk); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/part_notes.dart b/lib/widget/part_notes.dart deleted file mode 100644 index 6ceb23e..0000000 --- a/lib/widget/part_notes.dart +++ /dev/null @@ -1,74 +0,0 @@ -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/widget/refreshable_state.dart"; -import "package:flutter_markdown/flutter_markdown.dart"; -import "package:inventree/l10.dart"; - - -class PartNotesWidget extends StatefulWidget { - - const PartNotesWidget(this.part, {Key? key}) : super(key: key); - - final InvenTreePart part; - - @override - _PartNotesState createState() => _PartNotesState(part); -} - - -class _PartNotesState extends RefreshableState { - - _PartNotesState(this.part); - - final InvenTreePart part; - - @override - Future request(BuildContext context) async { - await part.reload(); - } - - @override - String getAppBarTitle(BuildContext context) => L10().partNotes; - - @override - List getAppBarActions(BuildContext context) { - - List actions = []; - - if (InvenTreeAPI().checkPermission("part", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { - part.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: part.notes, - ); - } - -} \ No newline at end of file diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart index 92ef69c..a95ace9 100644 --- a/lib/widget/progress.dart +++ b/lib/widget/progress.dart @@ -1,13 +1,59 @@ - +import "dart:io"; import "package:flutter/material.dart"; +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}) { + 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 */ 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; + } + + BuildContext? context = OneContext.hasContext ? OneContext().context : null; + + if (context == null) { + return; + } + + Loader.show( + context, + themeData: Theme.of( + context, + ).copyWith(colorScheme: ColorScheme.fromSwatch()), ); -} \ No newline at end of file +} + +void hideLoadingOverlay() { + if (Loader.isShown) { + Loader.hide(); + } +} diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart deleted file mode 100644 index 2a657ec..0000000 --- a/lib/widget/purchase_order_detail.dart +++ /dev/null @@ -1,387 +0,0 @@ -import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:one_context/one_context.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/inventree/company.dart"; -import "package:inventree/inventree/purchase_order.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"; - - -class PurchaseOrderDetailWidget extends StatefulWidget { - - const PurchaseOrderDetailWidget(this.order, {Key? key}): super(key: key); - - final InvenTreePurchaseOrder order; - - @override - _PurchaseOrderDetailState createState() => _PurchaseOrderDetailState(order); -} - - -class _PurchaseOrderDetailState extends RefreshableState { - - _PurchaseOrderDetailState(this.order); - - final InvenTreePurchaseOrder order; - - List lines = []; - - int completedLines = 0; - - @override - String getAppBarTitle(BuildContext context) => L10().purchaseOrder; - - @override - List getAppBarActions(BuildContext context) { - List actions = []; - - if (InvenTreeAPI().checkPermission("purchase_order", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { - editOrder(context); - } - ) - ); - } - - return actions; - } - - @override - Future request(BuildContext context) async { - await order.reload(); - - lines = await order.getLineItems(); - - completedLines = 0; - - for (var line in lines) { - if (line.isComplete) { - completedLines += 1; - } - } - - } - - Future editOrder(BuildContext context) async { - - order.editForm( - context, - L10().purchaseOrderEdit, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().purchaseOrderUpdated, success: true); - } - ); - } - - Widget headerTile(BuildContext context) { - - InvenTreeCompany? supplier = order.supplier; - - return Card( - child: ListTile( - title: Text(order.reference), - subtitle: Text(order.description), - leading: supplier == null ? null : InvenTreeAPI().getImage(supplier.thumbnail, width: 40, height: 40), - ) - ); - - } - - List orderTiles(BuildContext context) { - - List tiles = []; - - InvenTreeCompany? supplier = order.supplier; - - tiles.add(headerTile(context)); - - if (supplier != null) { - tiles.add(ListTile( - title: Text(L10().supplier), - subtitle: Text(supplier.name), - leading: FaIcon(FontAwesomeIcons.building, color: COLOR_CLICK), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyDetailWidget(supplier) - ) - ); - }, - )); - } - - if (order.supplierReference.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().supplierReference), - subtitle: Text(order.supplierReference), - leading: FaIcon(FontAwesomeIcons.hashtag), - )); - } - - tiles.add(ListTile( - title: Text(L10().lineItems), - leading: FaIcon(FontAwesomeIcons.clipboardList, color: COLOR_CLICK), - trailing: Text("${order.lineItemCount}"), - onTap: () { - setState(() { - // Switch to the "line items" tab - tabIndex = 1; - }); - }, - )); - - tiles.add(ListTile( - title: Text(L10().received), - leading: FaIcon(FontAwesomeIcons.clipboardCheck, color: COLOR_CLICK), - trailing: Text("${completedLines}"), - onTap: () { - setState(() { - // Switch to the "received items" tab - tabIndex = 2; - }); - }, - )); - - if (order.issueDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().issueDate), - subtitle: Text(order.issueDate), - leading: FaIcon(FontAwesomeIcons.calendarAlt), - )); - } - - if (order.targetDate.isNotEmpty) { - tiles.add(ListTile( - title: Text(L10().targetDate), - subtitle: Text(order.targetDate), - leading: FaIcon(FontAwesomeIcons.calendarAlt), - )); - } - - return tiles; - - } - - void receiveLine(BuildContext context, InvenTreePOLineItem lineItem) { - - Map 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.signInAlt, - onSuccess: (data) async { - showSnackIcon(L10().receivedItem, success: true); - refresh(context); - } - ); - } - - 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().supportPoReceive()) { - children.add( - SimpleDialogOption( - onPressed: () { - // Hide the dialog option - OneContext().popDialog(); - - receiveLine(context, lineItem); - }, - child: ListTile( - title: Text(L10().receiveItem), - leading: FaIcon(FontAwesomeIcons.signInAlt), - ) - ) - ); - } - - // No valid actions available - if (children.isEmpty) { - return; - } - - children.insert(0, Divider()); - - showDialog( - context: context, - builder: (BuildContext context) { - return SimpleDialog( - title: Text(L10().lineItem), - children: children, - ); - } - ); - - } - - List lineTiles(BuildContext context) { - - List tiles = []; - - tiles.add(headerTile(context)); - - 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: () { - // TODO: ? - }, - onLongPress: () { - lineItemMenu(context, line); - }, - ) - ); - } - } - - return tiles; - } - - @override - Widget getBody(BuildContext context) { - - return Center( - child: getSelectedWidget(context, tabIndex), - ); - } - - 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); - - default: - return ListView(); - } - } - - @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.info), - label: L10().details - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.thList), - label: L10().lineItems, - ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), - label: L10().stockItems - ) - ], - ); - } - -} \ No newline at end of file diff --git a/lib/widget/purchase_order_list.dart b/lib/widget/purchase_order_list.dart deleted file mode 100644 index 43f24ea..0000000 --- a/lib/widget/purchase_order_list.dart +++ /dev/null @@ -1,95 +0,0 @@ -import "package:flutter/material.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/refreshable_state.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/api.dart"; -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); - - final Map filters; - - @override - _PurchaseOrderListWidgetState createState() => _PurchaseOrderListWidgetState(filters); -} - - -class _PurchaseOrderListWidgetState extends RefreshableState { - - _PurchaseOrderListWidgetState(this.filters); - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => L10().purchaseOrders; - - @override - Widget getBody(BuildContext context) { - return PaginatedPurchaseOrderList(filters); - } -} - - -class PaginatedPurchaseOrderList extends StatefulWidget { - - const PaginatedPurchaseOrderList(this.filters); - - final Map filters; - - @override - _PaginatedPurchaseOrderListState createState() => _PaginatedPurchaseOrderListState(filters); - -} - - -class _PaginatedPurchaseOrderListState extends PaginatedSearchState { - - _PaginatedPurchaseOrderListState(Map filters) : super(filters); - - @override - Future requestPage(int limit, int offset, Map params) async { - - params["outstanding"] = "true"; - - 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().getImage( - supplier.thumbnail, - width: 40, - height: 40, - ), - trailing: Text("${order.lineItemCount}"), - onTap: () async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PurchaseOrderDetailWidget(order) - ) - ); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index fe318ca..d9c5ad5 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -1,40 +1,217 @@ +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"; +import "package:inventree/barcode/barcode.dart"; + import "package:inventree/widget/back.dart"; import "package:inventree/widget/drawer.dart"; -import "package:flutter/material.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 + */ + List appBarActions(BuildContext context) => []; -abstract class RefreshableState extends State { + // Return a title for the appBar (placeholder) + String getAppBarTitle() { + return "--- app bar ---"; + } - final refreshableKey = GlobalKey(); + // Function to construct a drawer (override if needed) + Widget getDrawer(BuildContext context) { + return InvenTreeDrawer(context); + } + + // Function to construct a set of tabs for this widget (override if needed) + List getTabs(BuildContext context) => []; + + // 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 implementation is to return a ListView + // Override getTiles to replace the internal context + return ListView( + physics: AlwaysScrollableScrollPhysics(), + children: [Divider(), ...getTiles(context)], + ); + } + + /* + * Construct the top AppBar for this view + */ + AppBar? buildAppBar(BuildContext context, GlobalKey key) { + List tabs = getTabIcons(context); + + return AppBar( + centerTitle: false, + bottom: tabs.isEmpty ? null : TabBar(tabs: tabs), + title: Text(getAppBarTitle()), + backgroundColor: COLOR_APP_BAR, + 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; + + List icons = [ + IconButton( + icon: Icon(Icons.menu, color: COLOR_ACTION), + iconSize: iconSize, + onPressed: () { + if (key.currentState != null) { + key.currentState!.openDrawer(); + } + }, + ), + IconButton( + icon: Icon(TablerIcons.search, color: COLOR_ACTION), + iconSize: iconSize, + onPressed: () { + if (InvenTreeAPI().checkConnection()) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SearchWidget(true)), + ); + } + }, + ), + IconButton( + icon: Icon(TablerIcons.barcode, color: COLOR_ACTION), + iconSize: iconSize, + onPressed: () { + if (InvenTreeAPI().checkConnection()) { + scanBarcode(context); + } + }, + ), + ]; + + return BottomAppBar( + 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( + 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) => []; +} + +/* + * 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 scaffoldKey = GlobalKey(); + final refreshKey = GlobalKey(); // 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; bool get loaded => !loading; - // Update current tab selection - void onTabSelectionChanged(int index) { - setState(() { - tabIndex = index; - }); - } - - List getAppBarActions(BuildContext context) { - return []; - } - - String getAppBarTitle(BuildContext context) { return "App Bar Title"; } + // Helper function to return API instance + InvenTreeAPI get api => InvenTreeAPI(); @override void initState() { super.initState(); - WidgetsBinding.instance?.addPostFrameCallback((_) => onBuild(_context!)); + WidgetsBinding.instance.addPostFrameCallback((_) => onBuild(_context!)); } // Function called after the widget is first build @@ -47,7 +224,12 @@ abstract class RefreshableState extends State { return; } + // Refresh the widget - handler for custom request() method Future refresh(BuildContext context) async { + // Escape if the widget is no longer loaded + if (!mounted) { + return; + } setState(() { loading = true; @@ -55,57 +237,52 @@ abstract class RefreshableState extends State { await request(context); + // Escape if the widget is no longer loaded + if (!mounted) { + return; + } + setState(() { loading = false; }); } - // 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; - } - @override Widget build(BuildContext context) { - // Save the context for future use _context = context; - return Scaffold( - key: refreshableKey, - appBar: AppBar( - title: Text(getAppBarTitle(context)), - actions: getAppBarActions(context), - leading: backButton(context, refreshableKey), - ), + List tabs = getTabIcons(context); + + Widget body = tabs.isEmpty + ? getBody(context) + : TabBarView(children: getTabs(context)); + + Scaffold view = Scaffold( + key: scaffoldKey, + appBar: buildAppBar(context, scaffoldKey), drawer: getDrawer(context), - floatingActionButton: getFab(context), - body: Builder( - builder: (BuildContext context) { - return RefreshIndicator( - onRefresh: () async { - refresh(context); - }, - child: getBody(context) - ); - } + floatingActionButton: buildSpeedDial(context), + floatingActionButtonLocation: FloatingActionButtonLocation.miniEndDocked, + body: RefreshIndicator( + key: refreshKey, + notificationPredicate: (ScrollNotification notification) { + return true; + }, + + onRefresh: () async { + refresh(context); + }, + child: body, ), - bottomNavigationBar: getBottomNavBar(context), + bottomNavigationBar: buildBottomAppBar(context, scaffoldKey), ); + + // 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 77258d4..40c5a33 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -1,56 +1,128 @@ import "dart:async"; - +import "package:async/async.dart"; import "package:flutter/material.dart"; +import "package:flutter_tabler_icons/flutter_tabler_icons.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"; -import "package:inventree/widget/refreshable_state.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/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/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"; + +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/stock_list.dart"; +import "package:inventree/widget/part/category_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 class SearchWidget extends StatefulWidget { + const SearchWidget(this.hasAppbar); + + final bool hasAppbar; @override - _SearchDisplayState createState() => _SearchDisplayState(); - + _SearchDisplayState createState() => _SearchDisplayState(hasAppbar); } class _SearchDisplayState extends RefreshableState { + _SearchDisplayState(this.hasAppBar) : super(); + + final _formKey = GlobalKey(); + + final bool hasAppBar; + + CancelableOperation? _search_query; @override - String getAppBarTitle(BuildContext context) => L10().search; + void dispose() { + super.dispose(); + } + + @override + String getAppBarTitle() => L10().search; + + @override + AppBar? buildAppBar(BuildContext context, GlobalKey key) { + if (hasAppBar) { + return super.buildAppBar(context, key); + } else { + return null; + } + } final TextEditingController searchController = TextEditingController(); 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 nPendingSearches > 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 nPurchaseOrderResults = 0; + int nSalesOrderResults = 0; + int nSupplierPartResults = 0; + int nManufacturerPartResults = 0; + int nCompanyResults = 0; + int nCustomerResults = 0; + int nManufacturerResults = 0; int nSupplierResults = 0; - int nPurchaseOrderResults = 0; + void resetSearchResults() { + if (mounted) { + setState(() { + nPendingSearches = 0; + + nPartResults = 0; + nCategoryResults = 0; + nStockResults = 0; + nLocationResults = 0; + nPurchaseOrderResults = 0; + nSalesOrderResults = 0; + nSupplierPartResults = 0; + nManufacturerPartResults = 0; + nCompanyResults = 0; + nCustomerResults = 0; + nManufacturerResults = 0; + nSupplierResults = 0; + }); + } + } // 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(); } @@ -58,117 +130,284 @@ class _SearchDisplayState extends RefreshableState { if (immediate) { search(text); } else { - debounceTimer = Timer(Duration(milliseconds: 250), () { + debounceTimer = Timer(Duration(milliseconds: 300), () { search(text); }); } - } + /* + * 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; + } + + // Actually perform the search query + Future _perform_search(Map body) async { + InvenTreeAPI().post("search/", body: body, expectedStatusCode: 200).then(( + APIResponse response, + ) { + String searchTerm = (body["search"] ?? "").toString(); + + // Only update if the results correspond to the current search term + if (searchTerm == searchController.text && mounted) { + decrementPendingSearches(); + + 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, + ); + 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(); + } + } + }); + } + + /* + * Callback when the search input is changed + */ Future search(String term) async { + var api = InvenTreeAPI(); - if (term.isEmpty) { - setState(() { - // Do not search on an empty string - nPartResults = 0; - nCategoryResults = 0; - nStockResults = 0; - nLocationResults = 0; - nSupplierResults = 0; - nPurchaseOrderResults = 0; - }); - + if (!mounted) { return; } - // Search parts - InvenTreePart().count( - searchQuery: term - ).then((int n) { - setState(() { - nPartResults = n; - }); - }); + resetSearchResults(); - // Search part categories - InvenTreePartCategory().count( - searchQuery: term, - ).then((int n) { - setState(() { - nCategoryResults = n; - }); - }); - - // Search stock items - InvenTreeStockItem().count( - searchQuery: term - ).then((int n) { - setState(() { - nStockResults = n; - }); - }); - - // Search stock locations - InvenTreeStockLocation().count( - searchQuery: term - ).then((int n) { - setState(() { - nLocationResults = n; - }); - }); - - // Search suppliers - InvenTreeCompany().count( - searchQuery: term, - filters: { - "is_supplier": "true", - }, - ).then((int n) { - setState(() { - nSupplierResults = n; - }); - }); - - // Search purchase orders - InvenTreePurchaseOrder().count( - searchQuery: term, - filters: { - "outstanding": "true" + // Cancel the previous search query (if in progress) + if (_search_query != null) { + if (!_search_query!.isCanceled) { + _search_query!.cancel(); } - ).then((int n) { - setState(() { - nPurchaseOrderResults = n; - }); - }); + } + _search_query = null; + + 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, + + InvenTreePart.MODEL_TYPE: {}, + InvenTreePartCategory.MODEL_TYPE: {}, + InvenTreeStockItem.MODEL_TYPE: {}, + InvenTreeStockLocation.MODEL_TYPE: {}, + InvenTreePurchaseOrder.MODEL_TYPE: {}, + InvenTreeSalesOrder.MODEL_TYPE: {}, + InvenTreeSupplierPart.MODEL_TYPE: {}, + InvenTreeManufacturerPart.MODEL_TYPE: {}, + }; + + if (api.supportsSplitCompanySearch) { + body["supplier"] = {}; + body["manufacturer"] = {}; + body["customer"] = {}; + } else { + // All "company" results are returned in a single query + body[InvenTreeCompany.MODEL_TYPE] = {}; + } + + if (body.isNotEmpty) { + if (mounted) { + setState(() { + nPendingSearches = 1; + }); + + _search_query = CancelableOperation.fromFuture(_perform_search(body)); + } + } + } else { + legacySearch(term); + } } - List _tiles(BuildContext context) { + /* + * Perform "legacy" search (without consolidated search API endpoint + */ + Future legacySearch(String term) async { + // Search parts + if (InvenTreePart().canView) { + nPendingSearches++; + InvenTreePart().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + if (mounted) { + decrementPendingSearches(); + setState(() { + nPartResults = n; + }); + } + } + }); + } + // Search part categories + if (InvenTreePartCategory().canView) { + nPendingSearches++; + InvenTreePartCategory().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + if (mounted) { + decrementPendingSearches(); + setState(() { + nCategoryResults = n; + }); + } + } + }); + } + + // Search stock items + if (InvenTreeStockItem().canView) { + nPendingSearches++; + InvenTreeStockItem().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + if (mounted) { + decrementPendingSearches(); + setState(() { + nStockResults = n; + }); + } + } + }); + } + + // Search stock locations + if (InvenTreeStockLocation().canView) { + nPendingSearches++; + InvenTreeStockLocation().count(searchQuery: term).then((int n) { + if (term == searchController.text) { + if (mounted) { + decrementPendingSearches(); + setState(() { + nLocationResults = n; + }); + } + } + }); + } + + // 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; + }); + } + } + }); + } + } + + @override + List getTiles(BuildContext context) { List tiles = []; // Search input tiles.add( - InputDecorator( - decoration: InputDecoration( + ListTile( + title: TextFormField( + decoration: InputDecoration(hintText: L10().queryEmpty), + key: _formKey, + readOnly: false, + autofocus: true, + autocorrect: false, + controller: searchController, + onChanged: (String text) { + onSearchTextChanged(text); + }, + onFieldSubmitted: (String text) {}, ), - child: ListTile( - title: TextField( - readOnly: false, - controller: searchController, - onChanged: (String text) { - onSearchTextChanged(text); - }, + trailing: GestureDetector( + child: Icon( + searchController.text.isEmpty + ? TablerIcons.search + : TablerIcons.backspace, + color: searchController.text.isEmpty ? COLOR_ACTION : COLOR_DANGER, ), - leading: IconButton( - icon: FaIcon(FontAwesomeIcons.backspace, color: Colors.red), - onPressed: () { - searchController.clear(); - onSearchTextChanged("", immediate: true); - }, - ), - ) - ) + onTap: () { + searchController.clear(); + onSearchTextChanged("", immediate: true); + }, + ), + ), ); String query = searchController.text; @@ -180,21 +419,17 @@ 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( - context, - MaterialPageRoute( - builder: (context) => PartList( - { - "original_search": query - } - ) - ) + context, + MaterialPageRoute( + builder: (context) => PartList({"original_search": query}), + ), ); - } - ) + }, + ), ); } @@ -203,21 +438,18 @@ 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( context, MaterialPageRoute( - builder: (context) => PartCategoryList( - { - "original_search": query - } - ) - ) + builder: (context) => + PartCategoryList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -226,21 +458,17 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockItems), - leading: FaIcon(FontAwesomeIcons.boxes), + leading: Icon(TablerIcons.package), trailing: Text("${nStockResults}"), onTap: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => StockItemList( - { - "original_search": query, - } - ) - ) + builder: (context) => StockItemList({"original_search": query}), + ), ); }, - ) + ), ); } @@ -249,46 +477,18 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockLocations), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + leading: Icon(TablerIcons.location), trailing: Text("${nLocationResults}"), onTap: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => StockLocationList( - { - "original_search": query - } - ) - ) + builder: (context) => + StockLocationList({"original_search": query}), + ), ); }, - ) - ); - } - - // Suppliers - if (nSupplierResults > 0) { - results.add( - ListTile( - title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.building), - trailing: Text("${nSupplierResults}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyListWidget( - L10().suppliers, - { - "is_supplier": "true", - "original_search": query - } - ) - ) - ); - }, - ) + ), ); } @@ -297,30 +497,168 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: Icon(TablerIcons.shopping_cart), trailing: Text("${nPurchaseOrderResults}"), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => PurchaseOrderListWidget( - filters: { - "original_search": query - } - ) - ) + filters: {"original_search": query}, + ), + ), ); }, - ) + ), ); } - if (results.isEmpty) { + // 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, + }), + ), + ); + }, + ), + ); + } + + // Customer results + if (nCustomerResults > 0) { + results.add( + ListTile( + title: Text(L10().customers), + leading: Icon(TablerIcons.building_store), + trailing: Text("${nCustomerResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyListWidget(L10().customers, { + "original_search": query, + "is_customer": "true", + }), + ), + ); + }, + ), + ); + } + + // Manufacturer results + if (nManufacturerResults > 0) { + results.add( + ListTile( + title: Text(L10().manufacturers), + leading: Icon(TablerIcons.building_factory_2), + trailing: Text("${nManufacturerResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyListWidget(L10().manufacturers, { + "original_search": query, + "is_manufacturer": "true", + }), + ), + ); + }, + ), + ); + } + + // Supplier results + if (nSupplierResults > 0) { + results.add( + ListTile( + title: Text(L10().suppliers), + leading: Icon(TablerIcons.building_store), + trailing: Text("${nSupplierResults}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyListWidget(L10().suppliers, { + "original_search": query, + "is_supplier": "true", + }), + ), + ); + }, + ), + ); + } + + // 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( - title: Text(L10().queryNoResults), - leading: FaIcon(FontAwesomeIcons.search), - ) + title: Text(L10().searching), + leading: Icon(TablerIcons.search), + trailing: CircularProgressIndicator(), + ), + ); + } + + if (!isSearching() && results.isEmpty && searchController.text.isNotEmpty) { + tiles.add( + ListTile( + title: Text( + L10().queryNoResults, + style: TextStyle(fontStyle: FontStyle.italic), + ), + leading: Icon(TablerIcons.zoom_cancel), + ), ); } else { for (Widget result in results) { @@ -329,18 +667,5 @@ 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/snacks.dart b/lib/widget/snacks.dart index e6ee864..f00b1ec 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -1,20 +1,27 @@ - -/* - * 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:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:one_context/one_context.dart"; + +import "package:inventree/helpers.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, +}) { + debug("showSnackIcon: '${text}'"); -void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? success, String? actionText}) { + // Escape quickly if we do not have context + if (!hasContext()) { + // Debug message for unit testing + return; + } BuildContext? context = OneContext().context; @@ -30,44 +37,45 @@ 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 = TablerIcons.circle_check; } - } else if (success != null && success == false) { backgroundColor = Colors.deepOrange; if (icon == null && onAction == null) { - icon = FontAwesomeIcons.exclamationCircle; + icon = TablerIcons.exclamation_circle; } } String _action = actionText ?? L10().details; - SnackBarAction? action; - - if (onAction != null) { - action = SnackBarAction( - label: _action, - onPressed: onAction, - ); - } - - List childs = [ - Text(text), - Spacer(), - ]; + List childs = [Text(text), Spacer()]; if (icon != null) { - childs.add(FaIcon(icon)); + childs.add(Icon(icon)); } - OneContext().showSnackBar(builder: (context) => SnackBar( - content: Row( - children: childs + OneContext().showSnackBar( + builder: (context) => SnackBar( + content: GestureDetector( + child: Row(children: childs), + onTap: () { + ScaffoldMessenger.of(context!).hideCurrentSnackBar(); + }, + ), + backgroundColor: backgroundColor, + showCloseIcon: true, + 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: action - ) ); - -} \ No newline at end of file +} diff --git a/lib/widget/spinner.dart b/lib/widget/spinner.dart index 5e9d598..e06e25b 100644 --- a/lib/widget/spinner.dart +++ b/lib/widget/spinner.dart @@ -1,10 +1,7 @@ import "package:flutter/material.dart"; - -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; class Spinner extends StatefulWidget { - const Spinner({ this.color = COLOR_GRAY_LIGHT, Key? key, @@ -29,12 +26,8 @@ class _SpinnerState extends State with SingleTickerProviderStateMixin { _controller = AnimationController( vsync: this, duration: Duration(milliseconds: 2000), - ) - ..repeat(); - _child = FaIcon( - widget.icon, - color: widget.color - ); + )..repeat(); + _child = Icon(widget.icon, color: widget.color); super.initState(); } @@ -47,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/starred_parts.dart b/lib/widget/starred_parts.dart deleted file mode 100644 index e667a94..0000000 --- a/lib/widget/starred_parts.dart +++ /dev/null @@ -1,91 +0,0 @@ -import "package:inventree/inventree/part.dart"; -import "package:inventree/widget/part_detail.dart"; -import "package:inventree/widget/progress.dart"; -import "package:inventree/widget/refreshable_state.dart"; -import "package:flutter/material.dart"; - -import "package:inventree/l10.dart"; - -import "package:inventree/api.dart"; - - -class StarredPartWidget extends StatefulWidget { - - const StarredPartWidget({Key? key}) : super(key: key); - - @override - _StarredPartState createState() => _StarredPartState(); -} - - -class _StarredPartState extends RefreshableState { - - List starredParts = []; - - @override - String getAppBarTitle(BuildContext context) => L10().partsStarred; - - @override - Future request(BuildContext context) async { - - final parts = await InvenTreePart().list(filters: {"starred": "true"}); - - starredParts.clear(); - - for (int idx = 0; idx < parts.length; idx++) { - if (parts[idx] is InvenTreePart) { - starredParts.add(parts[idx] as InvenTreePart); - } - } - } - - Widget _partResult(BuildContext context, int index) { - final part = starredParts[index]; - - return ListTile( - title: Text(part.fullname), - subtitle: Text(part.description), - leading: InvenTreeAPI().getImage( - part.thumbnail, - width: 40, - height: 40 - ), - onTap: () { - InvenTreePart().get(part.pk).then((var prt) { - if (prt is InvenTreePart) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartDetailWidget(prt)) - ); - } - }); - } - ); - } - - @override - Widget getBody(BuildContext context) { - - if (loading) { - return progressIndicator(); - } - - if (starredParts.isEmpty) { - return ListView( - children: [ - ListTile( - title: Text(L10().partsNone), - subtitle: Text(L10().partsStarredNone) - ) - ], - ); - } - - return ListView.separated( - itemCount: starredParts.length, - itemBuilder: _partResult, - separatorBuilder: (_, __) => const Divider(height: 3), - physics: ClampingScrollPhysics(), - ); - } -} \ No newline at end of file diff --git a/lib/widget/stock/location_display.dart b/lib/widget/stock/location_display.dart new file mode 100644 index 0000000..f6f74db --- /dev/null +++ b/lib/widget/stock/location_display.dart @@ -0,0 +1,388 @@ +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/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"; +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"; +import "package:inventree/widget/refreshable_state.dart"; +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; + + final String title = L10().stockLocation; + + @override + _LocationDisplayState createState() => _LocationDisplayState(location); +} + +class _LocationDisplayState extends RefreshableState { + _LocationDisplayState(this.location); + + final InvenTreeStockLocation? location; + + bool allowLabelPrinting = false; + + @override + String getAppBarTitle() { + return L10().stockLocation; + } + + @override + List appBarActions(BuildContext context) { + List actions = []; + + // 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); + }, + ), + ); + } + + // Add "edit" button + if (location != null && InvenTreeStockLocation().canEdit) { + actions.add( + IconButton( + icon: Icon(TablerIcons.edit), + tooltip: L10().editLocation, + onPressed: () { + _editLocationDialog(context); + }, + ), + ); + } + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + if (location != null) { + // 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); + }); + }, + ), + ); + } + + 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( + 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, + ), + ); + } + + return actions; + } + + @override + List actionButtons(BuildContext context) { + List actions = []; + + // Create new location + if (InvenTreeStockLocation().canCreate) { + actions.add( + 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); + }, + ), + ); + } + + if (widget.location != null && + allowLabelPrinting && + api.supportsModernLabelPrinting) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.printer), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel(context, "stocklocation", widget.location!.pk); + }, + ), + ); + } + + return actions; + } + + /* + * Launch a dialog form to edit this stock location + */ + void _editLocationDialog(BuildContext context) { + final _loc = location; + + if (_loc == null) { + return; + } + + _loc.editForm( + context, + L10().editLocation, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().locationUpdated, success: true); + }, + ); + } + + @override + Future onBuild(BuildContext context) async { + refresh(context); + } + + @override + Future request(BuildContext context) async { + // Reload location information + if (location != null) { + final bool result = await location!.reload(); + + if (!result) { + Navigator.of(context).pop(); + } + } + + allowLabelPrinting = await InvenTreeSettingsManager().getBool( + INV_ENABLE_LABEL_PRINTING, + true, + ); + } + + Future _newLocation(BuildContext context) async { + int pk = location?.pk ?? -1; + + InvenTreeStockLocation().createForm( + 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); + } + }, + ); + } + + /* + * 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 + fields.remove("serial"); + + Map data = {}; + + if (location != null) { + data["location"] = location!.pk; + } + + InvenTreeStockItem().createForm( + 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); + } + }, + ); + } + + 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), + ), + ); + } else { + List children = [ + ListTile( + title: Text("${location!.name}"), + subtitle: Text("${location!.description}"), + 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), + trailing: LinkIcon(), + 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 (loc is InvenTreeStockLocation) { + loc.goToDetailPage(context); + } + } + }, + ), + ); + } + + return Card(child: Column(children: children)); + } + } + + @override + List getTabIcons(BuildContext context) { + return [Tab(text: L10().details), Tab(text: L10().stockItems)]; + } + + @override + List getTabs(BuildContext context) { + return [Column(children: detailTiles()), Column(children: stockTiles())]; + } + + // 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(filters, title: L10().sublocations), + flex: 10, + ), + ]; + + return tiles; + } + + // Construct the "stock" panel + List stockTiles() { + Map filters = { + "location": location?.pk.toString() ?? "null", + }; + + return [Expanded(child: PaginatedStockItemList(filters), flex: 10)]; + } +} diff --git a/lib/widget/stock/location_list.dart b/lib/widget/stock/location_list.dart new file mode 100644 index 0000000..d59c369 --- /dev/null +++ b/lib/widget/stock/location_list.dart @@ -0,0 +1,101 @@ +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"; + +class StockLocationList extends StatefulWidget { + const StockLocationList(this.filters); + + final Map filters; + + @override + _StockLocationListState createState() => _StockLocationListState(filters); +} + +class _StockLocationListState extends RefreshableState { + _StockLocationListState(this.filters); + + final Map filters; + + @override + String getAppBarTitle() => L10().stockLocations; + + @override + Widget getBody(BuildContext context) { + return PaginatedStockLocationList(filters); + } +} + +class PaginatedStockLocationList extends PaginatedSearchWidget { + const PaginatedStockLocationList( + Map filters, { + String title = "", + }) : super(filters: filters, title: title); + + @override + String get searchTitle => title.isNotEmpty ? title : L10().stockLocations; + + @override + _PaginatedStockLocationListState createState() => + _PaginatedStockLocationListState(); +} + +class _PaginatedStockLocationListState + extends PaginatedSearchState { + _PaginatedStockLocationListState() : super(); + + @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": { + "label": L10().includeSublocations, + "help_text": L10().includeSublocationsDetail, + "tristate": false, + }, + }; + + @override + 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( + title: Text(location.name), + subtitle: Text(location.pathstring), + 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 new file mode 100644 index 0000000..282a962 --- /dev/null +++ b/lib/widget/stock/stock_detail.dart @@ -0,0 +1,856 @@ +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/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"; +import "package:inventree/api_form.dart"; +import "package:inventree/labels.dart"; +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/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"; +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"; + +class StockDetailWidget extends StatefulWidget { + const StockDetailWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreeStockItem item; + + @override + _StockItemDisplayState createState() => _StockItemDisplayState(); +} + +class _StockItemDisplayState extends RefreshableState { + _StockItemDisplayState(); + + @override + String getAppBarTitle() => L10().stockItem; + + bool stockShowHistory = false; + bool stockShowTests = true; + bool expiryEnabled = false; + + // Linked data fields + InvenTreePart? part; + InvenTreeStockLocation? defaultLocation; + InvenTreeSalesOrder? salesOrder; + InvenTreeCompany? customer; + + @override + List appBarActions(BuildContext context) { + List actions = []; + + if (api.supportsMixin("locate")) { + actions.add( + 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); + }, + ), + ); + } + + return actions; + } + + @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( + SpeedDialChild( + child: Icon(TablerIcons.circle_minus, color: Colors.red), + label: L10().removeStock, + onTap: _removeStockDialog, + ), + ); + + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus, color: Colors.green), + label: L10().addStock, + onTap: _addStockDialog, + ), + ); + } + + // Transfer item + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.transfer), + label: L10().transferStock, + onTap: () { + _transferStockDialog(context); + }, + ), + ); + } + + if (allowLabelPrinting && api.supportsModernLabelPrinting) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.printer), + label: L10().printLabel, + onTap: () async { + selectAndPrintLabel(context, "stockitem", widget.item.pk); + }, + ), + ); + } + + if (widget.item.canDelete) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.trash, color: Colors.red), + label: L10().stockItemDelete, + onTap: () { + _deleteItem(context); + }, + ), + ); + } + + return actions; + } + + @override + List barcodeButtons(BuildContext context) { + List actions = []; + + 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); + }); + }, + ), + ); + + actions.add( + customBarcodeAction( + context, + this, + widget.item.customBarcode, + "stockitem", + widget.item.pk, + ), + ); + } + + return actions; + } + + bool allowLabelPrinting = false; + int attachmentCount = 0; + + @override + Future onBuild(BuildContext context) async { + // Load part data if not already loaded + if (part == null) { + refresh(context); + } + } + + @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; + + final bool result = widget.item.pk > 0 && await widget.item.reload(); + + // Could not load this stock item for some reason + // Perhaps it has been depleted? + if (!result) { + Navigator.of(context).pop(); + } + + expiryEnabled = await api.getGlobalBooleanSetting("STOCK_ENABLE_EXPIRY"); + + // Request part information + part = await InvenTreePart().get(widget.item.partId) as InvenTreePart?; + + 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) { + if (mounted) { + setState(() { + // Update + }); + } + }); + } + + // Request the number of attachments + InvenTreeAttachment() + .countAttachments(InvenTreeStockItem.MODEL_TYPE, widget.item.pk) + .then((int value) { + if (mounted) { + setState(() { + attachmentCount = value; + }); + } + }); + + // 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; + }); + } + } + + allowLabelPrinting = await InvenTreeSettingsManager().getBool( + INV_ENABLE_LABEL_PRINTING, + true, + ); + } + + /// Delete the stock item from the database + Future _deleteItem(BuildContext context) async { + confirmationDialog( + L10().stockItemDelete, + L10().stockItemDeleteConfirm, + icon: TablerIcons.trash, + color: Colors.red, + acceptText: L10().delete, + onAccept: () async { + final bool result = await widget.item.delete(); + + if (result) { + Navigator.of(context).pop(); + showSnackIcon(L10().stockItemDeleteSuccess, success: true); + } else { + showSnackIcon(L10().stockItemDeleteFailure, success: false); + } + }, + ); + } + + Future _editStockItem(BuildContext context) async { + var fields = InvenTreeStockItem().formFields(); + + // Some fields we don't want to edit! + fields.remove("part"); + fields.remove("quantity"); + fields.remove("location"); + fields.remove("serial_numbers"); + + if (part == null || !part!.isTrackable) { + fields.remove("serial"); + } + + widget.item.editForm( + context, + L10().editItem, + fields: fields, + onSuccess: (data) async { + refresh(context); + showSnackIcon(L10().stockItemUpdated, success: true); + }, + ); + } + + /* + * Launch a dialog to 'add' quantity to this StockItem + */ + Future _addStockDialog() async { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": widget.item.pk, + }, + "quantity": {"parent": "items", "nested": true, "value": 0}, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.addStockUrl(), + fields, + method: "POST", + icon: TablerIcons.circle_plus, + onSuccess: (data) async { + _stockUpdateMessage(true); + refresh(context); + }, + ); + } + + void _stockUpdateMessage(bool result) { + if (result) { + showSnackIcon(L10().stockItemUpdated, success: true); + } + } + + /* + * Launch a dialog to 'remove' quantity from this StockItem + */ + void _removeStockDialog() { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": widget.item.pk, + }, + "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); + }, + ); + } + + Future _countStockDialog() async { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": widget.item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": widget.item.quantity, + }, + "notes": {}, + }; + + launchApiForm( + 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 { + Map fields = widget.item.transferFields(); + + launchApiForm( + 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 = LargeText(L10().unavailable, color: COLOR_DANGER); + } else if (!widget.item.isSerialized()) { + trailing = LargeText( + widget.item.quantityString(), + 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) { + showLoadingOverlay(); + var part = await InvenTreePart().get(widget.item.partId); + hideLoadingOverlay(); + + if (part is InvenTreePart) { + part.goToDetailPage(context); + } + } + }, + //trailing: LargeText(item.serialOrQuantityDisplay()), + ), + ); + } + + /* + * Construct a list of detail elements about this StockItem. + * The number of elements may vary depending on the StockItem details + */ + @override + List getTiles(BuildContext context) { + List tiles = []; + + // Image / name / description + tiles.add(headerTile()); + + if (loading) { + tiles.add(progressIndicator()); + 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: Icon(TablerIcons.location, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + if (widget.item.locationId > 0) { + showLoadingOverlay(); + var loc = await InvenTreeStockLocation().get( + widget.item.locationId, + ); + hideLoadingOverlay(); + + if (loc is InvenTreeStockLocation) { + loc.goToDetailPage(context); + } + } + }, + ), + ); + } else { + tiles.add( + ListTile( + title: Text(L10().stockLocation), + leading: Icon(TablerIcons.location), + subtitle: Text(L10().locationNotSet), + ), + ); + } + + 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( + 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: LargeText("${widget.item.quantityString()}"), + ), + ); + } + + 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( + title: Text(L10().status), + leading: Icon(TablerIcons.help_circle), + trailing: LargeText( + api.StockStatus.label(widget.item.status), + color: api.StockStatus.color(widget.item.status), + ), + ), + ); + + // Supplier part information (if available) + if (widget.item.supplierPartId > 0) { + tiles.add( + ListTile( + title: Text(L10().supplierPart), + subtitle: Text(widget.item.supplierSKU), + leading: Icon(TablerIcons.building, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () async { + showLoadingOverlay(); + var sp = await InvenTreeSupplierPart().get( + widget.item.supplierPartId, + ); + hideLoadingOverlay(); + if (sp is InvenTreeSupplierPart) { + sp.goToDetailPage(context); + } + }, + ), + ); + } + + if (widget.item.isBuilding) { + tiles.add( + ListTile( + title: Text(L10().inProduction), + leading: Icon(TablerIcons.tools), + subtitle: Text(L10().inProductionDetail), + onTap: () { + // TODO: Click through to the "build order" + }, + ), + ); + } + + if (widget.item.hasSalesOrder && salesOrder != null) { + tiles.add( + ListTile( + title: Text(L10().salesOrder), + subtitle: Text( + salesOrder?.reference ?? salesOrder?.description ?? "", + ), + leading: Icon(TablerIcons.truck_delivery, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + salesOrder?.goToDetailPage(context); + }, + ), + ); + } + + if (widget.item.hasCustomer && customer != null) { + tiles.add( + ListTile( + title: Text(L10().customer), + subtitle: Text("${customer?.name} - ${customer?.description}"), + leading: Icon(TablerIcons.building_store, color: COLOR_ACTION), + trailing: LinkIcon(), + onTap: () { + customer?.goToDetailPage(context); + }, + ), + ); + } + + if (widget.item.batch.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().batchCode), + subtitle: Text(widget.item.batch), + leading: Icon(TablerIcons.clipboard_text), + ), + ); + } + + if (widget.item.packaging.isNotEmpty) { + tiles.add( + ListTile( + 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), + ); + } 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, + ), + ); + } + + // Last update? + if (widget.item.updatedDateString.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().lastUpdated), + trailing: LargeText(widget.item.updatedDateString), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + // Stocktake? + if (widget.item.stocktakeDateString.isNotEmpty) { + tiles.add( + ListTile( + title: Text(L10().lastStocktake), + trailing: LargeText(widget.item.stocktakeDateString), + leading: Icon(TablerIcons.calendar), + ), + ); + } + + if (widget.item.hasLink) { + tiles.add( + ListTile( + title: Text("${widget.item.link}"), + leading: Icon(TablerIcons.link, color: COLOR_ACTION), + 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: LinkIcon(text: "${widget.item.testResultCount}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockItemTestResultsWidget(widget.item), + ), + ).then((ctx) { + refresh(context); + }); + }, + ), + ); + } + + if (widget.item.hasPurchasePrice) { + tiles.add( + ListTile( + title: Text(L10().purchasePrice), + leading: Icon(TablerIcons.currency_dollar), + trailing: LargeText( + renderCurrency( + widget.item.purchasePrice, + widget.item.purchasePriceCurrency, + ), + ), + ), + ); + } + + // TODO - Is this stock item linked to a PurchaseOrder? + + if (stockShowHistory && widget.item.trackingItemCount > 0) { + tiles.add( + ListTile( + title: Text(L10().history), + leading: Icon(TablerIcons.history, color: COLOR_ACTION), + trailing: LinkIcon(text: "${widget.item.trackingItemCount}"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockItemHistoryWidget(widget.item), + ), + ).then((ctx) { + refresh(context); + }); + }, + ), + ); + } + + // Notes field + 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.item)), + ); + }, + ), + ); + + ListTile? attachmentTile = ShowAttachmentsItem( + context, + InvenTreeStockItem.MODEL_TYPE, + widget.item.pk, + L10().stockItem, + attachmentCount, + widget.item.canEdit, + ); + + if (attachmentTile != null) { + tiles.add(attachmentTile); + } + + return tiles; + } +} diff --git a/lib/widget/stock/stock_item_history.dart b/lib/widget/stock/stock_item_history.dart new file mode 100644 index 0000000..7324156 --- /dev/null +++ b/lib/widget/stock/stock_item_history.dart @@ -0,0 +1,101 @@ +import "package:flutter/material.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; + + @override + _StockItemHistoryDisplayState createState() => + _StockItemHistoryDisplayState(item); +} + +class _StockItemHistoryDisplayState + extends RefreshableState { + _StockItemHistoryDisplayState(this.item); + + final InvenTreeStockItem item; + + @override + String getAppBarTitle() => L10().stockItemHistory; + + @override + List appBarActions(BuildContext context) => []; + + @override + Widget getBody(BuildContext context) { + 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); + + @override + String get searchTitle => L10().stockItemHistory; + + @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, + ); + } +} diff --git a/lib/widget/stock/stock_item_test_results.dart b/lib/widget/stock/stock_item_test_results.dart new file mode 100644 index 0000000..9fb7d92 --- /dev/null +++ b/lib/widget/stock/stock_item_test_results.dart @@ -0,0 +1,258 @@ +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"; +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/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); +} + +class _StockItemTestResultDisplayState + extends RefreshableState { + _StockItemTestResultDisplayState(this.item); + + @override + String getAppBarTitle() => L10().testResults; + + @override + List appBarActions(BuildContext context) => []; + + @override + List actionButtons(BuildContext context) { + List actions = []; + + if (InvenTreeStockItemTestResult().canCreate) { + actions.add( + SpeedDialChild( + child: Icon(TablerIcons.circle_plus), + label: L10().testResultAdd, + onTap: () { + addTestResult(context); + }, + ), + ); + } + + return actions; + } + + @override + Future request(BuildContext context) async { + await item.getTestTemplates(); + await item.getTestResults(); + } + + final InvenTreeStockItem item; + + 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}", + }, + onSuccess: (data) { + refresh(context); + }, + fileField: "attachment", + ); + } + + // Squish together templates and results + List getTestResults() { + var templates = item.testTemplates; + var results = item.testResults; + + List outputs = []; + + // Add each template to the list + for (var t in templates) { + outputs.add(t); + } + + // Add each result (compare to existing items / templates + for (var result in results) { + bool match = false; + + for (var ii = 0; ii < outputs.length; ii++) { + // Check against templates + if (outputs[ii] is InvenTreePartTestTemplate) { + var template = outputs[ii] as InvenTreePartTestTemplate; + + // Match the result to a template + if (result.templateId == template.pk || result.key == template.key) { + template.results.add(result); + match = true; + break; + } + } else if (outputs[ii] is InvenTreeStockItemTestResult) { + var r = outputs[ii] as InvenTreeStockItemTestResult; + + if (r.key == result.key) { + // Overwrite with a newer result + outputs[ii] = result; + match = true; + break; + } + } + } + + if (!match) { + outputs.add(result); + } + } + + return outputs; + } + + @override + List getTiles(BuildContext context) { + List tiles = []; + + tiles.add( + Card( + child: ListTile( + title: Text(item.partName), + subtitle: Text(item.partDescription), + leading: InvenTreeAPI().getThumbnail(item.partImage), + ), + ), + ); + + tiles.add( + ListTile( + title: Text( + L10().testResults, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ); + + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + + var results = getTestResults(); + + if (results.isEmpty) { + tiles.add( + ListTile( + title: Text(L10().testResultNone), + subtitle: Text(L10().testResultNoneDetail), + ), + ); + + return tiles; + } + + for (var item in results) { + bool _hasResult = false; + bool _required = false; + String _test = ""; + int _templateId = 0; + bool _result = false; + String _value = ""; + String _date = ""; + + Widget _icon = Icon(TablerIcons.help_circle, color: Colors.lightBlue); + bool _valueRequired = false; + bool _attachmentRequired = false; + + if (item is InvenTreePartTestTemplate) { + _result = item.passFailStatus(); + _test = item.testName; + _templateId = item.pk; + _required = item.required; + _value = item.latestResult()?.value ?? L10().noResults; + _valueRequired = item.requiresValue; + _attachmentRequired = item.requiresAttachment; + _date = item.latestResult()?.date ?? ""; + _hasResult = item.latestResult() != null; + } else if (item is InvenTreeStockItemTestResult) { + _result = item.result; + _test = item.testName; + _templateId = item.templateId; + _date = item.date; + _required = false; + _value = item.value; + _hasResult = true; + } + + if (!_hasResult) { + _icon = Icon(TablerIcons.help_circle, color: Colors.blue); + } else if (_result == true) { + _icon = Icon(TablerIcons.circle_check, color: COLOR_SUCCESS); + } else if (_result == false) { + _icon = Icon(TablerIcons.circle_x, color: COLOR_DANGER); + } + + tiles.add( + ListTile( + title: Text( + _test, + style: TextStyle( + fontWeight: _required ? FontWeight.bold : FontWeight.normal, + fontStyle: _hasResult ? FontStyle.normal : FontStyle.italic, + ), + ), + subtitle: Text(_value), + trailing: Text(_date), + leading: _icon, + onTap: () { + if (InvenTreeStockItemTestResult().canCreate) { + addTestResult( + context, + name: _test, + templateId: _templateId, + nameIsEditable: !_required, + valueRequired: _valueRequired, + attachmentRequired: _attachmentRequired, + ); + } + }, + ), + ); + } + + if (tiles.isEmpty) { + tiles.add(ListTile(title: Text(L10().testResultNone))); + } + + return tiles; + } +} diff --git a/lib/widget/stock/stock_list.dart b/lib/widget/stock/stock_list.dart new file mode 100644 index 0000000..d969792 --- /dev/null +++ b/lib/widget/stock/stock_list.dart @@ -0,0 +1,149 @@ +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"; +import "package:inventree/api.dart"; + +class StockItemList extends StatefulWidget { + const StockItemList(this.filters); + + final Map filters; + + @override + _StockListState createState() => _StockListState(filters); +} + +class _StockListState extends RefreshableState { + _StockListState(this.filters); + + final Map filters; + + @override + String getAppBarTitle() => L10().stockItems; + + @override + Widget getBody(BuildContext context) { + return PaginatedStockItemList(filters); + } +} + +class PaginatedStockItemList extends PaginatedSearchWidget { + const PaginatedStockItemList(Map filters) + : super(filters: filters); + + @override + String get searchTitle => L10().stockItems; + + @override + _PaginatedStockItemListState createState() => _PaginatedStockItemListState(); +} + +class _PaginatedStockItemListState + extends PaginatedSearchState { + _PaginatedStockItemListState() : super(); + + @override + String get prefix => "stock_"; + + @override + Map get orderingOptions => { + "part__name": L10().name, + "part__IPN": L10().internalPartNumber, + "stock": L10().quantity, + "status": L10().status, + "batch": L10().batchCode, + "updated": L10().lastUpdated, + "stocktake_date": L10().lastStocktake, + }; + + @override + Map> get filterOptions { + Map> filters = { + "available": { + "default": null, + "label": L10().available, + "help_text": L10().availableStock, + "tristate": true, + }, + "in_stock": { + "default": true, + "label": L10().filterInStock, + "help_text": L10().filterInStockDetail, + "tristate": true, + }, + "active": { + "default": true, + "label": L10().filterActive, + "help_text": L10().filterActiveDetail, + }, + "cascade": { + "default": true, + "label": L10().includeSublocations, + "help_text": L10().includeSublocationsDetail, + "tristate": false, + }, + "external": { + "default": null, + "label": L10().filterExternal, + "help_text": L10().filterExternalDetail, + "tristate": true, + }, + "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 { + // Ensure StockStatus codes are loaded + await InvenTreeAPI().StockStatus.load(); + + final page = await InvenTreeStockItem().listPaginated( + limit, + offset, + filters: params, + ); + + return page; + } + + @override + Widget buildItem(BuildContext context, InvenTreeModel model) { + InvenTreeStockItem item = model as InvenTreeStockItem; + + return ListTile( + title: Text("${item.partName}"), + subtitle: Text(item.locationPathString), + leading: InvenTreeAPI().getThumbnail(item.partThumbnail), + trailing: LargeText( + item.displayQuantity, + size: 14, + color: InvenTreeAPI().StockStatus.color(item.status), + ), + onTap: () { + item.goToDetailPage(context); + }, + ); + } +} diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart deleted file mode 100644 index 3b400b2..0000000 --- a/lib/widget/stock_detail.dart +++ /dev/null @@ -1,1102 +0,0 @@ -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"; -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/l10.dart"; -import "package:inventree/helpers.dart"; -import "package:inventree/api.dart"; -import "package:inventree/api_form.dart"; -import "package:inventree/app_settings.dart"; - - -class StockDetailWidget extends StatefulWidget { - - const StockDetailWidget(this.item, {Key? key}) : super(key: key); - - final InvenTreeStockItem item; - - @override - _StockItemDisplayState createState() => _StockItemDisplayState(item); -} - - -class _StockItemDisplayState extends RefreshableState { - - _StockItemDisplayState(this.item); - - @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 - List getAppBarActions(BuildContext context) { - - List actions = []; - - if (InvenTreeAPI().checkPermission("stock", "view")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.globe), - onPressed: _openInvenTreePage, - ) - ); - } - - if (InvenTreeAPI().checkPermission("stock", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - tooltip: L10().edit, - onPressed: () { _editStockItem(context); }, - ) - ); - } - - return actions; - } - - Future _openInvenTreePage() async { - item.goToInvenTreePage(); - } - - // StockItem object - final InvenTreeStockItem item; - - // Is label printing enabled for this StockItem? - // This will be determined when the widget is loaded - List> labels = []; - - // Part object - InvenTreePart? part; - - @override - Future onBuild(BuildContext context) async { - - // Load part data if not already loaded - if (part == null) { - refresh(context); - } - } - - @override - Future request(BuildContext context) async { - - final bool result = await item.reload(); - - stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; - - // Could not load this stock item for some reason - // Perhaps it has been depleted? - if (!result || item.pk == -1) { - Navigator.of(context).pop(); - } - - // Request part information - part = await InvenTreePart().get(item.partId) as InvenTreePart?; - - // Request test results (async) - item.getTestResults().then((value) { - setState(() { - // Update - }); - }); - - // Request information on labels available for this stock item - if (InvenTreeAPI().pluginsEnabled()) { - _getLabels(); - } - } - - 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": "${item.pk}", - }, - ).then((APIResponse response) { - if (response.isValid() && response.statusCode == 200) { - for (var label in response.data) { - if (label is Map) { - labels.add(label); - } - } - - setState(() { - }); - } - }); - } - - /// Delete the stock item from the database - Future _deleteItem(BuildContext context) async { - - confirmationDialog( - L10().stockItemDelete, - L10().stockItemDeleteConfirm, - icon: FontAwesomeIcons.trashAlt, - onAccept: () async { - final bool result = await item.delete(); - - if (result) { - Navigator.of(context).pop(); - showSnackIcon(L10().stockItemDeleteSuccess, success: true); - } else { - showSnackIcon(L10().stockItemDeleteFailure, success: false); - } - }, - ); - - } - - /// 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": "Label Template", - "type": "choice", - "value": initial_label, - "choices": label_options, - "required": true, - }, - "plugin": { - "label": "Printer", - "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=${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(); - - // Some fields we don't want to edit! - fields.remove("part"); - fields.remove("quantity"); - fields.remove("location"); - - item.editForm( - context, - L10().editItem, - fields: fields, - onSuccess: (data) async { - refresh(context); - showSnackIcon(L10().stockItemUpdated, success: true); - } - ); - - } - - 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); - } - - Future _addStockDialog() async { - - // TODO: In future, deprecate support for older API - if (InvenTreeAPI().supportModernStockTransactions()) { - - 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(); - }, - fields: [ - Text("Current stock: ${item.quantity}"), - QuantityField( - label: L10().addStock, - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ], - ); - } - - void _stockUpdateMessage(bool result) { - - if (result) { - showSnackIcon(L10().stockItemUpdated, success: true); - } - } - - 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); - - } - - void _removeStockDialog() { - - // TODO: In future, deprecate support for the older API - if (InvenTreeAPI().supportModernStockTransactions()) { - 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, - ), - ], - ); - } - - 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().supportModernStockTransactions()) { - - 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(); - }, - acceptText: L10().count, - fields: [ - QuantityField( - label: L10().countStock, - hint: "${item.quantityString}", - controller: _quantityController, - ), - TextFormField( - decoration: InputDecoration( - labelText: L10().notes, - ), - controller: _notesController, - ) - ] - ); - } - - - Future _unassignBarcode(BuildContext context) async { - - final bool result = await item.update(values: {"uid": ""}); - - if (result) { - showSnackIcon( - L10().stockItemUpdateSuccess, - success: true - ); - } else { - showSnackIcon( - L10().stockItemUpdateFailure, - success: false, - ); - } - - refresh(context); - } - - - // 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().supportModernStockTransactions()) { - - 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; - } - - 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, - ), - ], - ); - } - - Widget headerTile() { - return Card( - child: ListTile( - title: Text("${item.partName}"), - subtitle: Text("${item.partDescription}"), - leading: InvenTreeAPI().getImage(item.partImage), - trailing: Text( - item.statusLabel(context), - style: TextStyle( - color: item.statusColor - ) - ), - onTap: () { - if (item.partId > 0) { - InvenTreePart().get(item.partId).then((var part) { - if (part is InvenTreePart) { - Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); - } - }); - } - }, - //trailing: Text(item.serialOrQuantityDisplay()), - ) - ); - } - - /* - * Construct a list of detail elements about this StockItem. - * The number of elements may vary depending on the StockItem details - */ - List detailTiles() { - List tiles = []; - - // Image / name / description - tiles.add(headerTile()); - - if (loading) { - tiles.add(progressIndicator()); - return tiles; - } - - // Quantity information - if (item.isSerialized()) { - tiles.add( - ListTile( - title: Text(L10().serialNumber), - leading: FaIcon(FontAwesomeIcons.hashtag), - trailing: Text("${item.serialNumber}"), - ) - ); - } else { - tiles.add( - ListTile( - title: Text(L10().quantity), - leading: FaIcon(FontAwesomeIcons.cubes), - trailing: Text("${item.quantityString()}"), - ) - ); - } - - // Location information - if ((item.locationId > 0) && (item.locationName.isNotEmpty)) { - tiles.add( - ListTile( - title: Text(L10().stockLocation), - subtitle: Text("${item.locationPathString}"), - leading: FaIcon( - FontAwesomeIcons.mapMarkerAlt, - color: COLOR_CLICK, - ), - onTap: () { - if (item.locationId > 0) { - InvenTreeStockLocation().get(item.locationId).then((var loc) { - - if (loc is InvenTreeStockLocation) { - Navigator.push(context, MaterialPageRoute( - builder: (context) => LocationDisplayWidget(loc))); - } - }); - } - }, - ), - ); - } else { - tiles.add( - ListTile( - title: Text(L10().stockLocation), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), - subtitle: Text(L10().locationNotSet), - ) - ); - } - - if (item.isBuilding) { - tiles.add( - ListTile( - title: Text(L10().inProduction), - leading: FaIcon(FontAwesomeIcons.tools), - subtitle: Text(L10().inProductionDetail), - onTap: () { - // TODO: Click through to the "build order" - }, - ) - ); - } - - if (item.batch.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().batchCode), - subtitle: Text(item.batch), - leading: FaIcon(FontAwesomeIcons.layerGroup), - ) - ); - } - - if (item.packaging.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().packaging), - subtitle: Text(item.packaging), - leading: FaIcon(FontAwesomeIcons.box), - ) - ); - } - - // Last update? - if (item.updatedDateString.isNotEmpty) { - - tiles.add( - ListTile( - title: Text(L10().lastUpdated), - subtitle: Text(item.updatedDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) - ) - ); - } - - // Stocktake? - if (item.stocktakeDateString.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().lastStocktake), - subtitle: Text(item.stocktakeDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) - ) - ); - } - - // Supplier part? - // TODO: Display supplier part info page? - /* - if (item.supplierPartId > 0) { - tiles.add( - ListTile( - title: Text("${item.supplierName}"), - subtitle: Text("${item.supplierSKU}"), - leading: FaIcon(FontAwesomeIcons.industry), - trailing: InvenTreeAPI().getImage(item.supplierImage), - onTap: null, - ) - ); - } - */ - - if (item.link.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${item.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), - onTap: () { - item.openLink(); - }, - ) - ); - } - - if ((item.testResultCount > 0) || (part?.isTrackable ?? false)) { - tiles.add( - ListTile( - title: Text(L10().testResults), - leading: FaIcon(FontAwesomeIcons.tasks, color: COLOR_CLICK), - trailing: Text("${item.testResultCount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockItemTestResultsWidget(item)) - ).then((ctx) { - refresh(context); - }); - } - ) - ); - } - - if (item.hasPurchasePrice) { - tiles.add( - ListTile( - title: Text(L10().purchasePrice), - leading: FaIcon(FontAwesomeIcons.dollarSign), - trailing: Text(item.purchasePrice), - ) - ); - } - - // TODO - Is this stock item linked to a PurchaseOrder? - - if (stockShowHistory && item.trackingItemCount > 0) { - tiles.add( - ListTile( - title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK), - trailing: Text("${item.trackingItemCount}"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StockItemHistoryWidget(item)) - ).then((ctx) { - refresh(context); - }); - }, - ) - ); - } - - // Notes field - tiles.add( - ListTile( - title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => StockNotesWidget(item)) - ); - // TODO: Load notes in markdown viewer widget - // TODO: Make this widget editable? - } - ) - ); - - 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.userTimes) - ) - ); - - tiles.add( - ListTile( - subtitle: Text(L10().permissionAccountDenied), - ) - ); - - return tiles; - } - - // "Count" is not available for serialized stock - if (!item.isSerialized()) { - tiles.add( - ListTile( - title: Text(L10().countStock), - leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), - onTap: _countStockDialog, - trailing: Text(item.quantityString(includeUnits: true)), - ) - ); - - tiles.add( - ListTile( - title: Text(L10().removeStock), - leading: FaIcon(FontAwesomeIcons.minusCircle, color: COLOR_CLICK), - onTap: _removeStockDialog, - ) - ); - - tiles.add( - ListTile( - title: Text(L10().addStock), - leading: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), - onTap: _addStockDialog, - ) - ); - } - - tiles.add( - ListTile( - title: Text(L10().transferStock), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), - onTap: () { _transferStockDialog(context); }, - ) - ); - - // Scan item into a location - tiles.add( - ListTile( - title: Text(L10().scanIntoLocation), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), - trailing: Icon(Icons.qr_code_scanner), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(StockItemScanIntoLocationHandler(item))) - ).then((ctx) { - refresh(context); - }); - }, - ) - ); - - // Add or remove custom barcode - if (item.uid.isEmpty) { - tiles.add( - ListTile( - title: Text(L10().barcodeAssign), - leading: Icon(Icons.qr_code), - trailing: Icon(Icons.qr_code_scanner), - onTap: () { - - var handler = UniqueBarcodeHandler((String hash) { - item.update( - values: { - "uid": hash, - } - ).then((result) { - if (result) { - successTone(); - - showSnackIcon( - L10().barcodeAssigned, - success: true, - icon: Icons.qr_code, - ); - - refresh(context); - } - }); - }); - - Navigator.push( - context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(handler)) - ); - } - ) - ); - } else { - tiles.add( - ListTile( - title: Text(L10().barcodeUnassign), - leading: Icon(Icons.qr_code, color: COLOR_CLICK), - onTap: () { - _unassignBarcode(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.trashAlt, color: COLOR_DANGER), - onTap: () { - _deleteItem(context); - }, - ) - ); - } - - return tiles; - } - - @override - Widget getBottomNavBar(BuildContext context) { - return BottomNavigationBar( - currentIndex: tabIndex, - onTap: onTabSelectionChanged, - items: [ - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.infoCircle), - 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); - } -} \ No newline at end of file diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart deleted file mode 100644 index c2284c0..0000000 --- a/lib/widget/stock_item_history.dart +++ /dev/null @@ -1,75 +0,0 @@ -import "package:flutter/material.dart"; - -import "package:inventree/widget/refreshable_state.dart"; -import "package:inventree/l10.dart"; -import "package:inventree/inventree/stock.dart"; -import "package:inventree/inventree/model.dart"; - - -class StockItemHistoryWidget extends StatefulWidget { - - const StockItemHistoryWidget(this.item, {Key? key}) : super(key: key); - - final InvenTreeStockItem item; - - @override - _StockItemHistoryDisplayState createState() => _StockItemHistoryDisplayState(item); -} - - -class _StockItemHistoryDisplayState extends RefreshableState { - - _StockItemHistoryDisplayState(this.item); - - final InvenTreeStockItem item; - - @override - String getAppBarTitle(BuildContext context) => L10().stockItemHistory; - - List history = []; - - @override - Future request(BuildContext refresh) async { - - history.clear(); - - InvenTreeStockItemHistory().list(filters: {"item": "${item.pk}"}).then((List results) { - for (var result in results) { - if (result is InvenTreeStockItemHistory) { - history.add(result); - } - } - - // Refresh - setState(() { - }); - }); - } - - @override - Widget getBody(BuildContext context) { - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: historyList(), - ).toList() - ); - } - - 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 diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart deleted file mode 100644 index df34bb6..0000000 --- a/lib/widget/stock_item_test_results.dart +++ /dev/null @@ -1,223 +0,0 @@ -import "package:inventree/app_colors.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 { - - const StockItemTestResultsWidget(this.item, {Key? key}) : super(key: key); - - final InvenTreeStockItem item; - - @override - _StockItemTestResultDisplayState createState() => _StockItemTestResultDisplayState(item); -} - - -class _StockItemTestResultDisplayState extends RefreshableState { - - _StockItemTestResultDisplayState(this.item); - - @override - String getAppBarTitle(BuildContext context) => L10().testResults; - - @override - List getAppBarActions(BuildContext context) { - return [ - IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), - onPressed: () { - addTestResult(context); - } - ), - ]; - } - - @override - Future request(BuildContext context) async { - await item.getTestTemplates(); - await item.getTestResults(); - } - - final InvenTreeStockItem item; - - Future addTestResult(BuildContext context, {String name = "", bool nameIsEditable = true, bool result = false, String value = "", bool valueRequired = false, bool attachmentRequired = false}) async { - - InvenTreeStockItemTestResult().createForm( - context, - L10().testResultAdd, - data: { - "stock_item": "${item.pk}", - "test": "${name}", - }, - onSuccess: (data) { - refresh(context); - }, - fileField: "attachment", - ); - } - - // Squish together templates and results - List getTestResults() { - var templates = item.testTemplates; - var results = item.testResults; - - List outputs = []; - - // Add each template to the list - for (var t in templates) { - outputs.add(t); - } - - // Add each result (compare to existing items / templates - for (var result in results) { - bool match = false; - - for (var ii = 0; ii < outputs.length; ii++) { - - // Check against templates - if (outputs[ii] is InvenTreePartTestTemplate) { - var t = outputs[ii] as InvenTreePartTestTemplate; - - if (result.key == t.key) { - t.results.add(result); - match = true; - break; - } - } else if (outputs[ii] is InvenTreeStockItemTestResult) { - var r = outputs[ii] as InvenTreeStockItemTestResult; - - if (r.key == result.key) { - // Overwrite with a newer result - outputs[ii] = result; - match = true; - break; - } - } - } - - if (!match) { - outputs.add(result); - } - } - - return outputs; - } - - List resultsList() { - List tiles = []; - - tiles.add( - Card( - child: ListTile( - title: Text(item.partName), - subtitle: Text(item.partDescription), - leading: InvenTreeAPI().getImage(item.partImage), - ) - ) - ); - - tiles.add( - ListTile( - title: Text(L10().testResults, - style: TextStyle(fontWeight: FontWeight.bold) - ) - ) - ); - - if (loading) { - tiles.add(progressIndicator()); - return tiles; - } - - var results = getTestResults(); - - if (results.isEmpty) { - tiles.add(ListTile( - title: Text(L10().testResultNone), - subtitle: Text(L10().testResultNoneDetail), - )); - - return tiles; - } - - for (var item in results) { - - bool _required = false; - String _test = ""; - bool _result = false; - String _value = ""; - - FaIcon _icon = FaIcon(FontAwesomeIcons.questionCircle, color: COLOR_BLUE); - bool _valueRequired = false; - bool _attachmentRequired = false; - - if (item is InvenTreePartTestTemplate) { - _result = item.passFailStatus(); - _test = item.testName; - _required = item.required; - _value = item.latestResult()?.value ?? ""; - _valueRequired = item.requiresValue; - _attachmentRequired = item.requiresAttachment; - } else if (item is InvenTreeStockItemTestResult) { - _result = item.result; - _test = item.testName; - _required = false; - _value = item.value; - } - - if (_result == true) { - _icon = FaIcon(FontAwesomeIcons.checkCircle, - color: COLOR_SUCCESS, - ); - } else if (_result == false) { - _icon = FaIcon(FontAwesomeIcons.timesCircle, - color: COLOR_DANGER, - ); - } - - tiles.add(ListTile( - title: Text(_test, style: TextStyle(fontWeight: _required ? FontWeight.bold : FontWeight.normal)), - subtitle: Text(_value), - trailing: _icon, - onLongPress: () { - addTestResult( - context, - name: _test, - nameIsEditable: !_required, - valueRequired: _valueRequired, - attachmentRequired: _attachmentRequired - ); - } - )); - } - - if (tiles.isEmpty) { - tiles.add(ListTile( - title: Text(L10().testResultNone), - )); - } - - return tiles; - } - - @override - Widget getBody(BuildContext context) { - - return ListView( - children: ListTile.divideTiles( - context: context, - tiles: resultsList() - ).toList() - ); - } -} \ No newline at end of file diff --git a/lib/widget/stock_list.dart b/lib/widget/stock_list.dart deleted file mode 100644 index b78cdf1..0000000 --- a/lib/widget/stock_list.dart +++ /dev/null @@ -1,104 +0,0 @@ -import "package:flutter/material.dart"; - -import "package:inventree/inventree/model.dart"; -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/widget/stock_detail.dart"; -import "package:inventree/api.dart"; - - -class StockItemList extends StatefulWidget { - - const StockItemList(this.filters); - - final Map filters; - - @override - _StockListState createState() => _StockListState(filters); -} - - -class _StockListState extends RefreshableState { - - _StockListState(this.filters); - - final Map filters; - - @override - String getAppBarTitle(BuildContext context) => L10().purchaseOrders; - - @override - Widget getBody(BuildContext context) { - return PaginatedStockItemList(filters); - } -} - -class PaginatedStockItemList extends StatefulWidget { - - const PaginatedStockItemList(this.filters); - - final Map filters; - - @override - _PaginatedStockItemListState createState() => _PaginatedStockItemListState(filters); - -} - - -class _PaginatedStockItemListState extends PaginatedSearchState { - - _PaginatedStockItemListState(Map filters) : super(filters); - - @override - Future requestPage(int limit, int offset, Map params) async { - - // Do we include stock items from sub-locations? - final bool cascade = await InvenTreeSettingsManager().getBool(INV_STOCK_SUBLOCATION, true); - - params["cascade"] = "${cascade}"; - - final page = await InvenTreeStockItem().listPaginated( - limit, - offset, - filters: params - ); - - return page; - } - - void _openItem(BuildContext context, int pk) { - InvenTreeStockItem().get(pk).then((var item) { - if (item is InvenTreeStockItem) { - Navigator.push(context, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); - } - }); - } - - @override - Widget buildItem(BuildContext context, InvenTreeModel model) { - - InvenTreeStockItem item = model as InvenTreeStockItem; - - return ListTile( - title: Text("${item.partName}"), - subtitle: Text("${item.locationPathString}"), - leading: InvenTreeAPI().getImage( - item.partThumbnail, - width: 40, - height: 40, - ), - trailing: Text("${item.displayQuantity}", - style: TextStyle( - fontWeight: FontWeight.bold, - color: item.statusColor, - ), - ), - onTap: () { - _openItem(context, item.pk); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widget/stock_notes.dart b/lib/widget/stock_notes.dart deleted file mode 100644 index 05cc405..0000000 --- a/lib/widget/stock_notes.dart +++ /dev/null @@ -1,75 +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(BuildContext context) => L10().stockItemNotes; - - @override - Future request(BuildContext context) async { - await item.reload(); - } - - @override - List getAppBarActions(BuildContext context) { - List actions = []; - - if (InvenTreeAPI().checkPermission("stock", "change")) { - actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - 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/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 diff --git a/pubspec.lock b/pubspec.lock index 4fb3ba9..ed42dec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,268 +1,488 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f + url: "https://pub.dev" + source: hosted + version: "82.0.0" + adaptive_theme: + dependency: "direct main" + description: + name: adaptive_theme + sha256: caa49b4c73b681bf12a641dff77aa1383262a00cf38b9d1a25b180e275ba5ab9 + url: "https://pub.dev" + source: hosted + version: "3.7.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" + url: "https://pub.dev" + source: hosted + version: "7.4.5" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "4.0.7" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.7.0" async: - dependency: transitive + dependency: "direct main" description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.13.0" audioplayers: dependency: "direct main" description: name: audioplayers - url: "https://pub.dartlang.org" + sha256: a5341380a4f1d3a10a4edde5bb75de5127fe31e0faa8c4d860e64d2f91ad84c7 + url: "https://pub.dev" source: hosted - version: "0.20.1" + version: "6.4.0" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + sha256: f8c90823a45b475d2c129f85bbda9c029c8d4450b172f62e066564c6e170f69a + url: "https://pub.dev" + source: hosted + version: "5.2.0" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + sha256: "405cdbd53ebdb4623f1c5af69f275dad4f930ce895512d5261c07cd95d23e778" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: "7e0d081a6a527c53aef9539691258a08ff69a7dc15ef6335fbea1b4b03ebbef0" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + sha256: "77e5fa20fb4a64709158391c75c1cca69a481d35dc879b519e350a05ff520373" + url: "https://pub.dev" + source: hosted + version: "7.1.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + sha256: bd99d8821114747682a2be0adcdb70233d4697af989b549d3a20a0f49f6c9b13 + url: "https://pub.dev" + source: hosted + version: "5.1.0" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + sha256: "871d3831c25cd2408ddc552600fd4b32fba675943e319a41284704ee038ad563" + url: "https://pub.dev" + source: hosted + version: "4.2.0" back_button_interceptor: dependency: transitive description: name: back_button_interceptor - url: "https://pub.dartlang.org" + sha256: "8354b03320043db546e3f446af171faaa71384100486444113628f7db1e7fe9b" + url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "7.0.3" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" cached_network_image: dependency: "direct main" description: name: cached_network_image - url: "https://pub.dartlang.org" + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.4.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - url: "https://pub.dartlang.org" + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "4.1.1" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - url: "https://pub.dartlang.org" + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.3.1" camera: dependency: "direct main" description: name: camera - url: "https://pub.dartlang.org" + sha256: "413d2b34fe28496c35c69ede5b232fb9dd5ca2c3a4cb606b14efc1c7546cc8cb" + url: "https://pub.dev" source: hosted - version: "0.9.4+17" + version: "0.11.1" + camera_android_camerax: + dependency: transitive + description: + name: camera_android_camerax + sha256: b4197bd6ce75bc66963a904c34c4cbb6aaa2260a5d4aca13b3556926cf3a92b8 + url: "https://pub.dev" + source: hosted + version: "0.6.18+3" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: ca244564876d5a76f2126bca501aec25243cad23ba1784819242aea2fd25cf70 + url: "https://pub.dev" + source: hosted + version: "0.9.19+2" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - url: "https://pub.dartlang.org" + sha256: "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2" + url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.10.0" camera_web: dependency: transitive description: name: camera_web - url: "https://pub.dartlang.org" + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" + url: "https://pub.dev" source: hosted - version: "0.2.1+3" + version: "0.3.5" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: + version: "1.4.0" + checked_yaml: dependency: transitive description: - name: charcode - url: "https://pub.dartlang.org" + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "2.0.4" + 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: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 + url: "https://pub.dev" + source: hosted + version: "1.14.1" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" source: hosted - version: "0.3.2" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.8" + currency_formatter: + dependency: "direct main" + description: + name: currency_formatter + sha256: c2a32f8ab74649fa8df22e6d2e0288fdcddd733655bb95ccbabbf181e98f280a + 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: name: datetime_picker_formfield - url: "https://pub.dartlang.org" + sha256: "6d0412c98cc5da18a5dca1f81f82a834fbacdb5d249fd6d9bed42d912339720e" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" device_info_plus: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + sha256: "0c6396126421b590089447154c5f98a5de423b70cfb15b1578fd018843ee6f53" + url: "https://pub.dev" source: hosted - version: "3.2.2" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.2" + version: "11.4.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" + url: "https://pub.dev" source: hosted - version: "2.3.0+1" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" + version: "7.0.2" dropdown_search: dependency: "direct main" description: name: dropdown_search - url: "https://pub.dartlang.org" + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "5.0.6" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "2.1.4" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "7.0.1" file_picker: dependency: "direct main" description: name: file_picker - url: "https://pub.dartlang.org" + sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a + url: "https://pub.dev" source: hosted - version: "4.5.1" + version: "10.2.0" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" + url: "https://pub.dev" + source: hosted + version: "0.9.4+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + 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 source: sdk version: "0.0.0" - flutter_blurhash: - dependency: transitive - description: - name: flutter_blurhash - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.4" flutter_cache_manager: dependency: "direct main" description: name: flutter_cache_manager - url: "https://pub.dartlang.org" + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.4.1" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" source: hosted - version: "0.9.2" + version: "0.14.4" flutter_localizations: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_localized_locales: + dependency: "direct main" + description: + name: flutter_localized_locales + sha256: "478d10535edf07292e34cb4c757882edeeaf96d5e3dbb04b42733038bd41dd3f" + url: "https://pub.dev" + source: hosted + version: "2.0.5" flutter_markdown: dependency: "direct main" description: name: flutter_markdown - url: "https://pub.dartlang.org" + sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504" + url: "https://pub.dev" source: hosted - version: "0.6.9+1" + version: "0.6.23" + flutter_overlay_loader: + dependency: "direct main" + description: + name: flutter_overlay_loader + sha256: d447edb434269e5f639d03018577676e7e4b16ad4d619d028ed464f3a8180984 + url: "https://pub.dev" + source: hosted + version: "2.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.28" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "41d7ad0bc224248637b3a5e0b9083e912a75445bdb450cf82b8ed06d7af7c61d" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + flutter_staggered_grid_view: + dependency: transitive + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_tabler_icons: + dependency: "direct main" + description: + name: flutter_tabler_icons + sha256: "657c2201e12fa9121a12ddb4edb74d69290f803868eb6526f04102e6d49ec882" + url: "https://pub.dev" + source: hosted + version: "1.43.0" flutter_test: dependency: "direct dev" description: flutter @@ -273,550 +493,883 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" + frontend_server_client: + dependency: transitive description: - name: font_awesome_flutter - url: "https://pub.dartlang.org" + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" source: hosted - version: "9.2.0" + 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: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "1.4.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.2" image: dependency: transitive description: name: image - url: "https://pub.dartlang.org" + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "4.5.4" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" source: hosted - version: "0.8.4+11" + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb" + url: "https://pub.dev" + source: hosted + version: "0.8.12+23" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.dartlang.org" + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" infinite_scroll_pagination: dependency: "direct main" description: name: infinite_scroll_pagination - url: "https://pub.dartlang.org" + sha256: "4047eb8191e8b33573690922a9e995af64c3949dc87efc844f936b039ea279df" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.1.0" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.20.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.7.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + 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 - url: "https://pub.dartlang.org" + sha256: "3cd03646de313481336500ba02eb34d07c590535525f154aae7fda7362aa07a9" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "2.8.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" markdown: dependency: transitive description: name: markdown - url: "https://pub.dartlang.org" + sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "7.3.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + 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: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" octo_image: dependency: transitive description: name: octo_image - url: "https://pub.dartlang.org" + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "2.1.0" one_context: dependency: "direct main" description: name: one_context - url: "https://pub.dartlang.org" + sha256: bafae468bdb5d1089736c4e97582b85abd994a80b65c5becb6956a31c59d69e4 + url: "https://pub.dev" source: hosted - version: "1.1.1" - open_file: + version: "4.1.0" + open_filex: dependency: "direct main" description: - name: open_file - url: "https://pub.dartlang.org" + name: open_filex + sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900" + url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "4.7.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - url: "https://pub.dartlang.org" + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + url: "https://pub.dev" source: hosted - version: "1.4.0" - package_info_plus_linux: - dependency: transitive - description: - name: package_info_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - package_info_plus_macos: - dependency: transitive - description: - name: package_info_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + version: "8.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + url: "https://pub.dev" source: hosted - version: "1.0.2" - package_info_plus_web: - dependency: transitive - description: - name: package_info_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - package_info_plus_windows: - dependency: transitive - description: - name: package_info_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" + version: "3.2.0" path: dependency: "direct main" description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + url: "https://pub.dev" source: hosted - version: "2.0.12" - path_provider_ios: + version: "2.2.17" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - url: "https://pub.dartlang.org" + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" source: hosted - version: "2.0.8" + version: "2.4.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" source: hosted - version: "2.1.5" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" source: hosted - version: "2.0.5" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" + version: "2.3.0" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "6.1.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" source: hosted - version: "2.1.2" - process: + version: "2.1.8" + pool: dependency: transitive description: - name: process - url: "https://pub.dartlang.org" + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted - version: "4.2.4" - qr_code_scanner: - dependency: "direct main" - description: - name: qr_code_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.0" - quiver: + version: "1.5.1" + posix: dependency: transitive description: - name: quiver - url: "https://pub.dartlang.org" + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" source: hosted - version: "3.0.1+1" + version: "6.0.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" source: hosted - version: "0.27.3" + version: "0.28.0" sembast: dependency: "direct main" description: name: sembast - url: "https://pub.dartlang.org" + sha256: "7119cf6f79bd1d48c8ec7943f4facd96c15ab26823021ed0792a487c7cd34441" + url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.8.5+1" sentry: dependency: transitive description: name: sentry - url: "https://pub.dartlang.org" + sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb" + url: "https://pub.dev" source: hosted - version: "6.4.0" + version: "8.14.2" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - url: "https://pub.dartlang.org" + sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8" + url: "https://pub.dev" source: hosted - version: "6.4.0" + version: "8.14.2" shared_preferences: dependency: transitive description: name: shared_preferences - url: "https://pub.dartlang.org" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" + url: "https://pub.dev" source: hosted - version: "2.0.11" - shared_preferences_ios: + version: "2.4.10" + shared_preferences_foundation: dependency: transitive description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" source: hosted - version: "2.1.0" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" sliver_tools: dependency: transitive description: name: sliver_tools - url: "https://pub.dartlang.org" + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.dev" source: hosted - version: "0.2.5" + version: "0.2.12" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.8.1" + 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 - url: "https://pub.dartlang.org" + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" source: hosted - version: "2.0.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 - url: "https://pub.dartlang.org" + sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" + url: "https://pub.dev" source: hosted - version: "2.2.1" + 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: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.4.1" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" + url: "https://pub.dev" source: hosted - version: "3.0.0+2" + version: "3.3.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + url: "https://pub.dev" + source: hosted + version: "1.25.15" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.8" + version: "0.7.4" + test_core: + dependency: transitive + description: + name: test_core + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + url: "https://pub.dev" + source: hosted + version: "0.6.8" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" source: hosted - version: "6.0.20" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" source: hosted - version: "6.0.15" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" source: hosted - version: "6.0.15" + version: "6.3.3" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.4" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "4.5.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + wakelock_plus: + dependency: "direct main" + description: + name: wakelock_plus + sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 + url: "https://pub.dev" + source: hosted + version: "1.3.2" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + watcher: + dependency: transitive + description: + name: watcher + sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "5.14.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" source: hosted - version: "0.2.0+1" + version: "1.1.0" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "6.5.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.3" sdks: - dart: ">=2.16.0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=3.8.1 <4.0.0" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 74200e9..129d635 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,47 +1,55 @@ name: inventree description: InvenTree stock management -version: 0.6.1+39 +version: 0.21.2+108 environment: - sdk: ">=2.16.0 <3.0.0" + sdk: ^3.8.1 dependencies: - - audioplayers: ^0.20.1 # Play audio files - cached_network_image: ^3.2.0 # Download and cache remote images - 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 - file_picker: ^4.5.1 # Select files from the device + 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 + 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 + file_picker: ^10.1.4 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 flutter_localizations: sdk: flutter - flutter_markdown: ^0.6.9 # Rendering markdown - font_awesome_flutter: ^9.1.0 # FontAwesome icon set - http: ^0.13.4 - image_picker: ^0.8.3 # 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.0 # 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 + 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.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.20.2 + mobile_scanner: ^7.0.1 # Barcode scanning support + one_context: ^4.0.0 # Dialogs without requiring context + 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.5 # Local file storage + sembast: ^3.6.0 # NoSQL data storage + 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: + flutter_launcher_icons: ^0.14.1 flutter_test: sdk: flutter - lint: ^1.0.0 + lint: ^2.1.2 + test: ^1.22.0 flutter_icons: android: true @@ -54,39 +62,17 @@ flutter_icons: # The following section is specific to Flutter. flutter: uses-material-design: true - generate: true assets: - assets/image/icon.png + - assets/image/logo_transparent.png - assets/release_notes.md - assets/credits.md - 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 +sentry: + upload_debug_symbols: true + upload_source_maps: true \ 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/tasks.py b/tasks.py new file mode 100644 index 0000000..9c75e5a --- /dev/null +++ b/tasks.py @@ -0,0 +1,44 @@ +"""Invoke tasks for building the InvenTree mobile app.""" + +import os +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.""" + c.run("fvm flutter clean") + +@task +def update(c): + """Update flutter dependencies.""" + c.run("flutter pub get") + +@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 {l10_dir} && {python} collect_translations.py") + + +@task(pre=[clean, update, translate]) +def ios(c): + """Build iOS app in release configuration.""" + 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("fvm flutter build appbundle --release --no-tree-shake-icons") diff --git a/test/api_test.dart b/test/api_test.dart new file mode 100644 index 0000000..f19dbf4 --- /dev/null +++ b/test/api_test.dart @@ -0,0 +1,124 @@ +/* + * Unit tests for the InvenTree API code + */ + +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 { + await setupServerProfile(select: true); + + // Ensure the profile is selected + assert( + !await UserProfileDBManager().selectProfileByName("Missing Profile"), + ); + assert(await UserProfileDBManager().selectProfileByName(testServerName)); + }); + + 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 setupServerProfile(); + + profile.server = "http://localhost:5555"; + + bool result = await api.connectToServer(profile); + assert(!result); + + debugContains("SocketException at"); + + // Test incorrect login details + profile.server = testServerAddress; + + final response = await api.fetchToken(profile, "baduser", "badpassword"); + assert(!response.successful()); + + debugContains("Token request failed"); + + 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(); + + 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(); + + 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(testServerAddress)); + + assert(api.hasToken); + assert(api.isConnected()); + assert(!api.isConnecting()); + assert(api.checkConnection()); + }); + + test("Version Checks", () async { + // Test server version information + var api = InvenTreeAPI(); + + final profile = await setupServerProfile(fetchToken: true); + assert(await api.connectToServer(profile)); + + // Check supported functions + assert(api.apiVersion >= 50); + assert(api.serverInstance.isNotEmpty); + assert(api.serverVersion.isNotEmpty); + + // Ensure we can have user role data + assert(api.roles.isNotEmpty); + + // Check available permissions + assert(api.checkRole("part", "change")); + assert(api.checkRole("stock", "delete")); + assert(!api.checkRole("part", "weirdpermission")); + assert(api.checkRole("blah", "bloo")); + + debugContains("Received token from server"); + debugContains("showSnackIcon: 'Connected to Server'"); + }); + }); +} diff --git a/test/barcode_test.dart b/test/barcode_test.dart new file mode 100644 index 0000000..fc732a1 --- /dev/null +++ b/test/barcode_test.dart @@ -0,0 +1,173 @@ +/* + * Unit testing for barcode scanning functionality. + * + * As the unit testing framework cannot really "scan" barcode data, + * we will mock the scanned data by passing raw "barcode" data to the scanning framework. + */ + +import "package:flutter_test/flutter_test.dart"; + +import "package:inventree/api.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"; + +import "setup.dart"; + +void main() { + setupTestEnv(); + + // Connect to the server + setUpAll(() async { + await connectToTestServer(); + }); + + setUp(() async { + // Clear the debug log + clearDebugMessage(); + }); + + group("Test BarcodeScanHandler:", () { + // Tests for scanning a "generic" barcode + + var handler = BarcodeScanHandler(); + + test("Empty Barcode", () async { + // Handle an 'empty' barcode + await handler.processBarcode(""); + + debugContains("Scanned barcode data: ''"); + debugContains("showSnackIcon: 'Barcode scan error'"); + + assert(debugMessageCount() == 2); + }); + + test("Junk Data", () async { + // test scanning 'junk' data + + await handler.processBarcode("abcdefg"); + + debugContains("Scanned barcode data: 'abcdefg'"); + debugContains("showSnackIcon: 'No match for barcode'"); + }); + + test("Invalid StockLocation", () async { + // Scan an invalid stock location + await handler.processBarcode('{"stocklocation": 999999}'); + + debugContains("Scanned barcode data: '{\"stocklocation\": 999999}'"); + debugContains("showSnackIcon: 'No match for barcode'"); + assert(debugMessageCount() == 3); + }); + }); + + group("Test StockItemScanIntoLocationHandler:", () { + // Tests for scanning a stock item into a location + + test("Scan Into Location", () async { + final item = await InvenTreeStockItem().get(1) as InvenTreeStockItem?; + assert(item != null); + + assert(item!.pk == 1); + + var handler = StockItemScanIntoLocationHandler(item!); + + await handler.processBarcode('{"stocklocation": 7}'); + // Check the location has been updated + await item.reload(); + assert(item.locationId == 7); + + debugContains("Scanned stock location 7"); + + // Scan into a new location + await handler.processBarcode('{"stocklocation": 1}'); + await item.reload(); + assert(item.locationId == 1); + }); + }); + + group("Test StockLocationScanInItemsHandler:", () { + // Tests for scanning items into a stock location + + test("Scan In Items", () async { + final location = + await InvenTreeStockLocation().get(1) as InvenTreeStockLocation?; + + assert(location != null); + assert(location!.pk == 1); + + var handler = StockLocationScanInItemsHandler(location!); + + // Scan multiple items into this location + for (int id in [1, 2, 11]) { + await handler.processBarcode('{"stockitem": ${id}}'); + + var item = await InvenTreeStockItem().get(id) as InvenTreeStockItem?; + + assert(item != null); + assert(item!.pk == id); + assert(item!.locationId == 1); + } + }); + }); + + group("Test ScanParentLocationHandler:", () { + // Tests for scanning a location into a parent location + + test("Scan Parent", () async { + final location = + await InvenTreeStockLocation().get(7) as InvenTreeStockLocation?; + + assert(location != null); + assert(location!.pk == 7); + assert(location!.parentId == 4); + + var handler = ScanParentLocationHandler(location!); + + // Scan into new parent location + await handler.processBarcode('{"stocklocation": 1}'); + await location.reload(); + assert(location.parentId == 1); + + // Scan back into old parent location + await handler.processBarcode('{"stocklocation": 4}'); + await location.reload(); + assert(location.parentId == 4); + + debugContains("showSnackIcon: 'Scanned into location'"); + }); + }); + + group("Test PartBarcodes:", () { + // Assign a custom barcode to a Part instance + test("Assign Barcode", () async { + // Unlink barcode first + await InvenTreeAPI().unlinkBarcode({"part": "2"}); + + final part = await InvenTreePart().get(2) as InvenTreePart?; + + assert(part != null); + assert(part!.pk == 2); + + // Should have a "null" barcode + assert(part!.customBarcode.isEmpty); + + // Assign custom barcode data to the part + await InvenTreeAPI().linkBarcode({"part": "2", "barcode": "xyz-123"}); + + await part!.reload(); + assert(part.customBarcode.isNotEmpty); + + // Check we can de-register a barcode also + // Unlink barcode first + await InvenTreeAPI().unlinkBarcode({"part": "2"}); + + await part.reload(); + assert(part.customBarcode.isEmpty); + }); + }); +} diff --git a/test/fixtures/barcodes/test_sheet.png b/test/fixtures/barcodes/test_sheet.png new file mode 100644 index 0000000..026a5a5 Binary files /dev/null and b/test/fixtures/barcodes/test_sheet.png differ diff --git a/test/models_test.dart b/test/models_test.dart new file mode 100644 index 0000000..5c70949 --- /dev/null +++ b/test/models_test.dart @@ -0,0 +1,128 @@ +/* + * Unit tests for accessing various model classes via the API + */ + +import "package:test/test.dart"; + +import "package:inventree/api.dart"; +import "package:inventree/inventree/model.dart"; +import "package:inventree/inventree/part.dart"; + +import "setup.dart"; + +void main() { + setupTestEnv(); + + setUp(() async { + await connectToTestServer(); + }); + + 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 { + assert(InvenTreePart().URL == "part/"); + }); + + test("List Parts", () async { + List results; + + // List *all* parts + results = await InvenTreePart().list(); + expect(results.length, equals(14)); + + // List with active filter + results = await InvenTreePart().list(filters: {"active": "true"}); + expect(results.length, greaterThanOrEqualTo(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); + }); + + 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); + + APIResponse? response; + + if (result != null) { + InvenTreePart part = result as InvenTreePart; + assert(part.name == "M2x4 LPHS"); + + // Change the name to something else + + response = await part.update(values: {"name": "Woogle"}); + + assert(response.isValid()); + assert(response.statusCode == 200); + + assert(await part.reload()); + assert(part.name == "Woogle"); + + // And change it back again + response = await part.update(values: {"name": "M2x4 LPHS"}); + + assert(response.isValid()); + assert(response.statusCode == 200); + + assert(await part.reload()); + assert(part.name == "M2x4 LPHS"); + } + }); + }); +} diff --git a/test/preferences_test.dart b/test/preferences_test.dart new file mode 100644 index 0000000..86cec3d --- /dev/null +++ b/test/preferences_test.dart @@ -0,0 +1,67 @@ +/* + * Unit tests for the preferences manager + */ + +import "package:flutter_test/flutter_test.dart"; +import "package:inventree/preferences.dart"; + +import "setup.dart"; + +void main() { + setupTestEnv(); + + 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"), + ); + }); + + test("Booleans", () async { + // Tests for boolean values + + await InvenTreeSettingsManager().removeValue("chicken"); + + // Use default values when a setting does not exist + assert(await InvenTreeSettingsManager().getBool("chicken", true) == true); + assert( + await InvenTreeSettingsManager().getBool("chicken", false) == false, + ); + + // Explicitly set to true + await InvenTreeSettingsManager().setValue("chicken", true); + assert( + await InvenTreeSettingsManager().getBool("chicken", false) == true, + ); + + // Explicitly set to false + await InvenTreeSettingsManager().setValue("chicken", false); + assert( + await InvenTreeSettingsManager().getBool("chicken", true) == false, + ); + }); + }); +} diff --git a/test/setup.dart b/test/setup.dart new file mode 100644 index 0000000..10e849b --- /dev/null +++ b/test/setup.dart @@ -0,0 +1,100 @@ +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(); +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 "."; + }); +} + +// 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)); +} diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart new file mode 100644 index 0000000..e1b49cf --- /dev/null +++ b/test/user_profile_test.dart @@ -0,0 +1,115 @@ +/* + * Unit tests for the API class + */ + +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 + // 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: testServerName, + server: testServerAddress, + 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()); + + expect(result, equals(false)); + + // Add a profile with a new name + result = await UserProfileDBManager().addProfile( + UserProfile(name: "Another Test Profile"), + ); + + expect(result, equals(true)); + + // Check that the number of protocols available is still the same + var profiles = await UserProfileDBManager().getAllProfiles(); + + 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 Server"); + 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(testServerName)); + expect(p.server, equals(testServerAddress)); + + 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)); + } + }); + }); +} diff --git a/test/wedge_scanner_test.dart b/test/wedge_scanner_test.dart new file mode 100644 index 0000000..bd98872 --- /dev/null +++ b/test/wedge_scanner_test.dart @@ -0,0 +1,25 @@ +import "package:flutter/material.dart"; +import "package:flutter/services.dart"; +import "package:flutter_test/flutter_test.dart"; +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())), + ); + + // Generate some keyboard data + await simulateKeyDownEvent(LogicalKeyboardKey.keyA); + await simulateKeyDownEvent(LogicalKeyboardKey.keyB); + await simulateKeyDownEvent(LogicalKeyboardKey.keyC); + await simulateKeyDownEvent(LogicalKeyboardKey.enter, character: "\n"); + + // Check debug output + debugContains("scanned: abc"); + debugContains("No match for barcode"); + debugContains("Server Error"); + }); +} 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 { + // }); }