mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-12-06 02:59:29 +00:00
Added feature for part IPN suggest with category prefixes (#1054)
* Erweiterungstätigkeiten zur IPN-Vorschlagsliste anhand von Präfixen aus den Kategorien * Umstellung Migrationen bzgl. Multi-Plattform-Support. Zunächst MySQL, SQLite Statements integrieren. * Postgre Statements integrieren * SQL-Formatierung in Migration verbessern * Erweitere IPN-Suggest um Bauteilbeschreibung. Die Implementierung berücksichtigt nun zusätzlich die Bauteilbeschreibung zu maximal 150 Zeichen Länge für die Generierung von IPN-Vorschlägen und Inkrementen. * Anpassungen aus Analyse vornehmen * IPN-Validierung für Parts überarbeiten * IPN-Vorschlagslogik um Konfiguration erweitert * Anpassungen aus phpstan Analyse * IPN-Vorschlagslogik erweitert und Bauteil-IPN vereindeutigt Die IPN-Logik wurde um eine Konfiguration zur automatischen Suffix-Anfügung und die Berücksichtigung von doppelten Beschreibungen bei Bedarf ergänzt. Zudem wurde das Datenmodell angepasst, um eine eindeutige Speicherung der IPN zu gewährleisten. * Regex-Konfigurationsmöglichkeit für IPN-Vorschläge einführen Die Einstellungen für die IPN-Vorschlagslogik wurden um eine Regex-Validierung und eine Hilfetext-Konfiguration erweitert. Tests und Änderungen an den Formularoptionen wurden implementiert. * Match range assert and form limits in suggestPartDigits * Keep existing behavior with autoAppend suffix by default * Show the regex hint in the browser validation notice. * Improved translations * Removed unnecessary service definition * Removed german comments --------- Co-authored-by: Marcel Diegelmann <marcel.diegelmann@gmail.com> Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
This commit is contained in:
parent
14a4f1f437
commit
771857e014
34 changed files with 2791 additions and 115 deletions
|
|
@ -106,6 +106,15 @@ export default class extends Controller {
|
|||
editor_div.classList.add(...new_classes.split(","));
|
||||
}
|
||||
|
||||
// Automatic synchronization of source input
|
||||
editor.model.document.on("change:data", () => {
|
||||
editor.updateSourceElement();
|
||||
|
||||
// Dispatch the input event for further treatment
|
||||
const event = new Event("input");
|
||||
this.element.dispatchEvent(event);
|
||||
});
|
||||
|
||||
//This return is important! Otherwise we get mysterious errors in the console
|
||||
//See: https://github.com/ckeditor/ckeditor5/issues/5897#issuecomment-628471302
|
||||
return editor;
|
||||
|
|
|
|||
250
assets/controllers/elements/ipn_suggestion_controller.js
Normal file
250
assets/controllers/elements/ipn_suggestion_controller.js
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
import { Controller } from "@hotwired/stimulus";
|
||||
import "../../css/components/autocomplete_bootstrap_theme.css";
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["input"];
|
||||
static values = {
|
||||
partId: Number,
|
||||
partCategoryId: Number,
|
||||
partDescription: String,
|
||||
suggestions: Object,
|
||||
commonSectionHeader: String, // Dynamic header for common Prefixes
|
||||
partIncrementHeader: String, // Dynamic header for new possible part increment
|
||||
suggestUrl: String,
|
||||
};
|
||||
|
||||
connect() {
|
||||
this.configureAutocomplete();
|
||||
this.watchCategoryChanges();
|
||||
this.watchDescriptionChanges();
|
||||
}
|
||||
|
||||
templates = {
|
||||
commonSectionHeader({ title, html }) {
|
||||
return html`
|
||||
<section class="aa-Source">
|
||||
<div class="aa-SourceHeader">
|
||||
<span class="aa-SourceHeaderTitle">${title}</span>
|
||||
<div class="aa-SourceHeaderLine"></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
},
|
||||
partIncrementHeader({ title, html }) {
|
||||
return html`
|
||||
<section class="aa-Source">
|
||||
<div class="aa-SourceHeader">
|
||||
<span class="aa-SourceHeaderTitle">${title}</span>
|
||||
<div class="aa-SourceHeaderLine"></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
},
|
||||
list({ html }) {
|
||||
return html`
|
||||
<ul class="aa-List" role="listbox"></ul>
|
||||
`;
|
||||
},
|
||||
item({ suggestion, description, html }) {
|
||||
return html`
|
||||
<li class="aa-Item" role="option" data-suggestion="${suggestion}" aria-selected="false">
|
||||
<div class="aa-ItemWrapper">
|
||||
<div class="aa-ItemContent">
|
||||
<div class="aa-ItemIcon aa-ItemIcon--noBorder">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="aa-ItemContentBody">
|
||||
<div class="aa-ItemContentTitle">${suggestion}</div>
|
||||
<div class="aa-ItemContentDescription">${description}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
`;
|
||||
},
|
||||
};
|
||||
|
||||
configureAutocomplete() {
|
||||
const inputField = this.inputTarget;
|
||||
const commonPrefixes = this.suggestionsValue.commonPrefixes || [];
|
||||
const prefixesPartIncrement = this.suggestionsValue.prefixesPartIncrement || [];
|
||||
const commonHeader = this.commonSectionHeaderValue;
|
||||
const partIncrementHeader = this.partIncrementHeaderValue;
|
||||
|
||||
if (!inputField || (!commonPrefixes.length && !prefixesPartIncrement.length)) return;
|
||||
|
||||
// Check whether the panel should be created at the update
|
||||
if (this.isPanelInitialized) {
|
||||
const existingPanel = inputField.parentNode.querySelector(".aa-Panel");
|
||||
if (existingPanel) {
|
||||
// Only remove the panel in the update phase
|
||||
|
||||
existingPanel.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Create panel
|
||||
const panel = document.createElement("div");
|
||||
panel.classList.add("aa-Panel");
|
||||
panel.style.display = "none";
|
||||
|
||||
// Create panel layout
|
||||
const panelLayout = document.createElement("div");
|
||||
panelLayout.classList.add("aa-PanelLayout", "aa-Panel--scrollable");
|
||||
|
||||
// Section for prefixes part increment
|
||||
if (prefixesPartIncrement.length) {
|
||||
const partIncrementSection = document.createElement("section");
|
||||
partIncrementSection.classList.add("aa-Source");
|
||||
|
||||
const partIncrementHeaderHtml = this.templates.partIncrementHeader({
|
||||
title: partIncrementHeader,
|
||||
html: String.raw,
|
||||
});
|
||||
partIncrementSection.innerHTML += partIncrementHeaderHtml;
|
||||
|
||||
const partIncrementList = document.createElement("ul");
|
||||
partIncrementList.classList.add("aa-List");
|
||||
partIncrementList.setAttribute("role", "listbox");
|
||||
|
||||
prefixesPartIncrement.forEach((prefix) => {
|
||||
const itemHTML = this.templates.item({
|
||||
suggestion: prefix.title,
|
||||
description: prefix.description,
|
||||
html: String.raw,
|
||||
});
|
||||
partIncrementList.innerHTML += itemHTML;
|
||||
});
|
||||
|
||||
partIncrementSection.appendChild(partIncrementList);
|
||||
panelLayout.appendChild(partIncrementSection);
|
||||
}
|
||||
|
||||
// Section for common prefixes
|
||||
if (commonPrefixes.length) {
|
||||
const commonSection = document.createElement("section");
|
||||
commonSection.classList.add("aa-Source");
|
||||
|
||||
const commonSectionHeader = this.templates.commonSectionHeader({
|
||||
title: commonHeader,
|
||||
html: String.raw,
|
||||
});
|
||||
commonSection.innerHTML += commonSectionHeader;
|
||||
|
||||
const commonList = document.createElement("ul");
|
||||
commonList.classList.add("aa-List");
|
||||
commonList.setAttribute("role", "listbox");
|
||||
|
||||
commonPrefixes.forEach((prefix) => {
|
||||
const itemHTML = this.templates.item({
|
||||
suggestion: prefix.title,
|
||||
description: prefix.description,
|
||||
html: String.raw,
|
||||
});
|
||||
commonList.innerHTML += itemHTML;
|
||||
});
|
||||
|
||||
commonSection.appendChild(commonList);
|
||||
panelLayout.appendChild(commonSection);
|
||||
}
|
||||
|
||||
panel.appendChild(panelLayout);
|
||||
inputField.parentNode.appendChild(panel);
|
||||
|
||||
inputField.addEventListener("focus", () => {
|
||||
panel.style.display = "block";
|
||||
});
|
||||
|
||||
inputField.addEventListener("blur", () => {
|
||||
setTimeout(() => {
|
||||
panel.style.display = "none";
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Selection of an item
|
||||
panelLayout.addEventListener("mousedown", (event) => {
|
||||
const target = event.target.closest("li");
|
||||
|
||||
if (target) {
|
||||
inputField.value = target.dataset.suggestion;
|
||||
panel.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
this.isPanelInitialized = true;
|
||||
};
|
||||
|
||||
watchCategoryChanges() {
|
||||
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
|
||||
const descriptionField = document.querySelector('[data-ipn-suggestion="descriptionField"]');
|
||||
this.previousCategoryId = Number(this.partCategoryIdValue);
|
||||
|
||||
if (categoryField) {
|
||||
categoryField.addEventListener("change", () => {
|
||||
const categoryId = Number(categoryField.value);
|
||||
const description = String(descriptionField?.value ?? '');
|
||||
|
||||
// Check whether the category has changed compared to the previous ID
|
||||
if (categoryId !== this.previousCategoryId) {
|
||||
this.fetchNewSuggestions(categoryId, description);
|
||||
this.previousCategoryId = categoryId;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
watchDescriptionChanges() {
|
||||
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
|
||||
const descriptionField = document.querySelector('[data-ipn-suggestion="descriptionField"]');
|
||||
this.previousDescription = String(this.partDescriptionValue);
|
||||
|
||||
if (descriptionField) {
|
||||
descriptionField.addEventListener("input", () => {
|
||||
const categoryId = Number(categoryField.value);
|
||||
const description = String(descriptionField?.value ?? '');
|
||||
|
||||
// Check whether the description has changed compared to the previous one
|
||||
if (description !== this.previousDescription) {
|
||||
this.fetchNewSuggestions(categoryId, description);
|
||||
this.previousDescription = description;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchNewSuggestions(categoryId, description) {
|
||||
const baseUrl = this.suggestUrlValue;
|
||||
const partId = this.partIdValue;
|
||||
const truncatedDescription = description.length > 150 ? description.substring(0, 150) : description;
|
||||
const encodedDescription = this.base64EncodeUtf8(truncatedDescription);
|
||||
const url = `${baseUrl}?partId=${partId}&categoryId=${categoryId}` + (description !== '' ? `&description=${encodedDescription}` : '');
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error when calling up the IPN-suggestions: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
this.suggestionsValue = data;
|
||||
this.configureAutocomplete();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Errors when loading the new IPN-suggestions:", error);
|
||||
});
|
||||
};
|
||||
|
||||
base64EncodeUtf8(text) {
|
||||
const utf8Bytes = new TextEncoder().encode(text);
|
||||
return btoa(String.fromCharCode(...utf8Bytes));
|
||||
};
|
||||
}
|
||||
|
|
@ -231,6 +231,16 @@ services:
|
|||
tags:
|
||||
- { name: 'doctrine.fixtures.purger_factory', alias: 'reset_autoincrement_purger' }
|
||||
|
||||
App\Repository\PartRepository:
|
||||
arguments:
|
||||
$translator: '@translator'
|
||||
tags: ['doctrine.repository_service']
|
||||
|
||||
App\EventSubscriber\UserSystem\PartUniqueIpnSubscriber:
|
||||
tags:
|
||||
- { name: doctrine.event_listener, event: onFlush, connection: default }
|
||||
|
||||
|
||||
# We are needing this service inside a migration, where only the container is injected. So we need to define it as public, to access it from the container.
|
||||
App\Services\UserSystem\PermissionPresetsHelper:
|
||||
public: true
|
||||
|
|
|
|||
|
|
@ -116,6 +116,16 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
|
|||
value should be handled as confidential data and not shared publicly.
|
||||
* `SHOW_PART_IMAGE_OVERLAY`: Set to 0 to disable the part image overlay, which appears if you hover over an image in the
|
||||
part image gallery
|
||||
* `IPN_SUGGEST_REGEX`: A global regular expression, that part IPNs have to fullfill. Enforce your own format for your users.
|
||||
* `IPN_SUGGEST_REGEX_HELP`: Define your own user help text for the Regex format specification.
|
||||
* `IPN_AUTO_APPEND_SUFFIX`: When enabled, an incremental suffix will be added to the user input when entering an existing
|
||||
* IPN again upon saving.
|
||||
* `IPN_SUGGEST_PART_DIGITS`: Defines the fixed number of digits used as the increment at the end of an IPN (Internal Part Number).
|
||||
IPN prefixes, maintained within part categories and their hierarchy, form the foundation for suggesting complete IPNs.
|
||||
These suggestions become accessible during IPN input of a part. The constant specifies the digits used to calculate and assign
|
||||
unique increments for parts within a category hierarchy, ensuring consistency and uniqueness in IPN generation.
|
||||
* `IPN_USE_DUPLICATE_DESCRIPTION`: When enabled, the part’s description is used to find existing parts with the same
|
||||
description and to determine the next available IPN by incrementing their numeric suffix for the suggestion list.
|
||||
|
||||
### E-Mail settings (all env only)
|
||||
|
||||
|
|
|
|||
307
migrations/Version20250325073036.php
Normal file
307
migrations/Version20250325073036.php
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
final class Version20250325073036 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add part_ipn_prefix column to categories table and remove unique constraint from parts table';
|
||||
}
|
||||
|
||||
public function mySQLUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE categories ADD COLUMN part_ipn_prefix VARCHAR(255) NOT NULL DEFAULT ''
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function mySQLDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE categories DROP part_ipn_prefix
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TEMPORARY TABLE __temp__categories AS
|
||||
SELECT
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
FROM categories
|
||||
SQL);
|
||||
|
||||
$this->addSql('DROP TABLE categories');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
parent_id INTEGER DEFAULT NULL,
|
||||
id_preview_attachment INTEGER DEFAULT NULL,
|
||||
partname_hint CLOB NOT NULL,
|
||||
partname_regex CLOB NOT NULL,
|
||||
part_ipn_prefix VARCHAR(255) DEFAULT '' NOT NULL,
|
||||
disable_footprints BOOLEAN NOT NULL,
|
||||
disable_manufacturers BOOLEAN NOT NULL,
|
||||
disable_autodatasheets BOOLEAN NOT NULL,
|
||||
disable_properties BOOLEAN NOT NULL,
|
||||
default_description CLOB NOT NULL,
|
||||
default_comment CLOB NOT NULL,
|
||||
comment CLOB NOT NULL,
|
||||
not_selectable BOOLEAN NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
alternative_names CLOB DEFAULT NULL,
|
||||
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
|
||||
eda_info_invisible BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
|
||||
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
|
||||
CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
|
||||
CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
|
||||
)
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
INSERT INTO categories (
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
) SELECT
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
FROM __temp__categories
|
||||
SQL);
|
||||
|
||||
$this->addSql('DROP TABLE __temp__categories');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX IDX_3AF34668727ACA70 ON categories (parent_id)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX IDX_3AF34668EA7100A1 ON categories (id_preview_attachment)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX category_idx_name ON categories (name)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX category_idx_parent_name ON categories (parent_id, name)
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TEMPORARY TABLE __temp__categories AS
|
||||
SELECT
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
FROM categories
|
||||
SQL);
|
||||
|
||||
$this->addSql('DROP TABLE categories');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
parent_id INTEGER DEFAULT NULL,
|
||||
id_preview_attachment INTEGER DEFAULT NULL,
|
||||
partname_hint CLOB NOT NULL,
|
||||
partname_regex CLOB NOT NULL,
|
||||
disable_footprints BOOLEAN NOT NULL,
|
||||
disable_manufacturers BOOLEAN NOT NULL,
|
||||
disable_autodatasheets BOOLEAN NOT NULL,
|
||||
disable_properties BOOLEAN NOT NULL,
|
||||
default_description CLOB NOT NULL,
|
||||
default_comment CLOB NOT NULL,
|
||||
comment CLOB NOT NULL,
|
||||
not_selectable BOOLEAN NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
alternative_names CLOB DEFAULT NULL,
|
||||
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
|
||||
eda_info_invisible BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
|
||||
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
|
||||
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
|
||||
CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
|
||||
CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
|
||||
)
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
INSERT INTO categories (
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
) SELECT
|
||||
id,
|
||||
parent_id,
|
||||
id_preview_attachment,
|
||||
partname_hint,
|
||||
partname_regex,
|
||||
disable_footprints,
|
||||
disable_manufacturers,
|
||||
disable_autodatasheets,
|
||||
disable_properties,
|
||||
default_description,
|
||||
default_comment,
|
||||
comment,
|
||||
not_selectable,
|
||||
name,
|
||||
last_modified,
|
||||
datetime_added,
|
||||
alternative_names,
|
||||
eda_info_reference_prefix,
|
||||
eda_info_invisible,
|
||||
eda_info_exclude_from_bom,
|
||||
eda_info_exclude_from_board,
|
||||
eda_info_exclude_from_sim,
|
||||
eda_info_kicad_symbol
|
||||
FROM __temp__categories
|
||||
SQL);
|
||||
|
||||
$this->addSql('DROP TABLE __temp__categories');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX IDX_3AF34668727ACA70 ON categories (parent_id)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX IDX_3AF34668EA7100A1 ON categories (id_preview_attachment)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX category_idx_name ON categories (name)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX category_idx_parent_name ON categories (parent_id, name)
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function postgreSQLUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE categories ADD part_ipn_prefix VARCHAR(255) DEFAULT '' NOT NULL
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function postgreSQLDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE "categories" DROP part_ipn_prefix
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ use App\Services\Parts\PartLotWithdrawAddHelper;
|
|||
use App\Services\Parts\PricedetailHelper;
|
||||
use App\Services\ProjectSystem\ProjectBuildPartHelper;
|
||||
use App\Settings\BehaviorSettings\PartInfoSettings;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
|
|
@ -74,6 +75,7 @@ final class PartController extends AbstractController
|
|||
private readonly EntityManagerInterface $em,
|
||||
private readonly EventCommentHelper $commentHelper,
|
||||
private readonly PartInfoSettings $partInfoSettings,
|
||||
private readonly IpnSuggestSettings $ipnSuggestSettings,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -444,10 +446,13 @@ final class PartController extends AbstractController
|
|||
$template = 'parts/edit/update_from_ip.html.twig';
|
||||
}
|
||||
|
||||
$partRepository = $this->em->getRepository(Part::class);
|
||||
|
||||
return $this->render(
|
||||
$template,
|
||||
[
|
||||
'part' => $new_part,
|
||||
'ipnSuggestions' => $partRepository->autoCompleteIpn($data, $data->getDescription(), $this->ipnSuggestSettings->suggestPartDigits),
|
||||
'form' => $form,
|
||||
'merge_old_name' => $merge_infos['tname_before'] ?? null,
|
||||
'merge_other' => $merge_infos['other_part'] ?? null,
|
||||
|
|
@ -457,7 +462,6 @@ final class PartController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
#[Route(path: '/{id}/add_withdraw', name: 'part_add_withdraw', methods: ['POST'])]
|
||||
public function withdrawAddHandler(Part $part, Request $request, EntityManagerInterface $em, PartLotWithdrawAddHelper $withdrawAddHelper): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Parameters\AbstractParameter;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use App\Entity\Attachments\Attachment;
|
||||
use App\Entity\Parts\Category;
|
||||
|
|
@ -60,8 +61,11 @@ use Symfony\Component\Serializer\Serializer;
|
|||
#[Route(path: '/typeahead')]
|
||||
class TypeaheadController extends AbstractController
|
||||
{
|
||||
public function __construct(protected AttachmentURLGenerator $urlGenerator, protected Packages $assets)
|
||||
{
|
||||
public function __construct(
|
||||
protected AttachmentURLGenerator $urlGenerator,
|
||||
protected Packages $assets,
|
||||
protected IpnSuggestSettings $ipnSuggestSettings,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route(path: '/builtInResources/search', name: 'typeahead_builtInRessources')]
|
||||
|
|
@ -183,4 +187,30 @@ class TypeaheadController extends AbstractController
|
|||
|
||||
return new JsonResponse($data, Response::HTTP_OK, [], true);
|
||||
}
|
||||
|
||||
#[Route(path: '/parts/ipn-suggestions', name: 'ipn_suggestions', methods: ['GET'])]
|
||||
public function ipnSuggestions(
|
||||
Request $request,
|
||||
EntityManagerInterface $entityManager
|
||||
): JsonResponse {
|
||||
$partId = $request->query->get('partId');
|
||||
if ($partId === '0' || $partId === 'undefined' || $partId === 'null') {
|
||||
$partId = null;
|
||||
}
|
||||
$categoryId = $request->query->getInt('categoryId');
|
||||
$description = base64_decode($request->query->getString('description'), true);
|
||||
|
||||
/** @var Part $part */
|
||||
$part = $partId !== null ? $entityManager->getRepository(Part::class)->find($partId) : new Part();
|
||||
/** @var Category|null $category */
|
||||
$category = $entityManager->getRepository(Category::class)->find($categoryId);
|
||||
|
||||
$clonedPart = clone $part;
|
||||
$clonedPart->setCategory($category);
|
||||
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $description, $this->ipnSuggestSettings->suggestPartDigits);
|
||||
|
||||
return new JsonResponse($ipnSuggestions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,13 @@ class Category extends AbstractPartsContainingDBElement
|
|||
#[ORM\Column(type: Types::TEXT)]
|
||||
protected string $partname_regex = '';
|
||||
|
||||
/**
|
||||
* @var string The prefix for ipn generation for created parts in this category.
|
||||
*/
|
||||
#[Groups(['full', 'import', 'category:read', 'category:write'])]
|
||||
#[ORM\Column(type: Types::STRING, length: 255, nullable: false, options: ['default' => ''])]
|
||||
protected string $part_ipn_prefix = '';
|
||||
|
||||
/**
|
||||
* @var bool Set to true, if the footprints should be disabled for parts this category (not implemented yet).
|
||||
*/
|
||||
|
|
@ -225,6 +232,16 @@ class Category extends AbstractPartsContainingDBElement
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getPartIpnPrefix(): string
|
||||
{
|
||||
return $this->part_ipn_prefix;
|
||||
}
|
||||
|
||||
public function setPartIpnPrefix(string $part_ipn_prefix): void
|
||||
{
|
||||
$this->part_ipn_prefix = $part_ipn_prefix;
|
||||
}
|
||||
|
||||
public function isDisableFootprints(): bool
|
||||
{
|
||||
return $this->disable_footprints;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
|
@ -75,7 +74,6 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|||
* @extends AttachmentContainingDBElement<PartAttachment>
|
||||
* @template-use ParametersTrait<PartParameter>
|
||||
*/
|
||||
#[UniqueEntity(fields: ['ipn'], message: 'part.ipn.must_be_unique')]
|
||||
#[ORM\Entity(repositoryClass: PartRepository::class)]
|
||||
#[ORM\EntityListeners([TreeCacheInvalidationListener::class])]
|
||||
#[ORM\Table('`parts`')]
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use App\Validator\Constraints\UniquePartIpnConstraint;
|
||||
|
||||
/**
|
||||
* Advanced properties of a part, not related to a more specific group.
|
||||
|
|
@ -65,6 +66,7 @@ trait AdvancedPropertyTrait
|
|||
#[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])]
|
||||
#[ORM\Column(type: Types::STRING, length: 100, unique: true, nullable: true)]
|
||||
#[Length(max: 100)]
|
||||
#[UniquePartIpnConstraint]
|
||||
protected ?string $ipn = null;
|
||||
|
||||
/**
|
||||
|
|
|
|||
97
src/EventSubscriber/UserSystem/PartUniqueIpnSubscriber.php
Normal file
97
src/EventSubscriber/UserSystem/PartUniqueIpnSubscriber.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\EventSubscriber\UserSystem;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
|
||||
class PartUniqueIpnSubscriber implements EventSubscriber
|
||||
{
|
||||
public function __construct(
|
||||
private IpnSuggestSettings $ipnSuggestSettings
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
Events::onFlush,
|
||||
];
|
||||
}
|
||||
|
||||
public function onFlush(OnFlushEventArgs $args): void
|
||||
{
|
||||
if (!$this->ipnSuggestSettings->autoAppendSuffix) {
|
||||
return;
|
||||
}
|
||||
|
||||
$em = $args->getObjectManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
$meta = $em->getClassMetadata(Part::class);
|
||||
|
||||
// Collect all IPNs already reserved in the current flush (so new entities do not collide with each other)
|
||||
$reservedIpns = [];
|
||||
|
||||
// Helper to assign a collision-free IPN for a Part entity
|
||||
$ensureUnique = function (Part $part) use ($em, $uow, $meta, &$reservedIpns) {
|
||||
$ipn = $part->getIpn();
|
||||
if ($ipn === null || $ipn === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check against IPNs already reserved in the current flush (except itself)
|
||||
$originalIpn = $ipn;
|
||||
$candidate = $originalIpn;
|
||||
$increment = 1;
|
||||
|
||||
$conflicts = function (string $candidate) use ($em, $part, $reservedIpns) {
|
||||
// Collision within the current flush session?
|
||||
if (isset($reservedIpns[$candidate]) && $reservedIpns[$candidate] !== $part) {
|
||||
return true;
|
||||
}
|
||||
// Collision with an existing DB row?
|
||||
$existing = $em->getRepository(Part::class)->findOneBy(['ipn' => $candidate]);
|
||||
return $existing !== null && $existing->getId() !== $part->getId();
|
||||
};
|
||||
|
||||
while ($conflicts($candidate)) {
|
||||
$candidate = $originalIpn . '_' . $increment;
|
||||
$increment++;
|
||||
}
|
||||
|
||||
if ($candidate !== $ipn) {
|
||||
$before = $part->getIpn();
|
||||
$part->setIpn($candidate);
|
||||
|
||||
// Recompute the change set so Doctrine writes the change
|
||||
$uow->recomputeSingleEntityChangeSet($meta, $part);
|
||||
$reservedIpns[$candidate] = $part;
|
||||
|
||||
// If the old IPN was reserved already, clean it up
|
||||
if ($before !== null && isset($reservedIpns[$before]) && $reservedIpns[$before] === $part) {
|
||||
unset($reservedIpns[$before]);
|
||||
}
|
||||
} else {
|
||||
// Candidate unchanged, but reserve it so subsequent entities see it
|
||||
$reservedIpns[$candidate] = $part;
|
||||
}
|
||||
};
|
||||
|
||||
// 1) Iterate over new entities
|
||||
foreach ($uow->getScheduledEntityInsertions() as $entity) {
|
||||
if ($entity instanceof Part) {
|
||||
$ensureUnique($entity);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Iterate over updates (if IPN changed, ensure uniqueness again)
|
||||
foreach ($uow->getScheduledEntityUpdates() as $entity) {
|
||||
if ($entity instanceof Part) {
|
||||
$ensureUnique($entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +84,17 @@ class CategoryAdminForm extends BaseEntityAdminForm
|
|||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
|
||||
$builder->add('part_ipn_prefix', TextType::class, [
|
||||
'required' => false,
|
||||
'empty_data' => '',
|
||||
'label' => 'category.edit.part_ipn_prefix',
|
||||
'help' => 'category.edit.part_ipn_prefix.help',
|
||||
'attr' => [
|
||||
'placeholder' => 'category.edit.part_ipn_prefix.placeholder',
|
||||
],
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
|
||||
$builder->add('default_description', RichTextEditorType::class, [
|
||||
'required' => false,
|
||||
'empty_data' => '',
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use App\Form\Type\StructuralEntityType;
|
|||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||
use App\Services\LogSystem\EventCommentNeededHelper;
|
||||
use App\Services\LogSystem\EventCommentType;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
|
|
@ -57,8 +58,12 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|||
|
||||
class PartBaseType extends AbstractType
|
||||
{
|
||||
public function __construct(protected Security $security, protected UrlGeneratorInterface $urlGenerator, protected EventCommentNeededHelper $event_comment_needed_helper)
|
||||
{
|
||||
public function __construct(
|
||||
protected Security $security,
|
||||
protected UrlGeneratorInterface $urlGenerator,
|
||||
protected EventCommentNeededHelper $event_comment_needed_helper,
|
||||
protected IpnSuggestSettings $ipnSuggestSettings,
|
||||
) {
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
|
|
@ -70,6 +75,39 @@ class PartBaseType extends AbstractType
|
|||
/** @var PartDetailDTO|null $dto */
|
||||
$dto = $options['info_provider_dto'];
|
||||
|
||||
$descriptionAttr = [
|
||||
'placeholder' => 'part.edit.description.placeholder',
|
||||
'rows' => 2,
|
||||
];
|
||||
|
||||
if ($this->ipnSuggestSettings->useDuplicateDescription) {
|
||||
// Only add attribute when duplicate description feature is enabled
|
||||
$descriptionAttr['data-ipn-suggestion'] = 'descriptionField';
|
||||
}
|
||||
|
||||
$ipnAttr = [
|
||||
'class' => 'ipn-suggestion-field',
|
||||
'data-elements--ipn-suggestion-target' => 'input',
|
||||
'autocomplete' => 'off',
|
||||
];
|
||||
|
||||
if ($this->ipnSuggestSettings->regex !== null && $this->ipnSuggestSettings->regex !== '') {
|
||||
$ipnAttr['pattern'] = $this->ipnSuggestSettings->regex;
|
||||
$ipnAttr['placeholder'] = $this->ipnSuggestSettings->regex;
|
||||
$ipnAttr['title'] = $this->ipnSuggestSettings->regexHelp;
|
||||
}
|
||||
|
||||
$ipnOptions = [
|
||||
'required' => false,
|
||||
'empty_data' => null,
|
||||
'label' => 'part.edit.ipn',
|
||||
'attr' => $ipnAttr,
|
||||
];
|
||||
|
||||
if (isset($ipnAttr['pattern']) && $this->ipnSuggestSettings->regexHelp !== null && $this->ipnSuggestSettings->regexHelp !== '') {
|
||||
$ipnOptions['help'] = $this->ipnSuggestSettings->regexHelp;
|
||||
}
|
||||
|
||||
//Common section
|
||||
$builder
|
||||
->add('name', TextType::class, [
|
||||
|
|
@ -84,10 +122,7 @@ class PartBaseType extends AbstractType
|
|||
'empty_data' => '',
|
||||
'label' => 'part.edit.description',
|
||||
'mode' => 'markdown-single_line',
|
||||
'attr' => [
|
||||
'placeholder' => 'part.edit.description.placeholder',
|
||||
'rows' => 2,
|
||||
],
|
||||
'attr' => $descriptionAttr,
|
||||
])
|
||||
->add('minAmount', SIUnitType::class, [
|
||||
'attr' => [
|
||||
|
|
@ -105,6 +140,9 @@ class PartBaseType extends AbstractType
|
|||
'disable_not_selectable' => true,
|
||||
//Do not require category for new parts, so that the user must select the category by hand and cannot forget it (the requirement is handled by the constraint in the entity)
|
||||
'required' => !$new_part,
|
||||
'attr' => [
|
||||
'data-ipn-suggestion' => 'categoryField',
|
||||
]
|
||||
])
|
||||
->add('footprint', StructuralEntityType::class, [
|
||||
'class' => Footprint::class,
|
||||
|
|
@ -178,11 +216,7 @@ class PartBaseType extends AbstractType
|
|||
'disable_not_selectable' => true,
|
||||
'label' => 'part.edit.partCustomState',
|
||||
])
|
||||
->add('ipn', TextType::class, [
|
||||
'required' => false,
|
||||
'empty_data' => null,
|
||||
'label' => 'part.edit.ipn',
|
||||
]);
|
||||
->add('ipn', TextType::class, $ipnOptions);
|
||||
|
||||
//Comment section
|
||||
$builder->add('comment', RichTextEditorType::class, [
|
||||
|
|
|
|||
|
|
@ -22,17 +22,35 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @extends NamedDBElementRepository<Part>
|
||||
*/
|
||||
class PartRepository extends NamedDBElementRepository
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
private IpnSuggestSettings $ipnSuggestSettings;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TranslatorInterface $translator,
|
||||
IpnSuggestSettings $ipnSuggestSettings,
|
||||
) {
|
||||
parent::__construct($em, $em->getClassMetadata(Part::class));
|
||||
|
||||
$this->translator = $translator;
|
||||
$this->ipnSuggestSettings = $ipnSuggestSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summed up instock of all parts (only parts without a measurement unit).
|
||||
*
|
||||
|
|
@ -84,8 +102,7 @@ class PartRepository extends NamedDBElementRepository
|
|||
->where('ILIKE(part.name, :query) = TRUE')
|
||||
->orWhere('ILIKE(part.description, :query) = TRUE')
|
||||
->orWhere('ILIKE(category.name, :query) = TRUE')
|
||||
->orWhere('ILIKE(footprint.name, :query) = TRUE')
|
||||
;
|
||||
->orWhere('ILIKE(footprint.name, :query) = TRUE');
|
||||
|
||||
$qb->setParameter('query', '%'.$query.'%');
|
||||
|
||||
|
|
@ -94,4 +111,240 @@ class PartRepository extends NamedDBElementRepository
|
|||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides IPN (Internal Part Number) suggestions for a given part based on its category, description,
|
||||
* and configured autocomplete digit length.
|
||||
*
|
||||
* This function generates suggestions for common prefixes and incremented prefixes based on
|
||||
* the part's current category and its hierarchy. If the part is unsaved, a default "n.a." prefix is returned.
|
||||
*
|
||||
* @param Part $part The part for which autocomplete suggestions are generated.
|
||||
* @param string $description description to assist in generating suggestions.
|
||||
* @param int $suggestPartDigits The number of digits used in autocomplete increments.
|
||||
*
|
||||
* @return array An associative array containing the following keys:
|
||||
* - 'commonPrefixes': List of common prefixes found for the part.
|
||||
* - 'prefixesPartIncrement': Increments for the generated prefixes, including hierarchical prefixes.
|
||||
*/
|
||||
public function autoCompleteIpn(Part $part, string $description, int $suggestPartDigits): array
|
||||
{
|
||||
$category = $part->getCategory();
|
||||
$ipnSuggestions = ['commonPrefixes' => [], 'prefixesPartIncrement' => []];
|
||||
|
||||
if (strlen($description) > 150) {
|
||||
$description = substr($description, 0, 150);
|
||||
}
|
||||
|
||||
if ($description !== '' && $this->ipnSuggestSettings->useDuplicateDescription) {
|
||||
// Check if the description is already used in another part,
|
||||
|
||||
$suggestionByDescription = $this->getIpnSuggestByDescription($description);
|
||||
|
||||
if ($suggestionByDescription !== null && $suggestionByDescription !== $part->getIpn() && $part->getIpn() !== null && $part->getIpn() !== '') {
|
||||
$ipnSuggestions['prefixesPartIncrement'][] = [
|
||||
'title' => $part->getIpn(),
|
||||
'description' => $this->translator->trans('part.edit.tab.advanced.ipn.prefix.description.current-increment')
|
||||
];
|
||||
}
|
||||
|
||||
if ($suggestionByDescription !== null) {
|
||||
$ipnSuggestions['prefixesPartIncrement'][] = [
|
||||
'title' => $suggestionByDescription,
|
||||
'description' => $this->translator->trans('part.edit.tab.advanced.ipn.prefix.description.increment')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the category and ensure it's an instance of Category
|
||||
if ($category instanceof Category) {
|
||||
$currentPath = $category->getPartIpnPrefix();
|
||||
$directIpnPrefixEmpty = $category->getPartIpnPrefix() === '';
|
||||
$currentPath = $currentPath === '' ? 'n.a.' : $currentPath;
|
||||
|
||||
$increment = $this->generateNextPossiblePartIncrement($currentPath, $part, $suggestPartDigits);
|
||||
|
||||
$ipnSuggestions['commonPrefixes'][] = [
|
||||
'title' => $currentPath . '-',
|
||||
'description' => $directIpnPrefixEmpty ? $this->translator->trans('part.edit.tab.advanced.ipn.prefix_empty.direct_category', ['%name%' => $category->getName()]) : $this->translator->trans('part.edit.tab.advanced.ipn.prefix.direct_category')
|
||||
];
|
||||
|
||||
$ipnSuggestions['prefixesPartIncrement'][] = [
|
||||
'title' => $currentPath . '-' . $increment,
|
||||
'description' => $directIpnPrefixEmpty ? $this->translator->trans('part.edit.tab.advanced.ipn.prefix_empty.direct_category', ['%name%' => $category->getName()]) : $this->translator->trans('part.edit.tab.advanced.ipn.prefix.direct_category.increment')
|
||||
];
|
||||
|
||||
// Process parent categories
|
||||
$parentCategory = $category->getParent();
|
||||
|
||||
while ($parentCategory instanceof Category) {
|
||||
// Prepend the parent category's prefix to the current path
|
||||
$currentPath = $parentCategory->getPartIpnPrefix() . '-' . $currentPath;
|
||||
$currentPath = $parentCategory->getPartIpnPrefix() === '' ? 'n.a.-' . $currentPath : $currentPath;
|
||||
|
||||
$ipnSuggestions['commonPrefixes'][] = [
|
||||
'title' => $currentPath . '-',
|
||||
'description' => $this->translator->trans('part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment')
|
||||
];
|
||||
|
||||
$increment = $this->generateNextPossiblePartIncrement($currentPath, $part, $suggestPartDigits);
|
||||
|
||||
$ipnSuggestions['prefixesPartIncrement'][] = [
|
||||
'title' => $currentPath . '-' . $increment,
|
||||
'description' => $this->translator->trans('part.edit.tab.advanced.ipn.prefix.hierarchical.increment')
|
||||
];
|
||||
|
||||
// Move to the next parent category
|
||||
$parentCategory = $parentCategory->getParent();
|
||||
}
|
||||
} elseif ($part->getID() === null) {
|
||||
$ipnSuggestions['commonPrefixes'][] = [
|
||||
'title' => 'n.a.',
|
||||
'description' => $this->translator->trans('part.edit.tab.advanced.ipn.prefix.not_saved')
|
||||
];
|
||||
}
|
||||
|
||||
return $ipnSuggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests the next IPN (Internal Part Number) based on the provided part description.
|
||||
*
|
||||
* Searches for parts with similar descriptions and retrieves their existing IPNs to calculate the next suggestion.
|
||||
* Returns null if the description is empty or no suggestion can be generated.
|
||||
*
|
||||
* @param string $description The part description to search for.
|
||||
*
|
||||
* @return string|null The suggested IPN, or null if no suggestion is possible.
|
||||
*
|
||||
* @throws NonUniqueResultException
|
||||
*/
|
||||
public function getIpnSuggestByDescription(string $description): ?string
|
||||
{
|
||||
if ($description === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('part');
|
||||
|
||||
$qb->select('part')
|
||||
->where('part.description LIKE :descriptionPattern')
|
||||
->setParameter('descriptionPattern', $description.'%')
|
||||
->orderBy('part.id', 'ASC');
|
||||
|
||||
$partsBySameDescription = $qb->getQuery()->getResult();
|
||||
$givenIpnsWithSameDescription = [];
|
||||
|
||||
foreach ($partsBySameDescription as $part) {
|
||||
if ($part->getIpn() === null || $part->getIpn() === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$givenIpnsWithSameDescription[] = $part->getIpn();
|
||||
}
|
||||
|
||||
return $this->getNextIpnSuggestion($givenIpnsWithSameDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the next possible increment for a part within a given category, while ensuring uniqueness.
|
||||
*
|
||||
* This method calculates the next available increment for a part's identifier (`ipn`) based on the current path
|
||||
* and the number of digits specified for the autocomplete feature. It ensures that the generated identifier
|
||||
* aligns with the expected length and does not conflict with already existing identifiers in the same category.
|
||||
*
|
||||
* @param string $currentPath The base path or prefix for the part's identifier.
|
||||
* @param Part $currentPart The part entity for which the increment is being generated.
|
||||
* @param int $suggestPartDigits The number of digits reserved for the increment.
|
||||
*
|
||||
* @return string The next possible increment as a zero-padded string.
|
||||
*
|
||||
* @throws NonUniqueResultException If the query returns non-unique results.
|
||||
* @throws NoResultException If the query fails to return a result.
|
||||
*/
|
||||
private function generateNextPossiblePartIncrement(string $currentPath, Part $currentPart, int $suggestPartDigits): string
|
||||
{
|
||||
$qb = $this->createQueryBuilder('part');
|
||||
|
||||
$expectedLength = strlen($currentPath) + 1 + $suggestPartDigits; // Path + '-' + $suggestPartDigits digits
|
||||
|
||||
// Fetch all parts in the given category, sorted by their ID in ascending order
|
||||
$qb->select('part')
|
||||
->where('part.ipn LIKE :ipnPattern')
|
||||
->andWhere('LENGTH(part.ipn) = :expectedLength')
|
||||
->setParameter('ipnPattern', $currentPath . '%')
|
||||
->setParameter('expectedLength', $expectedLength)
|
||||
->orderBy('part.id', 'ASC');
|
||||
|
||||
$parts = $qb->getQuery()->getResult();
|
||||
|
||||
// Collect all used increments in the category
|
||||
$usedIncrements = [];
|
||||
foreach ($parts as $part) {
|
||||
if ($part->getIpn() === null || $part->getIpn() === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($part->getId() === $currentPart->getId() && $currentPart->getID() !== null) {
|
||||
// Extract and return the current part's increment directly
|
||||
$incrementPart = substr($part->getIpn(), -$suggestPartDigits);
|
||||
if (is_numeric($incrementPart)) {
|
||||
return str_pad((string) $incrementPart, $suggestPartDigits, '0', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract last $autocompletePartDigits digits for possible available part increment
|
||||
$incrementPart = substr($part->getIpn(), -$suggestPartDigits);
|
||||
if (is_numeric($incrementPart)) {
|
||||
$usedIncrements[] = (int) $incrementPart;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Generate the next free $autocompletePartDigits-digit increment
|
||||
$nextIncrement = 1; // Start at the beginning
|
||||
|
||||
while (in_array($nextIncrement, $usedIncrements, true)) {
|
||||
$nextIncrement++;
|
||||
}
|
||||
|
||||
return str_pad((string) $nextIncrement, $suggestPartDigits, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the next IPN suggestion based on the maximum numeric suffix found in the given IPNs.
|
||||
*
|
||||
* The new IPN is constructed using the base format of the first provided IPN,
|
||||
* incremented by the next free numeric suffix. If no base IPNs are found,
|
||||
* returns null.
|
||||
*
|
||||
* @param array $givenIpns List of IPNs to analyze.
|
||||
*
|
||||
* @return string|null The next suggested IPN, or null if no base IPNs can be derived.
|
||||
*/
|
||||
private function getNextIpnSuggestion(array $givenIpns): ?string {
|
||||
$maxSuffix = 0;
|
||||
|
||||
foreach ($givenIpns as $ipn) {
|
||||
// Check whether the IPN contains a suffix "_ <number>"
|
||||
if (preg_match('/_(\d+)$/', $ipn, $matches)) {
|
||||
$suffix = (int)$matches[1];
|
||||
if ($suffix > $maxSuffix) {
|
||||
$maxSuffix = $suffix; // Höchste Nummer speichern
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the basic format (the IPN without suffix) from the first IPN
|
||||
$baseIpn = $givenIpns[0] ?? '';
|
||||
$baseIpn = preg_replace('/_\d+$/', '', $baseIpn); // Remove existing "_ <number>"
|
||||
|
||||
if ($baseIpn === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Generate next free possible IPN
|
||||
return $baseIpn . '_' . ($maxSuffix + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
80
src/Settings/MiscSettings/IpnSuggestSettings.php
Normal file
80
src/Settings/MiscSettings/IpnSuggestSettings.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace App\Settings\MiscSettings;
|
||||
|
||||
use App\Settings\SettingsIcon;
|
||||
use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
|
||||
use Jbtronics\SettingsBundle\ParameterTypes\StringType;
|
||||
use Jbtronics\SettingsBundle\Settings\Settings;
|
||||
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
||||
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
||||
use Symfony\Component\Translation\TranslatableMessage as TM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[Settings(label: new TM("settings.misc.ipn_suggest"))]
|
||||
#[SettingsIcon("fa-list")]
|
||||
class IpnSuggestSettings
|
||||
{
|
||||
use SettingsTrait;
|
||||
|
||||
#[SettingsParameter(
|
||||
label: new TM("settings.misc.ipn_suggest.regex"),
|
||||
description: new TM("settings.misc.ipn_suggest.regex.help"),
|
||||
options: ['type' => StringType::class],
|
||||
formOptions: ['attr' => ['placeholder' => '^[A-Za-z0-9]{3,4}(?:-[A-Za-z0-9]{3,4})*-\d{4}$']],
|
||||
envVar: "IPN_SUGGEST_REGEX", envVarMode: EnvVarMode::OVERWRITE,
|
||||
)]
|
||||
public ?string $regex = null;
|
||||
|
||||
#[SettingsParameter(
|
||||
label: new TM("settings.misc.ipn_suggest.regex_help"),
|
||||
description: new TM("settings.misc.ipn_suggest.regex_help_description"),
|
||||
options: ['type' => StringType::class],
|
||||
formOptions: ['attr' => ['placeholder' => 'Format: 3–4 alphanumeric segments (any number) separated by "-", followed by "-" and 4 digits, e.g., PCOM-RES-0001']],
|
||||
envVar: "IPN_SUGGEST_REGEX_HELP", envVarMode: EnvVarMode::OVERWRITE,
|
||||
)]
|
||||
public ?string $regexHelp = null;
|
||||
|
||||
#[SettingsParameter(
|
||||
label: new TM("settings.misc.ipn_suggest.autoAppendSuffix"),
|
||||
envVar: "bool:IPN_AUTO_APPEND_SUFFIX", envVarMode: EnvVarMode::OVERWRITE,
|
||||
)]
|
||||
public bool $autoAppendSuffix = false;
|
||||
|
||||
#[SettingsParameter(label: new TM("settings.misc.ipn_suggest.suggestPartDigits"),
|
||||
description: new TM("settings.misc.ipn_suggest.suggestPartDigits.help"),
|
||||
formOptions: ['attr' => ['min' => 1, 'max' => 8]],
|
||||
envVar: "int:IPN_SUGGEST_PART_DIGITS", envVarMode: EnvVarMode::OVERWRITE
|
||||
)]
|
||||
#[Assert\Range(min: 1, max: 8)]
|
||||
public int $suggestPartDigits = 4;
|
||||
|
||||
#[SettingsParameter(
|
||||
label: new TM("settings.misc.ipn_suggest.useDuplicateDescription"),
|
||||
description: new TM("settings.misc.ipn_suggest.useDuplicateDescription.help"),
|
||||
envVar: "bool:IPN_USE_DUPLICATE_DESCRIPTION", envVarMode: EnvVarMode::OVERWRITE,
|
||||
)]
|
||||
public bool $useDuplicateDescription = false;
|
||||
}
|
||||
|
|
@ -35,4 +35,7 @@ class MiscSettings
|
|||
|
||||
#[EmbeddedSettings]
|
||||
public ?ExchangeRateSettings $exchangeRate = null;
|
||||
|
||||
#[EmbeddedSettings]
|
||||
public ?IpnSuggestSettings $ipnSuggestSettings = null;
|
||||
}
|
||||
|
|
|
|||
22
src/Validator/Constraints/UniquePartIpnConstraint.php
Normal file
22
src/Validator/Constraints/UniquePartIpnConstraint.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Validator\Constraints;
|
||||
|
||||
use Attribute;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
|
||||
class UniquePartIpnConstraint extends Constraint
|
||||
{
|
||||
public string $message = 'part.ipn.must_be_unique';
|
||||
|
||||
public function getTargets(): string|array
|
||||
{
|
||||
return [self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT];
|
||||
}
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
return UniquePartIpnValidator::class;
|
||||
}
|
||||
}
|
||||
55
src/Validator/Constraints/UniquePartIpnValidator.php
Normal file
55
src/Validator/Constraints/UniquePartIpnValidator.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Validator\Constraints;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
class UniquePartIpnValidator extends ConstraintValidator
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
private IpnSuggestSettings $ipnSuggestSettings;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, IpnSuggestSettings $ipnSuggestSettings)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->ipnSuggestSettings = $ipnSuggestSettings;
|
||||
}
|
||||
|
||||
public function validate($value, Constraint $constraint): void
|
||||
{
|
||||
if (null === $value || '' === $value) {
|
||||
return;
|
||||
}
|
||||
|
||||
//If the autoAppendSuffix option is enabled, the IPN becomes unique automatically later
|
||||
if ($this->ipnSuggestSettings->autoAppendSuffix) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$constraint instanceof UniquePartIpnConstraint) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Part $currentPart */
|
||||
$currentPart = $this->context->getObject();
|
||||
|
||||
if (!$currentPart instanceof Part) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repository = $this->entityManager->getRepository(Part::class);
|
||||
$existingParts = $repository->findBy(['ipn' => $value]);
|
||||
|
||||
foreach ($existingParts as $existingPart) {
|
||||
if ($currentPart->getId() !== $existingPart->getId()) {
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->setParameter('{{ value }}', $value)
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
<hr>
|
||||
{{ form_row(form.partname_regex) }}
|
||||
{{ form_row(form.partname_hint) }}
|
||||
{{ form_row(form.part_ipn_prefix) }}
|
||||
<hr>
|
||||
{{ form_row(form.default_description) }}
|
||||
{{ form_row(form.default_comment) }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
{{ form_row(form.needsReview) }}
|
||||
{{ form_row(form.favorite) }}
|
||||
{{ form_row(form.mass) }}
|
||||
{{ form_row(form.ipn) }}
|
||||
<div {{ stimulus_controller('elements/ipn_suggestion', {
|
||||
partId: part.id,
|
||||
partCategoryId: part.category ? part.category.id : null,
|
||||
partDescription: part.description,
|
||||
suggestions: ipnSuggestions,
|
||||
'commonSectionHeader': 'part.edit.tab.advanced.ipn.commonSectionHeader'|trans,
|
||||
'partIncrementHeader': 'part.edit.tab.advanced.ipn.partIncrementHeader'|trans,
|
||||
'suggestUrl': url('ipn_suggestions')
|
||||
}) }}>
|
||||
{{ form_row(form.ipn) }}
|
||||
</div>
|
||||
{{ form_row(form.partUnit) }}
|
||||
{{ form_row(form.partCustomState) }}
|
||||
297
tests/Repository/PartRepositoryTest.php
Normal file
297
tests/Repository/PartRepositoryTest.php
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Repository;
|
||||
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Settings\MiscSettings\IpnSuggestSettings;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use App\Repository\PartRepository;
|
||||
|
||||
final class PartRepositoryTest extends TestCase
|
||||
{
|
||||
public function test_autocompleteSearch_builds_expected_query_without_db(): void
|
||||
{
|
||||
$qb = $this->getMockBuilder(QueryBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([
|
||||
'select', 'leftJoin', 'where', 'orWhere',
|
||||
'setParameter', 'setMaxResults', 'orderBy', 'getQuery'
|
||||
])->getMock();
|
||||
|
||||
$qb->expects(self::once())->method('select')->with('part')->willReturnSelf();
|
||||
|
||||
$qb->expects(self::exactly(2))->method('leftJoin')->with($this->anything(), $this->anything())->willReturnSelf();
|
||||
|
||||
$qb->expects(self::atLeastOnce())->method('where')->with($this->anything())->willReturnSelf();
|
||||
$qb->method('orWhere')->with($this->anything())->willReturnSelf();
|
||||
|
||||
$searchQuery = 'res';
|
||||
$qb->expects(self::once())->method('setParameter')->with('query', '%'.$searchQuery.'%')->willReturnSelf();
|
||||
$qb->expects(self::once())->method('setMaxResults')->with(10)->willReturnSelf();
|
||||
$qb->expects(self::once())->method('orderBy')->with('NATSORT(part.name)', 'ASC')->willReturnSelf();
|
||||
|
||||
$emMock = $this->createMock(EntityManagerInterface::class);
|
||||
$classMetadata = new ClassMetadata(Part::class);
|
||||
$emMock->method('getClassMetadata')->with(Part::class)->willReturn($classMetadata);
|
||||
|
||||
$translatorMock = $this->createMock(TranslatorInterface::class);
|
||||
$ipnSuggestSettings = $this->createMock(IpnSuggestSettings::class);
|
||||
|
||||
$repo = $this->getMockBuilder(PartRepository::class)
|
||||
->setConstructorArgs([$emMock, $translatorMock, $ipnSuggestSettings])
|
||||
->onlyMethods(['createQueryBuilder'])
|
||||
->getMock();
|
||||
|
||||
$repo->expects(self::once())
|
||||
->method('createQueryBuilder')
|
||||
->with('part')
|
||||
->willReturn($qb);
|
||||
|
||||
$part = new Part(); // create found part, because it is not saved in DB
|
||||
$part->setName('Resistor');
|
||||
|
||||
$queryMock = $this->getMockBuilder(Query::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getResult'])
|
||||
->getMock();
|
||||
$queryMock->expects(self::once())->method('getResult')->willReturn([$part]);
|
||||
|
||||
$qb->method('getQuery')->willReturn($queryMock);
|
||||
|
||||
$result = $repo->autocompleteSearch($searchQuery, 10);
|
||||
|
||||
// Check one part found and returned
|
||||
self::assertIsArray($result);
|
||||
self::assertCount(1, $result);
|
||||
self::assertSame($part, $result[0]);
|
||||
}
|
||||
|
||||
public function test_autoCompleteIpn_with_unsaved_part_and_category_without_part_description(): void
|
||||
{
|
||||
$qb = $this->getMockBuilder(QueryBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([
|
||||
'select', 'leftJoin', 'where', 'andWhere', 'orWhere',
|
||||
'setParameter', 'setMaxResults', 'orderBy', 'getQuery'
|
||||
])->getMock();
|
||||
|
||||
$qb->method('select')->willReturnSelf();
|
||||
$qb->method('leftJoin')->willReturnSelf();
|
||||
$qb->method('where')->willReturnSelf();
|
||||
$qb->method('andWhere')->willReturnSelf();
|
||||
$qb->method('orWhere')->willReturnSelf();
|
||||
$qb->method('setParameter')->willReturnSelf();
|
||||
$qb->method('setMaxResults')->willReturnSelf();
|
||||
$qb->method('orderBy')->willReturnSelf();
|
||||
|
||||
$emMock = $this->createMock(EntityManagerInterface::class);
|
||||
$classMetadata = new ClassMetadata(Part::class);
|
||||
$emMock->method('getClassMetadata')->with(Part::class)->willReturn($classMetadata);
|
||||
|
||||
$translatorMock = $this->createMock(TranslatorInterface::class);
|
||||
$translatorMock->method('trans')
|
||||
->willReturnCallback(static function (string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string {
|
||||
return $id;
|
||||
});
|
||||
|
||||
$ipnSuggestSettings = $this->createMock(IpnSuggestSettings::class);
|
||||
|
||||
$ipnSuggestSettings->suggestPartDigits = 4;
|
||||
$ipnSuggestSettings->useDuplicateDescription = false;
|
||||
|
||||
$repo = $this->getMockBuilder(PartRepository::class)
|
||||
->setConstructorArgs([$emMock, $translatorMock, $ipnSuggestSettings])
|
||||
->onlyMethods(['createQueryBuilder'])
|
||||
->getMock();
|
||||
|
||||
$repo->expects(self::atLeastOnce())
|
||||
->method('createQueryBuilder')
|
||||
->with('part')
|
||||
->willReturn($qb);
|
||||
|
||||
$queryMock = $this->getMockBuilder(Query::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getResult'])
|
||||
->getMock();
|
||||
|
||||
$categoryParent = new Category();
|
||||
$categoryParent->setName('Passive components');
|
||||
$categoryParent->setPartIpnPrefix('PCOM');
|
||||
|
||||
$categoryChild = new Category();
|
||||
$categoryChild->setName('Resistors');
|
||||
$categoryChild->setPartIpnPrefix('RES');
|
||||
$categoryChild->setParent($categoryParent);
|
||||
|
||||
$partForSuggestGeneration = new Part(); // create found part, because it is not saved in DB
|
||||
$partForSuggestGeneration->setIpn('RES-0001');
|
||||
$partForSuggestGeneration->setCategory($categoryChild);
|
||||
|
||||
$queryMock->method('getResult')->willReturn([$partForSuggestGeneration]);
|
||||
$qb->method('getQuery')->willReturn($queryMock);
|
||||
$suggestions = $repo->autoCompleteIpn($partForSuggestGeneration, '', 4);
|
||||
|
||||
// Check structure available
|
||||
self::assertIsArray($suggestions);
|
||||
self::assertArrayHasKey('commonPrefixes', $suggestions);
|
||||
self::assertArrayHasKey('prefixesPartIncrement', $suggestions);
|
||||
self::assertNotEmpty($suggestions['commonPrefixes']);
|
||||
self::assertNotEmpty($suggestions['prefixesPartIncrement']);
|
||||
|
||||
// Check expected values
|
||||
self::assertSame('RES-', $suggestions['commonPrefixes'][0]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category', $suggestions['commonPrefixes'][0]['description']);
|
||||
self::assertSame('PCOM-RES-', $suggestions['commonPrefixes'][1]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment', $suggestions['commonPrefixes'][1]['description']);
|
||||
|
||||
self::assertSame('RES-0002', $suggestions['prefixesPartIncrement'][0]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category.increment', $suggestions['prefixesPartIncrement'][0]['description']);
|
||||
self::assertSame('PCOM-RES-0002', $suggestions['prefixesPartIncrement'][1]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.increment', $suggestions['prefixesPartIncrement'][1]['description']);
|
||||
}
|
||||
|
||||
public function test_autoCompleteIpn_with_unsaved_part_and_category_with_part_description(): void
|
||||
{
|
||||
$qb = $this->getMockBuilder(QueryBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([
|
||||
'select', 'leftJoin', 'where', 'andWhere', 'orWhere',
|
||||
'setParameter', 'setMaxResults', 'orderBy', 'getQuery'
|
||||
])->getMock();
|
||||
|
||||
$qb->method('select')->willReturnSelf();
|
||||
$qb->method('leftJoin')->willReturnSelf();
|
||||
$qb->method('where')->willReturnSelf();
|
||||
$qb->method('andWhere')->willReturnSelf();
|
||||
$qb->method('orWhere')->willReturnSelf();
|
||||
$qb->method('setParameter')->willReturnSelf();
|
||||
$qb->method('setMaxResults')->willReturnSelf();
|
||||
$qb->method('orderBy')->willReturnSelf();
|
||||
|
||||
$emMock = $this->createMock(EntityManagerInterface::class);
|
||||
$classMetadata = new ClassMetadata(Part::class);
|
||||
$emMock->method('getClassMetadata')->with(Part::class)->willReturn($classMetadata);
|
||||
|
||||
$translatorMock = $this->createMock(TranslatorInterface::class);
|
||||
$translatorMock->method('trans')
|
||||
->willReturnCallback(static function (string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string {
|
||||
return $id;
|
||||
});
|
||||
|
||||
$ipnSuggestSettings = $this->createMock(IpnSuggestSettings::class);
|
||||
|
||||
$ipnSuggestSettings->suggestPartDigits = 4;
|
||||
$ipnSuggestSettings->useDuplicateDescription = false;
|
||||
|
||||
$repo = $this->getMockBuilder(PartRepository::class)
|
||||
->setConstructorArgs([$emMock, $translatorMock, $ipnSuggestSettings])
|
||||
->onlyMethods(['createQueryBuilder'])
|
||||
->getMock();
|
||||
|
||||
$repo->expects(self::atLeastOnce())
|
||||
->method('createQueryBuilder')
|
||||
->with('part')
|
||||
->willReturn($qb);
|
||||
|
||||
$queryMock = $this->getMockBuilder(Query::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getResult'])
|
||||
->getMock();
|
||||
|
||||
$categoryParent = new Category();
|
||||
$categoryParent->setName('Passive components');
|
||||
$categoryParent->setPartIpnPrefix('PCOM');
|
||||
|
||||
$categoryChild = new Category();
|
||||
$categoryChild->setName('Resistors');
|
||||
$categoryChild->setPartIpnPrefix('RES');
|
||||
$categoryChild->setParent($categoryParent);
|
||||
|
||||
$partForSuggestGeneration = new Part(); // create found part, because it is not saved in DB
|
||||
$partForSuggestGeneration->setCategory($categoryChild);
|
||||
$partForSuggestGeneration->setIpn('1810-1679_1');
|
||||
$partForSuggestGeneration->setDescription('NETWORK-RESISTOR 4 0 OHM +5PCT 0.063W TKF SMT');
|
||||
|
||||
$queryMock->method('getResult')->willReturn([$partForSuggestGeneration]);
|
||||
$qb->method('getQuery')->willReturn($queryMock);
|
||||
$suggestions = $repo->autoCompleteIpn($partForSuggestGeneration, 'NETWORK-RESISTOR 4 0 OHM +5PCT 0.063W TKF SMT', 4);
|
||||
|
||||
// Check structure available
|
||||
self::assertIsArray($suggestions);
|
||||
self::assertArrayHasKey('commonPrefixes', $suggestions);
|
||||
self::assertArrayHasKey('prefixesPartIncrement', $suggestions);
|
||||
self::assertNotEmpty($suggestions['commonPrefixes']);
|
||||
self::assertCount(2, $suggestions['commonPrefixes']);
|
||||
self::assertNotEmpty($suggestions['prefixesPartIncrement']);
|
||||
self::assertCount(2, $suggestions['prefixesPartIncrement']);
|
||||
|
||||
// Check expected values without any increment, for user to decide
|
||||
self::assertSame('RES-', $suggestions['commonPrefixes'][0]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category', $suggestions['commonPrefixes'][0]['description']);
|
||||
self::assertSame('PCOM-RES-', $suggestions['commonPrefixes'][1]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment', $suggestions['commonPrefixes'][1]['description']);
|
||||
|
||||
// Check expected values with next possible increment at category level
|
||||
self::assertSame('RES-0001', $suggestions['prefixesPartIncrement'][0]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category.increment', $suggestions['prefixesPartIncrement'][0]['description']);
|
||||
self::assertSame('PCOM-RES-0001', $suggestions['prefixesPartIncrement'][1]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.increment', $suggestions['prefixesPartIncrement'][1]['description']);
|
||||
|
||||
$ipnSuggestSettings->useDuplicateDescription = true;
|
||||
|
||||
$suggestionsWithSameDescription = $repo->autoCompleteIpn($partForSuggestGeneration, 'NETWORK-RESISTOR 4 0 OHM +5PCT 0.063W TKF SMT', 4);
|
||||
|
||||
// Check structure available
|
||||
self::assertIsArray($suggestionsWithSameDescription);
|
||||
self::assertArrayHasKey('commonPrefixes', $suggestionsWithSameDescription);
|
||||
self::assertArrayHasKey('prefixesPartIncrement', $suggestionsWithSameDescription);
|
||||
self::assertNotEmpty($suggestionsWithSameDescription['commonPrefixes']);
|
||||
self::assertCount(2, $suggestionsWithSameDescription['commonPrefixes']);
|
||||
self::assertNotEmpty($suggestionsWithSameDescription['prefixesPartIncrement']);
|
||||
self::assertCount(4, $suggestionsWithSameDescription['prefixesPartIncrement']);
|
||||
|
||||
// Check expected values without any increment, for user to decide
|
||||
self::assertSame('RES-', $suggestionsWithSameDescription['commonPrefixes'][0]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category', $suggestionsWithSameDescription['commonPrefixes'][0]['description']);
|
||||
self::assertSame('PCOM-RES-', $suggestionsWithSameDescription['commonPrefixes'][1]['title']);
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment', $suggestionsWithSameDescription['commonPrefixes'][1]['description']);
|
||||
|
||||
// Check expected values with next possible increment at part description level
|
||||
self::assertSame('1810-1679_1', $suggestionsWithSameDescription['prefixesPartIncrement'][0]['title']); // current given value
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.description.current-increment', $suggestionsWithSameDescription['prefixesPartIncrement'][0]['description']);
|
||||
self::assertSame('1810-1679_2', $suggestionsWithSameDescription['prefixesPartIncrement'][1]['title']); // next possible value
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.description.increment', $suggestionsWithSameDescription['prefixesPartIncrement'][1]['description']);
|
||||
|
||||
// Check expected values with next possible increment at category level
|
||||
self::assertSame('RES-0001', $suggestionsWithSameDescription['prefixesPartIncrement'][2]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.direct_category.increment', $suggestionsWithSameDescription['prefixesPartIncrement'][2]['description']);
|
||||
self::assertSame('PCOM-RES-0001', $suggestionsWithSameDescription['prefixesPartIncrement'][3]['title']); // next possible free increment for given part category
|
||||
self::assertSame('part.edit.tab.advanced.ipn.prefix.hierarchical.increment', $suggestionsWithSameDescription['prefixesPartIncrement'][3]['description']);
|
||||
}
|
||||
}
|
||||
|
|
@ -1848,6 +1848,66 @@ Související prvky budou přesunuty nahoru.</target>
|
|||
<target>Pokročilé</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Návrhy bez přírůstku části</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Návrhy s číselnými přírůstky částí</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Aktuální specifikace IPN pro součást</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Další možná specifikace IPN na základě identického popisu součásti</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>IPN předpona přímé kategorie je prázdná, zadejte ji v kategorii „%name%“</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>IPN prefix přímé kategorie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>IPN prefix přímé kategorie a specifického přírůstku pro část</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN prefixy s hierarchickým pořadím kategorií rodičovských prefixů</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN prefixy s hierarchickým pořadím kategorií rodičovských prefixů a specifickým přírůstkem pro část</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Nejprve vytvořte součást a přiřaďte ji do kategorie: s dostupnými kategoriemi a jejich vlastními IPN prefixy lze automaticky navrhnout IPN označení pro danou součást</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6989,6 +7049,12 @@ Pokud jste to provedli nesprávně nebo pokud počítač již není důvěryhodn
|
|||
<target>Filtr názvů</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Předpona součásti IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10290,12 +10356,24 @@ Element 3</target>
|
|||
<target>např. "/Kondenzátor \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>např. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Regulární výraz kompatibilní s PCRE, kterému musí název dílu odpovídat.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Předpona navrhovaná při zadávání IPN části.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
@ -13029,6 +13107,54 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
|
|||
<target>Pokud potřebujete směnné kurzy mezi měnami mimo eurozónu, můžete zde zadat API klíč z fixer.io.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jd7tEu3" name="settings.misc.ipn_suggest">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest</source>
|
||||
<target>Seznam návrhů IPN součástek</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="adi7Zv4" name="settings.misc.ipn_suggest.regex">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex</source>
|
||||
<target>Regex</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kidR4vm" name="settings.misc.ipn_suggest.regex_help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help</source>
|
||||
<target>Nápověda text</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jch7Bn5" name="settings.misc.ipn_suggest.regex_help_description">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help_description</source>
|
||||
<target>Definujte svůj vlastní text nápovědy pro specifikaci formátu Regex.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kdi8mT4" name="settings.misc.ipn_suggest.autoAppendSuffix">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.autoAppendSuffix</source>
|
||||
<target>Pokud je tato možnost povolena, bude při opětovném zadání existujícího IPN při ukládání k vstupu přidána přírůstková přípona.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="rociEg6" name="settings.misc.ipn_suggest.suggestPartDigits">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits</source>
|
||||
<target>Počet čísel pro inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jdz6B4c" name="settings.misc.ipn_suggest.useDuplicateDescription">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.useDuplicateDescription</source>
|
||||
<target>Je-li povoleno, použije se popis součástky k nalezení existujících součástek se stejným popisem a k určení další volné IPN navýšením její číselné přípony pro seznam návrhů.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="judfiK3" name="settings.misc.ipn_suggest.suggestPartDigits.help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits.help</source>
|
||||
<target>Počet číslic použitých pro inkrementální číslování součástí v návrhovém systému IPN (Interní číslo součástky).</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Ffr5xYM" name="settings.behavior.part_info">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.part_info</source>
|
||||
|
|
|
|||
|
|
@ -1856,6 +1856,66 @@ Underelementer vil blive flyttet opad.</target>
|
|||
<target>Advanceret</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Forslag uden del-inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Forslag med numeriske deleforøgelser</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Aktuel IPN-specifikation for delen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Næste mulige IPN-specifikation baseret på en identisk delebeskrivelse</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>IPN-præfikset for den direkte kategori er tomt, angiv det i kategorien "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>IPN-præfiks for direkte kategori</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>IPN-præfiks for den direkte kategori og en delspecifik inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN-præfikser med hierarkisk rækkefølge af overordnede præfikser</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN-præfikser med hierarkisk rækkefølge af overordnede præfikser og en del-specifik inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Opret først en komponent, og tildel den en kategori: med eksisterende kategorier og deres egne IPN-præfikser kan IPN-betegnelsen for komponenten foreslås automatisk</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="uc9NwcF" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6996,6 +7056,12 @@ Bemærk også, at uden to-faktor-godkendelse er din konto ikke længere så godt
|
|||
<target>Navnefilter</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>IPN-komponentförstavelse</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="UH78POJ" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10316,12 +10382,24 @@ Element 3</target>
|
|||
<target>f.eks. "/Kondensator \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>f.eks. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="QFgP__5" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Et PCRE-kompatibelt regulært udtryk, som delnavnet skal opfylde.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Et prefix foreslået, når IPN for en del indtastes.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vr7oZKL" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="de">
|
||||
<file id="messages.en">
|
||||
<file id="messages.de">
|
||||
<unit id="x_wTSQS" name="attachment_type.caption">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\AttachmentTypeAdmin.html.twig:4</note>
|
||||
|
|
@ -242,7 +242,7 @@
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>part.info.timetravel_hint</source>
|
||||
<target>So sah das Bauteil vor %timestamp% aus. <i>Beachten Sie, dass dieses Feature experimentell ist und die angezeigten Infos daher nicht unbedingt korrekt sind.</i></target>
|
||||
<target><![CDATA[So sah das Bauteil vor %timestamp% aus. <i>Beachten Sie, dass dieses Feature experimentell ist und die angezeigten Infos daher nicht unbedingt korrekt sind.</i>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="3exvSpl" name="standard.label">
|
||||
|
|
@ -737,9 +737,9 @@
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>user.edit.tfa.disable_tfa_message</source>
|
||||
<target>Dies wird <b>alle aktiven Zwei-Faktor-Authentifizierungsmethoden des Nutzers deaktivieren</b> und die <b>Backupcodes löschen</b>! <br>
|
||||
Der Benutzer wird alle Zwei-Faktor-Authentifizierungmethoden neu einrichten müssen und neue Backupcodes ausdrucken müssen! <br><br>
|
||||
<b>Führen sie dies nur durch, wenn Sie über die Identität des (um Hilfe suchenden) Benutzers absolut sicher sind, da ansonsten eine Kompromittierung des Accounts durch einen Angreifer erfolgen könnte!</b></target>
|
||||
<target><![CDATA[Dies wird <b>alle aktiven Zwei-Faktor-Authentifizierungsmethoden des Nutzers deaktivieren</b> und die <b>Backupcodes löschen</b>! <br>
|
||||
Der Benutzer wird alle Zwei-Faktor-Authentifizierungmethoden neu einrichten müssen und neue Backupcodes ausdrucken müssen! <br><br>
|
||||
<b>Führen sie dies nur durch, wenn Sie über die Identität des (um Hilfe suchenden) Benutzers absolut sicher sind, da ansonsten eine Kompromittierung des Accounts durch einen Angreifer erfolgen könnte!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="APsHYu0" name="user.edit.tfa.disable_tfa.btn">
|
||||
|
|
@ -1446,7 +1446,7 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>homepage.github.text</source>
|
||||
<target>Quellcode, Downloads, Bugreports, ToDo-Liste usw. gibts auf der <a class="link-external" target="_blank" href="%href%">GitHub Projektseite</a></target>
|
||||
<target><![CDATA[Quellcode, Downloads, Bugreports, ToDo-Liste usw. gibts auf der <a class="link-external" target="_blank" href="%href%">GitHub Projektseite</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="D5OKsgU" name="homepage.help.caption">
|
||||
|
|
@ -1468,7 +1468,7 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>homepage.help.text</source>
|
||||
<target>Hilfe und Tipps finden sie im <a class="link-external" rel="noopener" target="_blank" href="%href%">Wiki</a> der GitHub Seite.</target>
|
||||
<target><![CDATA[Hilfe und Tipps finden sie im <a class="link-external" rel="noopener" target="_blank" href="%href%">Wiki</a> der GitHub Seite.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dnirx4v" name="homepage.forum.caption">
|
||||
|
|
@ -1710,7 +1710,7 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.fallback</source>
|
||||
<target>Wenn dies nicht funktioniert, rufen Sie <a href="%url%">%url%</a> auf und geben Sie die folgenden Daten ein</target>
|
||||
<target><![CDATA[Wenn dies nicht funktioniert, rufen Sie <a href="%url%">%url%</a> auf und geben Sie die folgenden Daten ein]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DduL9Hu" name="email.pw_reset.username">
|
||||
|
|
@ -1740,7 +1740,7 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.valid_unit %date%</source>
|
||||
<target>Das Reset-Token ist gültig bis <i>%date%</i></target>
|
||||
<target><![CDATA[Das Reset-Token ist gültig bis <i>%date%</i>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8sBnjRy" name="orderdetail.delete">
|
||||
|
|
@ -1847,6 +1847,66 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
<target>Erweiterte Optionen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="_iVXTDt" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Vorschläge ohne Teil-Inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="7.yHB9w" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Vorschläge mit numerischen Teil-Inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="H1o.JFb" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Aktuelle IPN-Angabe des Bauteils</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="wt.Rn7C" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Nächstmögliche IPN-Angabe auf Basis der identischen Bauteil-Beschreibung</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="RXA8jNa" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>IPN-Präfix der direkten Kategorie leer, geben Sie einen Präfix in Kategorie "%name%" an</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="fdSIyqC" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>IPN-Präfix der direkten Kategorie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="0l7ST7C" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>IPN-Präfix der direkten Kategorie und eines teilspezifischen Inkrements</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="1Y9qoug" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN-Präfixe mit hierarchischer Kategorienreihenfolge der Elternpräfixe</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a6_204L" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN-Präfixe mit hierarchischer Kategorienreihenfolge der Elternpräfixe und ein teilsspezifisches Inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VS8w2qp" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Bitte erstellen Sie zuerst ein Bauteil und weisen Sie dieses einer Kategorie zu: mit vorhandenen Kategorien und derene eigenen IPN-Präfix kann die IPN-Angabe für das jeweilige Teil automatisch vorgeschlagen werden</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -3583,8 +3643,8 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.disable.confirm_message</source>
|
||||
<target>Wenn Sie die Authenticator App deaktivieren, werden alle Backupcodes gelöscht, daher sie müssen sie evtl. neu ausdrucken.<br>
|
||||
Beachten Sie außerdem, dass ihr Account ohne Zwei-Faktor-Authentifizierung nicht mehr so gut gegen Angreifer geschützt ist!</target>
|
||||
<target><![CDATA[Wenn Sie die Authenticator App deaktivieren, werden alle Backupcodes gelöscht, daher sie müssen sie evtl. neu ausdrucken.<br>
|
||||
Beachten Sie außerdem, dass ihr Account ohne Zwei-Faktor-Authentifizierung nicht mehr so gut gegen Angreifer geschützt ist!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yu9MSt5" name="tfa_google.disabled_message">
|
||||
|
|
@ -3604,7 +3664,7 @@ Beachten Sie außerdem, dass ihr Account ohne Zwei-Faktor-Authentifizierung nich
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.step.download</source>
|
||||
<target>Laden Sie eine Authenticator App herunter (z.B. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)</target>
|
||||
<target><![CDATA[Laden Sie eine Authenticator App herunter (z.B. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="eriwJoR" name="tfa_google.step.scan">
|
||||
|
|
@ -3846,8 +3906,8 @@ Beachten Sie außerdem, dass ihr Account ohne Zwei-Faktor-Authentifizierung nich
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_trustedDevices.explanation</source>
|
||||
<target>Bei der Überprüfung des zweiten Faktors, kann der aktuelle Computer als vertrauenswürdig gekennzeichnet werden, daher werden keine Zwei-Faktor-Überprüfungen mehr an diesem Computer benötigt.
|
||||
Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertrauenswürdig ist, können Sie hier den Status <i>aller </i>Computer zurücksetzen.</target>
|
||||
<target><![CDATA[Bei der Überprüfung des zweiten Faktors, kann der aktuelle Computer als vertrauenswürdig gekennzeichnet werden, daher werden keine Zwei-Faktor-Überprüfungen mehr an diesem Computer benötigt.
|
||||
Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertrauenswürdig ist, können Sie hier den Status <i>aller </i>Computer zurücksetzen.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="FZINq8z" name="tfa_trustedDevices.invalidate.confirm_title">
|
||||
|
|
@ -5324,7 +5384,7 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>label_options.lines_mode.help</source>
|
||||
<target>Wenn Sie hier Twig auswählen, wird das Contentfeld als Twig-Template interpretiert. Weitere Hilfe gibt es in der <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig Dokumentation</a> und dem <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a>.</target>
|
||||
<target><![CDATA[Wenn Sie hier Twig auswählen, wird das Contentfeld als Twig-Template interpretiert. Weitere Hilfe gibt es in der <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig Dokumentation</a> und dem <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="isvxbiX" name="label_options.page_size.label">
|
||||
|
|
@ -6988,6 +7048,12 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
|||
<target>Namensfilter</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a37rx0r" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Bauteil IPN-Präfix</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -7186,15 +7252,15 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>mass_creation.lines.placeholder</source>
|
||||
<target>Element 1
|
||||
<target><![CDATA[Element 1
|
||||
Element 1.1
|
||||
Element 1.1.1
|
||||
Element 1.2
|
||||
Element 2
|
||||
Element 3
|
||||
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2</target>
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="TWSqPFi" name="entity.mass_creation.btn">
|
||||
|
|
@ -9479,25 +9545,25 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="r4vDLAt" name="filter.parameter_value_constraint.operator.<">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<</source>
|
||||
<target>Typ. Wert <</target>
|
||||
<target><![CDATA[Typ. Wert <]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="X9SA3UP" name="filter.parameter_value_constraint.operator.>">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.></source>
|
||||
<target>Typ. Wert ></target>
|
||||
<target><![CDATA[Typ. Wert >]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="BQGaoQS" name="filter.parameter_value_constraint.operator.<=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<=</source>
|
||||
<target>Typ. Wert <=</target>
|
||||
<target><![CDATA[Typ. Wert <=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2ha3P6g" name="filter.parameter_value_constraint.operator.>=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.>=</source>
|
||||
<target>Typ. Wert >=</target>
|
||||
<target><![CDATA[Typ. Wert >=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4DaBace" name="filter.parameter_value_constraint.operator.BETWEEN">
|
||||
|
|
@ -9605,7 +9671,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="4tHhDtU" name="parts_list.search.searching_for">
|
||||
<segment state="translated">
|
||||
<source>parts_list.search.searching_for</source>
|
||||
<target>Suche Teile mit dem Suchbegriff <b>%keyword%</b></target>
|
||||
<target><![CDATA[Suche Teile mit dem Suchbegriff <b>%keyword%</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4vomKLa" name="parts_list.search_options.caption">
|
||||
|
|
@ -10265,13 +10331,13 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="NdZ1t7a" name="project.builds.number_of_builds_possible">
|
||||
<segment state="translated">
|
||||
<source>project.builds.number_of_builds_possible</source>
|
||||
<target>Sie haben genug Bauteile auf Lager, um <b>%max_builds%</b> Exemplare dieses Projektes zu bauen.</target>
|
||||
<target><![CDATA[Sie haben genug Bauteile auf Lager, um <b>%max_builds%</b> Exemplare dieses Projektes zu bauen.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="iuSpPbg" name="project.builds.check_project_status">
|
||||
<segment state="translated">
|
||||
<source>project.builds.check_project_status</source>
|
||||
<target>Der aktuelle Projektstatus ist <b>"%project_status%"</b>. Sie sollten überprüfen, ob sie das Projekt mit diesem Status wirklich bauen wollen!</target>
|
||||
<target><![CDATA[Der aktuelle Projektstatus ist <b>"%project_status%"</b>. Sie sollten überprüfen, ob sie das Projekt mit diesem Status wirklich bauen wollen!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Y7vSSxi" name="project.builds.following_bom_entries_miss_instock_n">
|
||||
|
|
@ -10364,16 +10430,28 @@ Element 1 -> Element 1.2</target>
|
|||
<target>z.B. "/Kondensator \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5zV57Ks" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>z.B. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Ein PCRE-kompatibler regulärer Ausdruck, den der Bauteilename erfüllen muss.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="f3gkGc9" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Ein Präfix, der bei der IPN-Eingabe eines Bauteils vorgeschlagen wird.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
<target>Nutzen Sie -> um verschachtelte Strukturen anzulegen, z.B. "Element 1->Element 1.1"</target>
|
||||
<target><![CDATA[Nutzen Sie -> um verschachtelte Strukturen anzulegen, z.B. "Element 1->Element 1.1"]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
||||
|
|
@ -10397,13 +10475,13 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="XLnXtsR" name="homepage.first_steps.introduction">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.introduction</source>
|
||||
<target>Die Datenbank ist momentan noch leer. Sie möchten möglicherweise die <a href="%url%">Dokumentation</a> lesen oder anfangen, die folgenden Datenstrukturen anzulegen.</target>
|
||||
<target><![CDATA[Die Datenbank ist momentan noch leer. Sie möchten möglicherweise die <a href="%url%">Dokumentation</a> lesen oder anfangen, die folgenden Datenstrukturen anzulegen.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q79MOIk" name="homepage.first_steps.create_part">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.create_part</source>
|
||||
<target>Oder Sie können direkt ein <a href="%url%">neues Bauteil erstellen</a>.</target>
|
||||
<target><![CDATA[Oder Sie können direkt ein <a href="%url%">neues Bauteil erstellen</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vplYq4f" name="homepage.first_steps.hide_hint">
|
||||
|
|
@ -10415,7 +10493,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="MJoZl4f" name="homepage.forum.text">
|
||||
<segment state="translated">
|
||||
<source>homepage.forum.text</source>
|
||||
<target>Für Fragen rund um Part-DB, nutze das <a class="link-external" rel="noopener" target="_blank" href="%href%">Diskussionsforum</a></target>
|
||||
<target><![CDATA[Für Fragen rund um Part-DB, nutze das <a class="link-external" rel="noopener" target="_blank" href="%href%">Diskussionsforum</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YsukbnK" name="log.element_edited.changed_fields.category">
|
||||
|
|
@ -11081,7 +11159,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="p_IxB9K" name="parts.import.help_documentation">
|
||||
<segment state="translated">
|
||||
<source>parts.import.help_documentation</source>
|
||||
<target>Konsultieren Sie die <a href="%link%">Dokumentation</a> für weiter Informationen über das Dateiformat.</target>
|
||||
<target><![CDATA[Konsultieren Sie die <a href="%link%">Dokumentation</a> für weiter Informationen über das Dateiformat.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="awbvhVq" name="parts.import.help">
|
||||
|
|
@ -11273,7 +11351,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="o5u.Nnz" name="part.filter.lessThanDesired">
|
||||
<segment state="translated">
|
||||
<source>part.filter.lessThanDesired</source>
|
||||
<target>Weniger vorhanden als gewünscht (Gesamtmenge < Mindestmenge)</target>
|
||||
<target><![CDATA[Weniger vorhanden als gewünscht (Gesamtmenge < Mindestmenge)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YN9eLcZ" name="part.filter.lotOwner">
|
||||
|
|
@ -12085,13 +12163,13 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="i68lU5x" name="part.merge.confirm.title">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.title</source>
|
||||
<target>Möchten Sie wirklich <b>%other%</b> in <b>%target%</b> zusammenführen?</target>
|
||||
<target><![CDATA[Möchten Sie wirklich <b>%other%</b> in <b>%target%</b> zusammenführen?]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="k0anzYV" name="part.merge.confirm.message">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.message</source>
|
||||
<target><b>%other%</b> wird gelöscht, und das aktuelle Bauteil wird mit den angezeigten Daten gespeichert.</target>
|
||||
<target><![CDATA[<b>%other%</b> wird gelöscht, und das aktuelle Bauteil wird mit den angezeigten Daten gespeichert.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="mmW5Yl1" name="part.info.merge_modal.title">
|
||||
|
|
@ -12445,7 +12523,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="p7LGAIX" name="settings.ips.element14.apiKey.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.element14.apiKey.help</source>
|
||||
<target>Sie können sich unter <a href="https://partner.element14.com/">https://partner.element14.com/</a> für einen API-Schlüssel registrieren.</target>
|
||||
<target><![CDATA[Sie können sich unter <a href="https://partner.element14.com/">https://partner.element14.com/</a> für einen API-Schlüssel registrieren.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ZdUHpZc" name="settings.ips.element14.storeId">
|
||||
|
|
@ -12457,7 +12535,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="XXGUxF6" name="settings.ips.element14.storeId.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.element14.storeId.help</source>
|
||||
<target>Die Domain des Shops, aus dem die Daten abgerufen werden sollen. Diese bestimmt die Sprache und Währung der Ergebnisse. Eine Liste der gültigen Domains finden Sie <a href="https://partner.element14.com/docs/Product_Search_API_REST__Description">hier</a>.</target>
|
||||
<target><![CDATA[Die Domain des Shops, aus dem die Daten abgerufen werden sollen. Diese bestimmt die Sprache und Währung der Ergebnisse. Eine Liste der gültigen Domains finden Sie <a href="https://partner.element14.com/docs/Product_Search_API_REST__Description">hier</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="WKWZIm2" name="settings.ips.tme">
|
||||
|
|
@ -12475,7 +12553,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="_pYLrPT" name="settings.ips.tme.token.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.tme.token.help</source>
|
||||
<target>Sie können einen API-Token und einen geheimen Schlüssel unter <a href="https://developers.tme.eu/en/">https://developers.tme.eu/en/</a> erhalten.</target>
|
||||
<target><![CDATA[Sie können einen API-Token und einen geheimen Schlüssel unter <a href="https://developers.tme.eu/en/">https://developers.tme.eu/en/</a> erhalten.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yswx4bq" name="settings.ips.tme.secret">
|
||||
|
|
@ -12523,7 +12601,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="gu.JlpT" name="settings.ips.mouser.apiKey.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.mouser.apiKey.help</source>
|
||||
<target>Sie können sich unter <a href="https://eu.mouser.com/api-hub/">https://eu.mouser.com/api-hub/</a> für einen API-Schlüssel registrieren.</target>
|
||||
<target><![CDATA[Sie können sich unter <a href="https://eu.mouser.com/api-hub/">https://eu.mouser.com/api-hub/</a> für einen API-Schlüssel registrieren.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q66CNjw" name="settings.ips.mouser.searchLimit">
|
||||
|
|
@ -12571,7 +12649,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="xU8_Qw." name="settings.ips.mouser.searchOptions.rohsAndInStock">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.mouser.searchOptions.rohsAndInStock</source>
|
||||
<target>Sofort verfügbar & RoHS konform</target>
|
||||
<target><![CDATA[Sofort verfügbar & RoHS konform]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="fQYt0Om" name="settings.ips.lcsc">
|
||||
|
|
@ -12601,7 +12679,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="kKv0J3." name="settings.system.attachments">
|
||||
<segment state="translated">
|
||||
<source>settings.system.attachments</source>
|
||||
<target>Anhänge & Dateien</target>
|
||||
<target><![CDATA[Anhänge & Dateien]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsRff8T" name="settings.system.attachments.maxFileSize">
|
||||
|
|
@ -12625,7 +12703,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="T.PBu5P" name="settings.system.attachments.allowDownloads.help">
|
||||
<segment state="translated">
|
||||
<source>settings.system.attachments.allowDownloads.help</source>
|
||||
<target>Mit dieser Option können Benutzer externe Dateien in die Part-DB herunterladen, indem sie eine URL angeben. <b>Achtung: Dies kann ein Sicherheitsrisiko darstellen, da Benutzer dadurch möglicherweise über die Part-DB auf Intranet-Ressourcen zugreifen können!</b></target>
|
||||
<target><![CDATA[Mit dieser Option können Benutzer externe Dateien in die Part-DB herunterladen, indem sie eine URL angeben. <b>Achtung: Dies kann ein Sicherheitsrisiko darstellen, da Benutzer dadurch möglicherweise über die Part-DB auf Intranet-Ressourcen zugreifen können!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id=".OyihML" name="settings.system.attachments.downloadByDefault">
|
||||
|
|
@ -12799,8 +12877,8 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="0GRlEe5" name="settings.system.localization.base_currency_description">
|
||||
<segment state="translated">
|
||||
<source>settings.system.localization.base_currency_description</source>
|
||||
<target>Die Währung, in der Preisinformationen und Wechselkurse gespeichert werden. Diese Währung wird angenommen, wenn für eine Preisinformation keine Währung festgelegt ist.
|
||||
<b>Bitte beachten Sie, dass die Währungen bei einer Änderung dieses Wertes nicht umgerechnet werden. Wenn Sie also die Basiswährung ändern, nachdem Sie bereits Preisinformationen hinzugefügt haben, führt dies zu falschen Preisen!</b></target>
|
||||
<target><![CDATA[Die Währung, in der Preisinformationen und Wechselkurse gespeichert werden. Diese Währung wird angenommen, wenn für eine Preisinformation keine Währung festgelegt ist.
|
||||
<b>Bitte beachten Sie, dass die Währungen bei einer Änderung dieses Wertes nicht umgerechnet werden. Wenn Sie also die Basiswährung ändern, nachdem Sie bereits Preisinformationen hinzugefügt haben, führt dies zu falschen Preisen!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cvpTUeY" name="settings.system.privacy">
|
||||
|
|
@ -12830,7 +12908,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="w07P3Dt" name="settings.misc.kicad_eda.category_depth.help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.kicad_eda.category_depth.help</source>
|
||||
<target>Dieser Wert bestimmt die Tiefe des Kategoriebaums, der in KiCad sichtbar ist. 0 bedeutet, dass nur die Kategorien der obersten Ebene sichtbar sind. Setzen Sie den Wert auf > 0, um weitere Ebenen anzuzeigen. Setzen Sie den Wert auf -1, um alle Teile der Part-DB innerhalb einer einzigen Kategorie in KiCad anzuzeigen.</target>
|
||||
<target><![CDATA[Dieser Wert bestimmt die Tiefe des Kategoriebaums, der in KiCad sichtbar ist. 0 bedeutet, dass nur die Kategorien der obersten Ebene sichtbar sind. Setzen Sie den Wert auf > 0, um weitere Ebenen anzuzeigen. Setzen Sie den Wert auf -1, um alle Teile der Part-DB innerhalb einer einzigen Kategorie in KiCad anzuzeigen.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VwvmcWE" name="settings.behavior.sidebar">
|
||||
|
|
@ -12848,7 +12926,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="jc0JTvL" name="settings.behavior.sidebar.items.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.sidebar.items.help</source>
|
||||
<target>Die Menüs, die standardmäßig in der Seitenleiste angezeigt werden. Die Reihenfolge der Elemente kann per Drag & Drop geändert werden.</target>
|
||||
<target><![CDATA[Die Menüs, die standardmäßig in der Seitenleiste angezeigt werden. Die Reihenfolge der Elemente kann per Drag & Drop geändert werden.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gVSWDkE" name="settings.behavior.sidebar.rootNodeEnabled">
|
||||
|
|
@ -12896,7 +12974,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="SUD8H3b" name="settings.behavior.table.parts_default_columns.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.table.parts_default_columns.help</source>
|
||||
<target>Die Spalten, die standardmäßig in Bauteiltabellen angezeigt werden sollen. Die Reihenfolge der Elemente kann per Drag & Drop geändert werden.</target>
|
||||
<target><![CDATA[Die Spalten, die standardmäßig in Bauteiltabellen angezeigt werden sollen. Die Reihenfolge der Elemente kann per Drag & Drop geändert werden.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="hazr_g5" name="settings.ips.oemsecrets">
|
||||
|
|
@ -12950,7 +13028,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="KLJYfJ0" name="settings.ips.oemsecrets.sortMode.M">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.oemsecrets.sortMode.M</source>
|
||||
<target>Vollständigkeit & Herstellername</target>
|
||||
<target><![CDATA[Vollständigkeit & Herstellername]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8C9ijHM" name="entity.export.flash.error.no_entities">
|
||||
|
|
@ -13109,6 +13187,54 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<target>Wenn Sie Wechselkurse zwischen Nicht-Euro-Währungen benötigen, können Sie hier einen API-Schlüssel von fixer.io eingeben.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yBc_psK" name="settings.misc.ipn_suggest">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest</source>
|
||||
<target>Bauteil IPN-Vorschlagsliste</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="rMHQxvM" name="settings.misc.ipn_suggest.regex">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex</source>
|
||||
<target>Regex</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jGPeETQ" name="settings.misc.ipn_suggest.regex_help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help</source>
|
||||
<target>Hilfetext</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gsSNHJd" name="settings.misc.ipn_suggest.regex_help_description">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help_description</source>
|
||||
<target>Definieren Sie Ihren eigenen Nutzer-Hilfetext zur Regex Formatvorgabe.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="irHQep1" name="settings.misc.ipn_suggest.autoAppendSuffix">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.autoAppendSuffix</source>
|
||||
<target>Hänge ein inkrementelles Suffix an, wenn eine IPN bereits durch ein anderes Bauteil verwendet wird.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="MHvNzxt" name="settings.misc.ipn_suggest.suggestPartDigits">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits</source>
|
||||
<target>Stellen für numerisches Inkrement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kH.lU0y" name="settings.misc.ipn_suggest.useDuplicateDescription">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.useDuplicateDescription</source>
|
||||
<target>Verwende Bauteilebeschreibung zur Ermittlung der nächsten IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="1RN3Xwz" name="settings.misc.ipn_suggest.suggestPartDigits.help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits.help</source>
|
||||
<target>Die Anzahl der Ziffern, die für die inkrementale Nummerierung von Teilen im IPN-Vorschlagssystem verwendet werden.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Ffr5xYM" name="settings.behavior.part_info">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.part_info</source>
|
||||
|
|
@ -13562,7 +13688,7 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
<unit id="FsrRdkp" name="settings.behavior.homepage.items.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.homepage.items.help</source>
|
||||
<target>Die Elemente, die auf der Startseite angezeigt werden sollen. Die Reihenfolge kann per Drag & Drop geändert werden.</target>
|
||||
<target><![CDATA[Die Elemente, die auf der Startseite angezeigt werden sollen. Die Reihenfolge kann per Drag & Drop geändert werden.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="CYw3_pS" name="settings.system.customization.showVersionOnHomepage">
|
||||
|
|
@ -14304,5 +14430,11 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
|||
Dies ist auf der Informationsquellen Übersichtsseite möglich.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="L4nq52R" name="settings.misc.ipn_suggest.useDuplicateDescription.help">
|
||||
<segment>
|
||||
<source>settings.misc.ipn_suggest.useDuplicateDescription.help</source>
|
||||
<target>Wenn aktiviert, wird die Bauteil-Beschreibung verwendet, um vorhandene Teile mit derselben Beschreibung zu finden und die nächste verfügbare IPN für die Vorschlagsliste zu ermitteln, indem der numerische Suffix entsprechend erhöht wird.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -1589,5 +1589,83 @@
|
|||
<target>Προσαρμοσμένη κατάσταση μέρους</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Πρόθεμα εξαρτήματος IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>π.χ. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Μια προτεινόμενη πρόθεμα κατά την εισαγωγή του IPN ενός τμήματος.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Προτάσεις χωρίς αύξηση μέρους</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Προτάσεις με αριθμητικές αυξήσεις μερών</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Τρέχουσα προδιαγραφή IPN του εξαρτήματος</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Επόμενη δυνατή προδιαγραφή IPN βάσει της ίδιας περιγραφής εξαρτήματος</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Το IPN πρόθεμα της άμεσης κατηγορίας είναι κενό, καθορίστε το στην κατηγορία "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Πρόθεμα IPN για την άμεση κατηγορία</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Πρόθεμα IPN της άμεσης κατηγορίας και μιας ειδικής για μέρος αύξησης</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>Προθέματα IPN με ιεραρχική σειρά κατηγοριών των προθέτων γονέων</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>Προθέματα IPN με ιεραρχική σειρά κατηγοριών των προθέτων γονέων και συγκεκριμένη αύξηση για το μέρος</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Δημιουργήστε πρώτα ένα εξάρτημα και αντιστοιχίστε το σε μια κατηγορία: με τις υπάρχουσες κατηγορίες και τα δικά τους προθέματα IPN, η ονομασία IPN για το εξάρτημα μπορεί να προταθεί αυτόματα</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@
|
|||
</notes>
|
||||
<segment state="final">
|
||||
<source>part.info.timetravel_hint</source>
|
||||
<target>This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i></target>
|
||||
<target><![CDATA[This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="3exvSpl" name="standard.label">
|
||||
|
|
@ -737,10 +737,10 @@
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>user.edit.tfa.disable_tfa_message</source>
|
||||
<target>This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>!
|
||||
<br>
|
||||
The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br>
|
||||
<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b></target>
|
||||
<target><![CDATA[This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>!
|
||||
<br>
|
||||
The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br>
|
||||
<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="APsHYu0" name="user.edit.tfa.disable_tfa.btn">
|
||||
|
|
@ -891,9 +891,9 @@ The user will have to set up all two-factor authentication methods again and pri
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>entity.delete.message</source>
|
||||
<target>This can not be undone!
|
||||
<br>
|
||||
Sub elements will be moved upwards.</target>
|
||||
<target><![CDATA[This can not be undone!
|
||||
<br>
|
||||
Sub elements will be moved upwards.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2tKAqHw" name="entity.delete">
|
||||
|
|
@ -1447,7 +1447,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="final">
|
||||
<source>homepage.github.text</source>
|
||||
<target>Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a></target>
|
||||
<target><![CDATA[Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="D5OKsgU" name="homepage.help.caption">
|
||||
|
|
@ -1469,7 +1469,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>homepage.help.text</source>
|
||||
<target>Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a></target>
|
||||
<target><![CDATA[Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dnirx4v" name="homepage.forum.caption">
|
||||
|
|
@ -1711,7 +1711,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.fallback</source>
|
||||
<target>If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info</target>
|
||||
<target><![CDATA[If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DduL9Hu" name="email.pw_reset.username">
|
||||
|
|
@ -1741,7 +1741,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.valid_unit %date%</source>
|
||||
<target>The reset token will be valid until <i>%date%</i>.</target>
|
||||
<target><![CDATA[The reset token will be valid until <i>%date%</i>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8sBnjRy" name="orderdetail.delete">
|
||||
|
|
@ -1848,6 +1848,66 @@ Sub elements will be moved upwards.</target>
|
|||
<target>Advanced</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="_iVXTDt" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Suggestions without part increment</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="7.yHB9w" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Suggestions with numeric part increment</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="H1o.JFb" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Current IPN specification of the part</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="wt.Rn7C" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Next possible IPN specification based on an identical part description</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="RXA8jNa" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>IPN prefix of direct category empty, specify one in category "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="fdSIyqC" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>IPN prefix of direct category</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="0l7ST7C" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>IPN prefix of direct category and part-specific increment</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="1Y9qoug" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN prefixes with hierarchical category order of parent-prefix(es)</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a6_204L" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN prefixes with hierarchical category order of parent-prefix(es) and part-specific increment</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VS8w2qp" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Please create part at first and assign it to a category: with existing categories and their own IPN prefix, the IPN for the part can be suggested automatically</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -3584,8 +3644,8 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.disable.confirm_message</source>
|
||||
<target>If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br>
|
||||
Also note that without two-factor authentication, your account is no longer as well protected against attackers!</target>
|
||||
<target><![CDATA[If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br>
|
||||
Also note that without two-factor authentication, your account is no longer as well protected against attackers!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yu9MSt5" name="tfa_google.disabled_message">
|
||||
|
|
@ -3605,7 +3665,7 @@ Also note that without two-factor authentication, your account is no longer as w
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.step.download</source>
|
||||
<target>Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)</target>
|
||||
<target><![CDATA[Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="eriwJoR" name="tfa_google.step.scan">
|
||||
|
|
@ -3847,8 +3907,8 @@ Also note that without two-factor authentication, your account is no longer as w
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_trustedDevices.explanation</source>
|
||||
<target>When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed.
|
||||
If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here.</target>
|
||||
<target><![CDATA[When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed.
|
||||
If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="FZINq8z" name="tfa_trustedDevices.invalidate.confirm_title">
|
||||
|
|
@ -5325,7 +5385,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>label_options.lines_mode.help</source>
|
||||
<target>If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a> for more information.</target>
|
||||
<target><![CDATA[If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a> for more information.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="isvxbiX" name="label_options.page_size.label">
|
||||
|
|
@ -6989,6 +7049,12 @@ If you have done this incorrectly or if a computer is no longer trusted, you can
|
|||
<target>Name filter</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a37rx0r" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Part IPN Prefix</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -7187,15 +7253,15 @@ Exampletown</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>mass_creation.lines.placeholder</source>
|
||||
<target>Element 1
|
||||
<target><![CDATA[Element 1
|
||||
Element 1.1
|
||||
Element 1.1.1
|
||||
Element 1.2
|
||||
Element 2
|
||||
Element 3
|
||||
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2</target>
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="TWSqPFi" name="entity.mass_creation.btn">
|
||||
|
|
@ -9480,25 +9546,25 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="r4vDLAt" name="filter.parameter_value_constraint.operator.<">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<</source>
|
||||
<target>Typ. Value <</target>
|
||||
<target><![CDATA[Typ. Value <]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="X9SA3UP" name="filter.parameter_value_constraint.operator.>">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.></source>
|
||||
<target>Typ. Value ></target>
|
||||
<target><![CDATA[Typ. Value >]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="BQGaoQS" name="filter.parameter_value_constraint.operator.<=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<=</source>
|
||||
<target>Typ. Value <=</target>
|
||||
<target><![CDATA[Typ. Value <=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2ha3P6g" name="filter.parameter_value_constraint.operator.>=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.>=</source>
|
||||
<target>Typ. Value >=</target>
|
||||
<target><![CDATA[Typ. Value >=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4DaBace" name="filter.parameter_value_constraint.operator.BETWEEN">
|
||||
|
|
@ -9606,7 +9672,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="4tHhDtU" name="parts_list.search.searching_for">
|
||||
<segment state="translated">
|
||||
<source>parts_list.search.searching_for</source>
|
||||
<target>Searching parts with keyword <b>%keyword%</b></target>
|
||||
<target><![CDATA[Searching parts with keyword <b>%keyword%</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4vomKLa" name="parts_list.search_options.caption">
|
||||
|
|
@ -10266,13 +10332,13 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="NdZ1t7a" name="project.builds.number_of_builds_possible">
|
||||
<segment state="translated">
|
||||
<source>project.builds.number_of_builds_possible</source>
|
||||
<target>You have enough stocked to build <b>%max_builds%</b> builds of this project.</target>
|
||||
<target><![CDATA[You have enough stocked to build <b>%max_builds%</b> builds of this project.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="iuSpPbg" name="project.builds.check_project_status">
|
||||
<segment state="translated">
|
||||
<source>project.builds.check_project_status</source>
|
||||
<target>The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status!</target>
|
||||
<target><![CDATA[The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Y7vSSxi" name="project.builds.following_bom_entries_miss_instock_n">
|
||||
|
|
@ -10365,16 +10431,28 @@ Element 1 -> Element 1.2</target>
|
|||
<target>e.g "/Capacitor \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5zV57Ks" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>e.g "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>A PCRE-compatible regular expression, which a part name have to match.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="f3gkGc9" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>A prefix suggested when entering the IPN of a part.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
<target>Use -> to create nested structures, e.g. "Node 1->Node 1.1"</target>
|
||||
<target><![CDATA[Use -> to create nested structures, e.g. "Node 1->Node 1.1"]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
||||
|
|
@ -10398,13 +10476,13 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="XLnXtsR" name="homepage.first_steps.introduction">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.introduction</source>
|
||||
<target>Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures:</target>
|
||||
<target><![CDATA[Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures:]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q79MOIk" name="homepage.first_steps.create_part">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.create_part</source>
|
||||
<target>Or you can directly <a href="%url%">create a new part</a>.</target>
|
||||
<target><![CDATA[Or you can directly <a href="%url%">create a new part</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vplYq4f" name="homepage.first_steps.hide_hint">
|
||||
|
|
@ -10416,7 +10494,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="MJoZl4f" name="homepage.forum.text">
|
||||
<segment state="translated">
|
||||
<source>homepage.forum.text</source>
|
||||
<target>For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a></target>
|
||||
<target><![CDATA[For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YsukbnK" name="log.element_edited.changed_fields.category">
|
||||
|
|
@ -11082,7 +11160,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="p_IxB9K" name="parts.import.help_documentation">
|
||||
<segment state="translated">
|
||||
<source>parts.import.help_documentation</source>
|
||||
<target>See the <a href="%link%">documentation</a> for more information on the file format.</target>
|
||||
<target><![CDATA[See the <a href="%link%">documentation</a> for more information on the file format.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="awbvhVq" name="parts.import.help">
|
||||
|
|
@ -11274,7 +11352,7 @@ Element 1 -> Element 1.2</target>
|
|||
<unit id="o5u.Nnz" name="part.filter.lessThanDesired">
|
||||
<segment state="translated">
|
||||
<source>part.filter.lessThanDesired</source>
|
||||
<target>In stock less than desired (total amount < min. amount)</target>
|
||||
<target><![CDATA[In stock less than desired (total amount < min. amount)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YN9eLcZ" name="part.filter.lotOwner">
|
||||
|
|
@ -12086,13 +12164,13 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="i68lU5x" name="part.merge.confirm.title">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.title</source>
|
||||
<target>Do you really want to merge <b>%other%</b> into <b>%target%</b>?</target>
|
||||
<target><![CDATA[Do you really want to merge <b>%other%</b> into <b>%target%</b>?]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="k0anzYV" name="part.merge.confirm.message">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.message</source>
|
||||
<target><b>%other%</b> will be deleted, and the part will be saved with the shown information.</target>
|
||||
<target><![CDATA[<b>%other%</b> will be deleted, and the part will be saved with the shown information.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="mmW5Yl1" name="part.info.merge_modal.title">
|
||||
|
|
@ -12446,7 +12524,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="p7LGAIX" name="settings.ips.element14.apiKey.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.element14.apiKey.help</source>
|
||||
<target>You can register for an API key on <a href="https://partner.element14.com/">https://partner.element14.com/</a>.</target>
|
||||
<target><![CDATA[You can register for an API key on <a href="https://partner.element14.com/">https://partner.element14.com/</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ZdUHpZc" name="settings.ips.element14.storeId">
|
||||
|
|
@ -12458,7 +12536,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="XXGUxF6" name="settings.ips.element14.storeId.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.element14.storeId.help</source>
|
||||
<target>The store domain to retrieve the data from. This decides the language and currency of results. See <a href="https://partner.element14.com/docs/Product_Search_API_REST__Description">here</a> for a list of valid domains.</target>
|
||||
<target><![CDATA[The store domain to retrieve the data from. This decides the language and currency of results. See <a href="https://partner.element14.com/docs/Product_Search_API_REST__Description">here</a> for a list of valid domains.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="WKWZIm2" name="settings.ips.tme">
|
||||
|
|
@ -12476,7 +12554,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="_pYLrPT" name="settings.ips.tme.token.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.tme.token.help</source>
|
||||
<target>You can get an API token and secret on <a href="https://developers.tme.eu/en/">https://developers.tme.eu/en/</a>.</target>
|
||||
<target><![CDATA[You can get an API token and secret on <a href="https://developers.tme.eu/en/">https://developers.tme.eu/en/</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yswx4bq" name="settings.ips.tme.secret">
|
||||
|
|
@ -12524,7 +12602,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="gu.JlpT" name="settings.ips.mouser.apiKey.help">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.mouser.apiKey.help</source>
|
||||
<target>You can register for an API key on <a href="https://eu.mouser.com/api-hub/">https://eu.mouser.com/api-hub/</a>.</target>
|
||||
<target><![CDATA[You can register for an API key on <a href="https://eu.mouser.com/api-hub/">https://eu.mouser.com/api-hub/</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q66CNjw" name="settings.ips.mouser.searchLimit">
|
||||
|
|
@ -12602,7 +12680,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="kKv0J3." name="settings.system.attachments">
|
||||
<segment state="translated">
|
||||
<source>settings.system.attachments</source>
|
||||
<target>Attachments & Files</target>
|
||||
<target><![CDATA[Attachments & Files]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsRff8T" name="settings.system.attachments.maxFileSize">
|
||||
|
|
@ -12626,7 +12704,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="T.PBu5P" name="settings.system.attachments.allowDownloads.help">
|
||||
<segment state="translated">
|
||||
<source>settings.system.attachments.allowDownloads.help</source>
|
||||
<target>With this option users can download external files into Part-DB by providing an URL. <b>Attention: This can be a security issue, as it might allow users to access intranet ressources via Part-DB!</b></target>
|
||||
<target><![CDATA[With this option users can download external files into Part-DB by providing an URL. <b>Attention: This can be a security issue, as it might allow users to access intranet ressources via Part-DB!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id=".OyihML" name="settings.system.attachments.downloadByDefault">
|
||||
|
|
@ -12800,8 +12878,8 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="0GRlEe5" name="settings.system.localization.base_currency_description">
|
||||
<segment state="translated">
|
||||
<source>settings.system.localization.base_currency_description</source>
|
||||
<target>The currency that is used to store price information and exchange rates in. This currency is assumed, when no currency is set for a price information.
|
||||
<b>Please note that the currencies are not converted, when changing this value. So changing the default currency after you already added price information, will result in wrong prices!</b></target>
|
||||
<target><![CDATA[The currency that is used to store price information and exchange rates in. This currency is assumed, when no currency is set for a price information.
|
||||
<b>Please note that the currencies are not converted, when changing this value. So changing the default currency after you already added price information, will result in wrong prices!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cvpTUeY" name="settings.system.privacy">
|
||||
|
|
@ -12831,7 +12909,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="w07P3Dt" name="settings.misc.kicad_eda.category_depth.help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.kicad_eda.category_depth.help</source>
|
||||
<target>This value determines the depth of the category tree, that is visible inside KiCad. 0 means that only the top level categories are visible. Set to a value > 0 to show more levels. Set to -1, to show all parts of Part-DB inside a sigle cnategory in KiCad.</target>
|
||||
<target><![CDATA[This value determines the depth of the category tree, that is visible inside KiCad. 0 means that only the top level categories are visible. Set to a value > 0 to show more levels. Set to -1, to show all parts of Part-DB inside a sigle cnategory in KiCad.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VwvmcWE" name="settings.behavior.sidebar">
|
||||
|
|
@ -12849,7 +12927,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="jc0JTvL" name="settings.behavior.sidebar.items.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.sidebar.items.help</source>
|
||||
<target>The menus which appear at the sidebar by default. Order of items can be changed via drag & drop.</target>
|
||||
<target><![CDATA[The menus which appear at the sidebar by default. Order of items can be changed via drag & drop.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gVSWDkE" name="settings.behavior.sidebar.rootNodeEnabled">
|
||||
|
|
@ -12897,7 +12975,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="SUD8H3b" name="settings.behavior.table.parts_default_columns.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.table.parts_default_columns.help</source>
|
||||
<target>The columns to show by default in part tables. Order of items can be changed via drag & drop.</target>
|
||||
<target><![CDATA[The columns to show by default in part tables. Order of items can be changed via drag & drop.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="hazr_g5" name="settings.ips.oemsecrets">
|
||||
|
|
@ -12951,7 +13029,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="KLJYfJ0" name="settings.ips.oemsecrets.sortMode.M">
|
||||
<segment state="translated">
|
||||
<source>settings.ips.oemsecrets.sortMode.M</source>
|
||||
<target>Completeness & Manufacturer name</target>
|
||||
<target><![CDATA[Completeness & Manufacturer name]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8C9ijHM" name="entity.export.flash.error.no_entities">
|
||||
|
|
@ -13110,6 +13188,54 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<target>If you need exchange rates between non-euro currencies, you can input an API key from fixer.io here.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yBc_psK" name="settings.misc.ipn_suggest">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest</source>
|
||||
<target>Part IPN Suggest</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="rMHQxvM" name="settings.misc.ipn_suggest.regex">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex</source>
|
||||
<target>Regex</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jGPeETQ" name="settings.misc.ipn_suggest.regex_help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help</source>
|
||||
<target>Help text</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gsSNHJd" name="settings.misc.ipn_suggest.regex_help_description">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.regex_help_description</source>
|
||||
<target>Define your own user help text for the Regex format specification.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="irHQep1" name="settings.misc.ipn_suggest.autoAppendSuffix">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.autoAppendSuffix</source>
|
||||
<target>Add incremental suffix to IPN, if the value is already used by another part</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="MHvNzxt" name="settings.misc.ipn_suggest.suggestPartDigits">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits</source>
|
||||
<target>Increment Digits</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kH.lU0y" name="settings.misc.ipn_suggest.useDuplicateDescription">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.useDuplicateDescription</source>
|
||||
<target>Use part description to find next available IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="1RN3Xwz" name="settings.misc.ipn_suggest.suggestPartDigits.help">
|
||||
<segment state="translated">
|
||||
<source>settings.misc.ipn_suggest.suggestPartDigits.help</source>
|
||||
<target>The number of digits used for the incremental numbering of parts in the IPN (Internal Part Number) suggestion system.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Ffr5xYM" name="settings.behavior.part_info">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.part_info</source>
|
||||
|
|
@ -13563,7 +13689,7 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="FsrRdkp" name="settings.behavior.homepage.items.help">
|
||||
<segment state="translated">
|
||||
<source>settings.behavior.homepage.items.help</source>
|
||||
<target>The items to show at the homepage. Order can be changed via drag & drop.</target>
|
||||
<target><![CDATA[The items to show at the homepage. Order can be changed via drag & drop.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="CYw3_pS" name="settings.system.customization.showVersionOnHomepage">
|
||||
|
|
@ -14330,5 +14456,17 @@ You can do this in the provider info list.</target>
|
|||
You can do this in the provider info list.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="L4nq52R" name="settings.misc.ipn_suggest.useDuplicateDescription.help">
|
||||
<segment>
|
||||
<source>settings.misc.ipn_suggest.useDuplicateDescription.help</source>
|
||||
<target>When enabled, the part’s description is used to find existing parts with the same description and to determine the next available IPN by incrementing their numeric suffix for the suggestion list.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="NIw6dtz" name="settings.misc.ipn_suggest.regex.help">
|
||||
<segment>
|
||||
<source>settings.misc.ipn_suggest.regex.help</source>
|
||||
<target>A PCRE-compatible regular expression every IPN has to fulfill. Leave empty to allow all everything as IPN. </target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -1848,6 +1848,66 @@ Subelementos serán desplazados hacia arriba.</target>
|
|||
<target>Avanzado</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Sugerencias sin incremento de parte</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Sugerencias con incrementos numéricos de partes</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Especificación actual de IPN de la pieza</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Siguiente especificación de IPN posible basada en una descripción idéntica de la pieza</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>El prefijo IPN de la categoría directa está vacío, especifíquelo en la categoría "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Prefijo IPN de la categoría directa</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Prefijo IPN de la categoría directa y un incremento específico de la pieza</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>Prefijos IPN con orden jerárquico de categorías de prefijos principales</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>Prefijos IPN con orden jerárquico de categorías de prefijos principales y un incremento específico para la parte</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Primero cree un componente y asígnele una categoría: con las categorías existentes y sus propios prefijos IPN, el identificador IPN para el componente puede ser sugerido automáticamente</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6988,6 +7048,12 @@ Subelementos serán desplazados hacia arriba.</target>
|
|||
<target>Filtro de nombre</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Prefijo de IPN de la pieza</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10308,12 +10374,24 @@ Elemento 3</target>
|
|||
<target>p.ej. "/Condensador \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>p.ej. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Una expresión regular compatible con PCRE, la cual debe coincidir con el nombre de un componente.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Un prefijo sugerido al ingresar el IPN de una parte.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
|
|
@ -1826,6 +1826,66 @@ Show/Hide sidebar</target>
|
|||
<target>Avancé</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Suggestions sans incrément de partie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Propositions avec incréments numériques de parties</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Spécification IPN actuelle pour la pièce</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Prochaine spécification IPN possible basée sur une description identique de la pièce</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Le préfixe IPN de la catégorie directe est vide, veuillez le spécifier dans la catégorie "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Préfixe IPN de la catégorie directe</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Préfixe IPN de la catégorie directe et d'un incrément spécifique à la partie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>Préfixes IPN avec un ordre hiérarchique des catégories des préfixes parents</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>Préfixes IPN avec un ordre hiérarchique des catégories des préfixes parents et un incrément spécifique à la pièce</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Créez d'abord une pièce et assignez-la à une catégorie : avec les catégories existantes et leurs propres préfixes IPN, l'identifiant IPN pour la pièce peut être proposé automatiquement</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="uc9NwcF" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6930,6 +6990,12 @@ Si vous avez fait cela de manière incorrecte ou si un ordinateur n'est plus fia
|
|||
<target>Filtre de nom</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Préfixe de pièce IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="UH78POJ" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -9151,5 +9217,17 @@ exemple de ville</target>
|
|||
<target>État personnalisé de la pièce</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>par ex. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Un préfixe suggéré lors de la saisie de l'IPN d'une pièce.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -1848,6 +1848,66 @@ I sub elementi saranno spostati verso l'alto.</target>
|
|||
<target>Avanzate</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Suggerimenti senza incremento di parte</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Suggerimenti con incrementi numerici delle parti</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Specifica IPN attuale per il pezzo</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Prossima specifica IPN possibile basata su una descrizione identica del pezzo</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Il prefisso IPN della categoria diretta è vuoto, specificarlo nella categoria "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Prefisso IPN della categoria diretta</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Prefisso IPN della categoria diretta e di un incremento specifico della parte</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>Prefissi IPN con ordine gerarchico delle categorie dei prefissi padre</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>Prefissi IPN con ordine gerarchico delle categorie dei prefissi padre e un incremento specifico per il pezzo</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Crea prima un componente e assegnagli una categoria: con le categorie esistenti e i loro propri prefissi IPN, l'identificativo IPN per il componente può essere suggerito automaticamente</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6990,6 +7050,12 @@ Se è stato fatto in modo errato o se un computer non è più attendibile, puoi
|
|||
<target>Filtro nome</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Prefisso parte IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10310,12 +10376,24 @@ Element 3</target>
|
|||
<target>es. "/Condensatore \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>es. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Un'espressione regolare compatibile con PCRE che il nome del componente deve soddisfare.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Un prefisso suggerito durante l'inserimento dell'IPN di una parte.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
|
|
@ -1826,6 +1826,66 @@
|
|||
<target>詳細</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>部品の増加なしの提案。</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>パーツの数値インクリメントを含む提案</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>部品の現在のIPN仕様</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>同じ部品説明に基づく次の可能なIPN仕様</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>直接カテゴリの IPN プレフィックスが空です。「%name%」カテゴリで指定してください</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>直接カテゴリのIPNプレフィックス</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>直接カテゴリのIPNプレフィックスと部品特有のインクリメント</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>親プレフィックスの階層カテゴリ順のIPNプレフィックス</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>親プレフィックスの階層カテゴリ順とパーツ固有の増分のIPNプレフィックス</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>まずはコンポーネントを作成し、それをカテゴリに割り当ててください:既存のカテゴリとそれぞれのIPNプレフィックスを基に、コンポーネントのIPNを自動的に提案できます</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="uc9NwcF" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6931,6 +6991,12 @@
|
|||
<target>名前のフィルター</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>部品 IPN 接頭辞</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="UH78POJ" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -8888,5 +8954,17 @@ Exampletown</target>
|
|||
<target>部品のカスタム状態</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>例: "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>部品のIPN入力時に提案される接頭辞。</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -778,5 +778,83 @@
|
|||
<target>Aangepaste status van onderdeel</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>IPN-voorvoegsel van onderdeel</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>bijv. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Een voorgesteld voorvoegsel bij het invoeren van de IPN van een onderdeel.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Suggesties zonder toename van onderdelen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Suggesties met numerieke verhogingen van onderdelen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Huidige IPN-specificatie voor het onderdeel</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Volgende mogelijke IPN-specificatie op basis van een identieke onderdeelbeschrijving</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Het IPN-prefix van de directe categorie is leeg, geef het op in de categorie "%name%"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>IPN-prefix van de directe categorie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>IPN-voorvoegsel van de directe categorie en een onderdeel specifiek increment</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN-prefixen met een hiërarchische volgorde van hoofdcategorieën</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN-prefixen met een hiërarchische volgorde van hoofdcategorieën en een specifieke toename voor het onderdeel</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Maak eerst een component en wijs het toe aan een categorie: met de bestaande categorieën en hun eigen IPN-prefixen kan de IPN voor het component automatisch worden voorgesteld</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
|||
|
|
@ -1853,6 +1853,66 @@ Po usunięciu pod elementy zostaną przeniesione na górę.</target>
|
|||
<target>Zaawansowane</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Sugestie bez zwiększenia części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Propozycje z numerycznymi przyrostami części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Aktualna specyfikacja IPN dla części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Następna możliwa specyfikacja IPN na podstawie identycznego opisu części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Prefiks IPN kategorii bezpośredniej jest pusty, podaj go w kategorii "%name%".</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Prefiks IPN kategorii bezpośredniej</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Prefiks IPN bezpośredniej kategorii i specyficzny dla części przyrost</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>Prefiksy IPN z hierarchiczną kolejnością kategorii prefiksów nadrzędnych</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>Prefiksy IPN z hierarchiczną kolejnością kategorii prefiksów nadrzędnych i specyficznym przyrostem dla części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Najpierw utwórz komponent i przypisz go do kategorii: dzięki istniejącym kategoriom i ich własnym prefiksom IPN identyfikator IPN dla komponentu może być proponowany automatycznie</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6993,6 +7053,12 @@ Jeśli zrobiłeś to niepoprawnie lub komputer nie jest już godny zaufania, mo
|
|||
<target>Filtr nazwy</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Prefiks IPN części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10313,12 +10379,24 @@ Element 3</target>
|
|||
<target>np. "/Kondensator \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>np. "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>Wyrażenie regularne zgodne z PCRE, do którego musi pasować nazwa komponentu.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Een voorgesteld voorvoegsel bij het invoeren van de IPN van een onderdeel.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
|
|
@ -1856,6 +1856,66 @@
|
|||
<target>Расширенные</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Предложения без увеличения частей.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>Предложения с числовыми приращениями частей</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>Текущая спецификация IPN для детали</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>Следующая возможная спецификация IPN на основе идентичного описания детали</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>Префикс IPN для прямой категории пуст, укажите его в категории «%name%».</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>Префикс IPN для прямой категории</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>Префикс IPN прямой категории и специфическое для части приращение</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>IPN-префиксы с иерархическим порядком категорий родительских префиксов</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>IPN-префиксы с иерархическим порядком категорий родительских префиксов и специфическим увеличением для компонента</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>Сначала создайте компонент и назначьте ему категорию: на основе существующих категорий и их собственных IPN-префиксов идентификатор IPN для компонента может быть предложен автоматически</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c3S4jwK" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -7000,6 +7060,12 @@
|
|||
<target>Фильтр по имени</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>Префикс IPN детали</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yY_ld.7" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10317,12 +10383,24 @@
|
|||
<target>e.g "/Конденсатор \d+ nF/i"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>e.g "B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DL.TreI" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>PCRE-совместимое регулярное выражение которому должно соответствовать имя компонента.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>Предлагаемый префикс при вводе IPN детали.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
|
|
@ -1856,6 +1856,66 @@
|
|||
<target>高级</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1k7Blf" name="part.edit.tab.advanced.ipn.commonSectionHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.commonSectionHeader</source>
|
||||
<target>Sugestie bez zwiększenia części</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2achA.b" name="part.edit.tab.advanced.ipn.partIncrementHeader">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.partIncrementHeader</source>
|
||||
<target>包含部件数值增量的建议</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a7jKe3c" name="part.edit.tab.advanced.ipn.prefix.description.current-increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.current-increment</source>
|
||||
<target>部件的当前IPN规格</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kEco9iX" name="part.edit.tab.advanced.ipn.prefix.description.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.description.increment</source>
|
||||
<target>基于相同部件描述的下一个可能的IPN规格</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||
<target>直接类别的 IPN 前缀为空,请在类别“%name%”中指定。</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ec2DiJd" name="part.edit.tab.advanced.ipn.prefix.direct_category">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category</source>
|
||||
<target>直接类别的IPN前缀</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2e.kJb4" name="part.edit.tab.advanced.ipn.prefix.direct_category.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.direct_category.increment</source>
|
||||
<target>直接类别的IPN前缀和部件特定的增量</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ba1GCoq" name="part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.no_increment</source>
|
||||
<target>具有父级前缀层级类别顺序的IPN前缀</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="d1uVFa3" name="part.edit.tab.advanced.ipn.prefix.hierarchical.increment">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.hierarchical.increment</source>
|
||||
<target>具有父级前缀层级类别顺序和组件特定增量的IPN前缀</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a4rPagW" name="part.edit.tab.advanced.ipn.prefix.not_saved">
|
||||
<segment state="translated">
|
||||
<source>part.edit.tab.advanced.ipn.prefix.not_saved</source>
|
||||
<target>请先创建组件并将其分配到类别:基于现有类别及其专属的IPN前缀,可以自动建议组件的IPN</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="uc9NwcF" name="part.edit.tab.part_lots">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40</note>
|
||||
|
|
@ -6997,6 +7057,12 @@
|
|||
<target>名称过滤器</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dsG4xTQ" name="category.edit.part_ipn_prefix">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix</source>
|
||||
<target>部件 IPN 前缀</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="UH78POJ" name="category.edit.default_description">
|
||||
<notes>
|
||||
<note priority="1">obsolete</note>
|
||||
|
|
@ -10316,12 +10382,24 @@ Element 3</target>
|
|||
<target> </target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OXeGz1A" name="category.edit.part_ipn_prefix.placeholder">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.placeholder</source>
|
||||
<target>例如:"B12A"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="QFgP__5" name="category.edit.partname_regex.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.partname_regex.help</source>
|
||||
<target>与PCRE兼容的正则表达式,部分名称必须匹配。</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a1bUsfJ" name="category.edit.part_ipn_prefix.help">
|
||||
<segment state="translated">
|
||||
<source>category.edit.part_ipn_prefix.help</source>
|
||||
<target>输入零件IPN时建议的前缀。</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vr7oZKL" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue