mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-14 22:29:33 +00:00
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.
This commit is contained in:
parent
9c565cbaed
commit
0dc7dbdb03
20 changed files with 361 additions and 35 deletions
|
|
@ -78,6 +78,15 @@ export default class extends Controller {
|
||||||
editor_div.classList.add(...new_classes.split(","));
|
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
|
//This return is important! Otherwise we get mysterious errors in the console
|
||||||
//See: https://github.com/ckeditor/ckeditor5/issues/5897#issuecomment-628471302
|
//See: https://github.com/ckeditor/ckeditor5/issues/5897#issuecomment-628471302
|
||||||
return editor;
|
return editor;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ export default class extends Controller {
|
||||||
static values = {
|
static values = {
|
||||||
partId: Number,
|
partId: Number,
|
||||||
partCategoryId: Number,
|
partCategoryId: Number,
|
||||||
|
partDescription: String,
|
||||||
suggestions: Object,
|
suggestions: Object,
|
||||||
commonSectionHeader: String, // Dynamic header for common Prefixes
|
commonSectionHeader: String, // Dynamic header for common Prefixes
|
||||||
partIncrementHeader: String, // Dynamic header for new possible part increment
|
partIncrementHeader: String, // Dynamic header for new possible part increment
|
||||||
|
|
@ -15,6 +16,7 @@ export default class extends Controller {
|
||||||
connect() {
|
connect() {
|
||||||
this.configureAutocomplete();
|
this.configureAutocomplete();
|
||||||
this.watchCategoryChanges();
|
this.watchCategoryChanges();
|
||||||
|
this.watchDescriptionChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
templates = {
|
templates = {
|
||||||
|
|
@ -92,34 +94,6 @@ export default class extends Controller {
|
||||||
const panelLayout = document.createElement("div");
|
const panelLayout = document.createElement("div");
|
||||||
panelLayout.classList.add("aa-PanelLayout", "aa-Panel--scrollable");
|
panelLayout.classList.add("aa-PanelLayout", "aa-Panel--scrollable");
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section for prefixes part increment
|
// Section for prefixes part increment
|
||||||
if (prefixesPartIncrement.length) {
|
if (prefixesPartIncrement.length) {
|
||||||
const partIncrementSection = document.createElement("section");
|
const partIncrementSection = document.createElement("section");
|
||||||
|
|
@ -148,6 +122,34 @@ export default class extends Controller {
|
||||||
panelLayout.appendChild(partIncrementSection);
|
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);
|
panel.appendChild(panelLayout);
|
||||||
inputField.parentNode.appendChild(panel);
|
inputField.parentNode.appendChild(panel);
|
||||||
|
|
||||||
|
|
@ -176,25 +178,48 @@ export default class extends Controller {
|
||||||
|
|
||||||
watchCategoryChanges() {
|
watchCategoryChanges() {
|
||||||
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
|
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
|
||||||
|
const descriptionField = document.querySelector('[data-ipn-suggestion="descriptionField"]');
|
||||||
this.previousCategoryId = Number(this.partCategoryIdValue);
|
this.previousCategoryId = Number(this.partCategoryIdValue);
|
||||||
|
|
||||||
if (categoryField) {
|
if (categoryField) {
|
||||||
categoryField.addEventListener("change", () => {
|
categoryField.addEventListener("change", () => {
|
||||||
const categoryId = Number(categoryField.value);
|
const categoryId = Number(categoryField.value);
|
||||||
|
const description = String(descriptionField.value);
|
||||||
|
|
||||||
// Check whether the category has changed compared to the previous ID
|
// Check whether the category has changed compared to the previous ID
|
||||||
if (categoryId !== this.previousCategoryId) {
|
if (categoryId !== this.previousCategoryId) {
|
||||||
this.fetchNewSuggestions(categoryId);
|
this.fetchNewSuggestions(categoryId, description);
|
||||||
this.previousCategoryId = categoryId;
|
this.previousCategoryId = categoryId;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNewSuggestions(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 baseUrl = this.suggestUrlValue;
|
||||||
const partId = this.partIdValue;
|
const partId = this.partIdValue;
|
||||||
const url = `${baseUrl}?partId=${partId}&categoryId=${categoryId}`;
|
const truncatedDescription = description.length > 150 ? description.substring(0, 150) : description;
|
||||||
|
const encodedDescription = this.base64EncodeUtf8(truncatedDescription);
|
||||||
|
const url = `${baseUrl}?partId=${partId}&categoryId=${categoryId}&description=${encodedDescription}`;
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
@ -217,4 +242,9 @@ export default class extends Controller {
|
||||||
console.error("Errors when loading the new IPN-suggestions:", error);
|
console.error("Errors when loading the new IPN-suggestions:", error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
base64EncodeUtf8(text) {
|
||||||
|
const utf8Bytes = new TextEncoder().encode(text);
|
||||||
|
return btoa(String.fromCharCode(...utf8Bytes));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -464,7 +464,7 @@ final class PartController extends AbstractController
|
||||||
$template,
|
$template,
|
||||||
[
|
[
|
||||||
'part' => $new_part,
|
'part' => $new_part,
|
||||||
'ipnSuggestions' => $partRepository->autoCompleteIpn($data, $this->autocompletePartDigits),
|
'ipnSuggestions' => $partRepository->autoCompleteIpn($data, base64_encode($data->getDescription()), $this->autocompletePartDigits),
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
'merge_old_name' => $merge_infos['tname_before'] ?? null,
|
'merge_old_name' => $merge_infos['tname_before'] ?? null,
|
||||||
'merge_other' => $merge_infos['other_part'] ?? null,
|
'merge_other' => $merge_infos['other_part'] ?? null,
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,7 @@ class TypeaheadController extends AbstractController
|
||||||
$partId = null;
|
$partId = null;
|
||||||
}
|
}
|
||||||
$categoryId = $request->query->getInt('categoryId');
|
$categoryId = $request->query->getInt('categoryId');
|
||||||
|
$description = $request->query->getString('description');
|
||||||
|
|
||||||
/** @var Part $part */
|
/** @var Part $part */
|
||||||
$part = $partId !== null ? $entityManager->getRepository(Part::class)->find($partId) : new Part();
|
$part = $partId !== null ? $entityManager->getRepository(Part::class)->find($partId) : new Part();
|
||||||
|
|
@ -292,7 +293,7 @@ class TypeaheadController extends AbstractController
|
||||||
$clonedPart->setCategory($category);
|
$clonedPart->setCategory($category);
|
||||||
|
|
||||||
$partRepository = $entityManager->getRepository(Part::class);
|
$partRepository = $entityManager->getRepository(Part::class);
|
||||||
$ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $this->autocompletePartDigits);
|
$ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $description, $this->autocompletePartDigits);
|
||||||
|
|
||||||
return new JsonResponse($ipnSuggestions);
|
return new JsonResponse($ipnSuggestions);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ class PartBaseType extends AbstractType
|
||||||
'attr' => [
|
'attr' => [
|
||||||
'placeholder' => 'part.edit.description.placeholder',
|
'placeholder' => 'part.edit.description.placeholder',
|
||||||
'rows' => 2,
|
'rows' => 2,
|
||||||
|
'data-ipn-suggestion' => 'descriptionField',
|
||||||
],
|
],
|
||||||
])
|
])
|
||||||
->add('minAmount', SIUnitType::class, [
|
->add('minAmount', SIUnitType::class, [
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,30 @@ class PartRepository extends NamedDBElementRepository
|
||||||
return $qb->getQuery()->getResult();
|
return $qb->getQuery()->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function autoCompleteIpn(Part $part, int $autocompletePartDigits): array
|
/**
|
||||||
|
* 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 Base64-encoded description to assist in generating suggestions.
|
||||||
|
* @param int $autocompletePartDigits 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 $autocompletePartDigits): array
|
||||||
{
|
{
|
||||||
$category = $part->getCategory();
|
$category = $part->getCategory();
|
||||||
$ipnSuggestions = ['commonPrefixes' => [], 'prefixesPartIncrement' => []];
|
$ipnSuggestions = ['commonPrefixes' => [], 'prefixesPartIncrement' => []];
|
||||||
|
$description = base64_decode($description);
|
||||||
|
|
||||||
|
if (strlen($description) > 150) {
|
||||||
|
$description = substr($description, 0, 150);
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the category and ensure it's an instance of Category
|
// Validate the category and ensure it's an instance of Category
|
||||||
if ($category instanceof Category) {
|
if ($category instanceof Category) {
|
||||||
|
|
@ -127,6 +147,22 @@ class PartRepository extends NamedDBElementRepository
|
||||||
'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')
|
'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')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$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')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$ipnSuggestions['prefixesPartIncrement'][] = [
|
$ipnSuggestions['prefixesPartIncrement'][] = [
|
||||||
'title' => $currentPath . '-' . $increment,
|
'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')
|
'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')
|
||||||
|
|
@ -165,7 +201,62 @@ class PartRepository extends NamedDBElementRepository
|
||||||
return $ipnSuggestions;
|
return $ipnSuggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateNextPossiblePartIncrement(string $currentPath, Part $currentPart, int $autocompletePartDigits): string
|
/**
|
||||||
|
* 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 $autocompletePartDigits The number of digits reserved for the increment.
|
||||||
|
*
|
||||||
|
* @return string|null The next possible increment as a zero-padded string, or null if it cannot be generated.
|
||||||
|
*
|
||||||
|
* @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 $autocompletePartDigits): ?string
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('part');
|
$qb = $this->createQueryBuilder('part');
|
||||||
|
|
||||||
|
|
@ -213,4 +304,41 @@ class PartRepository extends NamedDBElementRepository
|
||||||
|
|
||||||
return str_pad((string) $nextIncrement, $autocompletePartDigits, '0', STR_PAD_LEFT);
|
return str_pad((string) $nextIncrement, $autocompletePartDigits, '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); // Entferne vorhandene "_<Zahl>"
|
||||||
|
|
||||||
|
if ($baseIpn === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate next free possible IPN
|
||||||
|
return $baseIpn . '_' . ($maxSuffix + 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
<div {{ stimulus_controller('elements/ipn_suggestion', {
|
<div {{ stimulus_controller('elements/ipn_suggestion', {
|
||||||
partId: part.id,
|
partId: part.id,
|
||||||
partCategoryId: part.category ? part.category.id : null,
|
partCategoryId: part.category ? part.category.id : null,
|
||||||
|
partDescription: part.description,
|
||||||
suggestions: ipnSuggestions,
|
suggestions: ipnSuggestions,
|
||||||
'commonSectionHeader': 'part.edit.tab.advanced.ipn.commonSectionHeader'|trans,
|
'commonSectionHeader': 'part.edit.tab.advanced.ipn.commonSectionHeader'|trans,
|
||||||
'partIncrementHeader': 'part.edit.tab.advanced.ipn.partIncrementHeader'|trans,
|
'partIncrementHeader': 'part.edit.tab.advanced.ipn.partIncrementHeader'|trans,
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,18 @@ Související prvky budou přesunuty nahoru.</target>
|
||||||
<target>Návrhy s číselnými přírůstky částí</target>
|
<target>Návrhy s číselnými přírůstky částí</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1862,6 +1862,18 @@ Underelementer vil blive flyttet opad.</target>
|
||||||
<target>Forslag med numeriske deleforøgelser</target>
|
<target>Forslag med numeriske deleforøgelser</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1853,6 +1853,18 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
||||||
<target>Vorschläge mit numerischen Teil-Inkrement</target>
|
<target>Vorschläge mit numerischen Teil-Inkrement</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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>Aktuelle IPN-Angabe des Bauteils</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ächstmögliche IPN-Angabe auf Basis der identischen Bauteil-Beschreibung</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -2506,6 +2506,18 @@
|
||||||
<target>Προτάσεις με αριθμητικές αυξήσεις μερών</target>
|
<target>Προτάσεις με αριθμητικές αυξήσεις μερών</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,18 @@ Sub elements will be moved upwards.</target>
|
||||||
<target>Suggestions with numeric part increment</target>
|
<target>Suggestions with numeric part increment</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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>Current IPN specification of the part</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>Next possible IPN specification based on an identical part description</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,18 @@ Subelementos serán desplazados hacia arriba.</target>
|
||||||
<target>Sugerencias con incrementos numéricos de partes</target>
|
<target>Sugerencias con incrementos numéricos de partes</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1832,6 +1832,18 @@ Show/Hide sidebar</target>
|
||||||
<target>Propositions avec incréments numériques de parties</target>
|
<target>Propositions avec incréments numériques de parties</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,18 @@ I sub elementi saranno spostati verso l'alto.</target>
|
||||||
<target>Suggerimenti con incrementi numerici delle parti</target>
|
<target>Suggerimenti con incrementi numerici delle parti</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1832,6 +1832,18 @@
|
||||||
<target>パーツの数値インクリメントを含む提案</target>
|
<target>パーツの数値インクリメントを含む提案</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1731,6 +1731,18 @@
|
||||||
<target>Suggesties met numerieke verhogingen van onderdelen</target>
|
<target>Suggesties met numerieke verhogingen van onderdelen</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1859,6 +1859,18 @@ Po usunięciu pod elementy zostaną przeniesione na górę.</target>
|
||||||
<target>Propozycje z numerycznymi przyrostami części</target>
|
<target>Propozycje z numerycznymi przyrostami części</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1862,6 +1862,18 @@
|
||||||
<target>Предложения с числовыми приращениями частей</target>
|
<target>Предложения с числовыми приращениями частей</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
|
|
@ -1862,6 +1862,18 @@
|
||||||
<target>包含部件数值增量的建议</target>
|
<target>包含部件数值增量的建议</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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">
|
<unit id="dB1ChKc" name="part.edit.tab.advanced.ipn.prefix_empty.direct_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue