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:
Marcel Diegelmann 2025-07-09 09:45:43 +02:00
parent a7665af6b8
commit b2b0f39ac6
20 changed files with 361 additions and 35 deletions

View file

@ -78,6 +78,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;

View file

@ -6,6 +6,7 @@ export default class extends Controller {
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
@ -15,6 +16,7 @@ export default class extends Controller {
connect() {
this.configureAutocomplete();
this.watchCategoryChanges();
this.watchDescriptionChanges();
}
templates = {
@ -92,34 +94,6 @@ export default class extends Controller {
const panelLayout = document.createElement("div");
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
if (prefixesPartIncrement.length) {
const partIncrementSection = document.createElement("section");
@ -148,6 +122,34 @@ export default class extends Controller {
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);
@ -176,25 +178,48 @@ export default class extends Controller {
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);
this.fetchNewSuggestions(categoryId, description);
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 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, {
method: "GET",
@ -217,4 +242,9 @@ export default class extends Controller {
console.error("Errors when loading the new IPN-suggestions:", error);
});
};
base64EncodeUtf8(text) {
const utf8Bytes = new TextEncoder().encode(text);
return btoa(String.fromCharCode(...utf8Bytes));
};
}

View file

@ -451,7 +451,7 @@ final class PartController extends AbstractController
$template,
[
'part' => $new_part,
'ipnSuggestions' => $partRepository->autoCompleteIpn($data, $this->autocompletePartDigits),
'ipnSuggestions' => $partRepository->autoCompleteIpn($data, base64_encode($data->getDescription()), $this->autocompletePartDigits),
'form' => $form,
'merge_old_name' => $merge_infos['tname_before'] ?? null,
'merge_other' => $merge_infos['other_part'] ?? null,

View file

@ -197,6 +197,7 @@ class TypeaheadController extends AbstractController
$partId = null;
}
$categoryId = $request->query->getInt('categoryId');
$description = $request->query->getString('description');
/** @var Part $part */
$part = $partId !== null ? $entityManager->getRepository(Part::class)->find($partId) : new Part();
@ -206,7 +207,7 @@ class TypeaheadController extends AbstractController
$clonedPart->setCategory($category);
$partRepository = $entityManager->getRepository(Part::class);
$ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $this->autocompletePartDigits);
$ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $description, $this->autocompletePartDigits);
return new JsonResponse($ipnSuggestions);
}

View file

@ -86,6 +86,7 @@ class PartBaseType extends AbstractType
'attr' => [
'placeholder' => 'part.edit.description.placeholder',
'rows' => 2,
'data-ipn-suggestion' => 'descriptionField',
],
])
->add('minAmount', SIUnitType::class, [

View file

@ -109,10 +109,30 @@ class PartRepository extends NamedDBElementRepository
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();
$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
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')
];
$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'][] = [
'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')
@ -165,7 +201,62 @@ class PartRepository extends NamedDBElementRepository
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');
@ -213,4 +304,41 @@ class PartRepository extends NamedDBElementRepository
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);
}
}

View file

@ -4,6 +4,7 @@
<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,

View file

@ -1854,6 +1854,18 @@ Související prvky budou přesunuty nahoru.</target>
<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>

View file

@ -1862,6 +1862,18 @@ Underelementer vil blive flyttet opad.</target>
<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>

View file

@ -1853,6 +1853,18 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
<target>Vorschläge mit numerischen Teil-Inkrement</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>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">
<segment state="translated">
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>

View file

@ -1565,6 +1565,18 @@
<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>

View file

@ -1854,6 +1854,18 @@ Sub elements will be moved upwards.</target>
<target>Suggestions with numeric part increment</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>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">
<segment state="translated">
<source>part.edit.tab.advanced.ipn.prefix_empty.direct_category</source>

View file

@ -1854,6 +1854,18 @@ Subelementos serán desplazados hacia arriba.</target>
<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>

View file

@ -1832,6 +1832,18 @@ Show/Hide sidebar</target>
<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>

View file

@ -1854,6 +1854,18 @@ I sub elementi saranno spostati verso l'alto.</target>
<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>

View file

@ -1832,6 +1832,18 @@
<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>

View file

@ -754,6 +754,18 @@
<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>

View file

@ -1859,6 +1859,18 @@ Po usunięciu pod elementy zostaną przeniesione na górę.</target>
<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>

View file

@ -1862,6 +1862,18 @@
<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>

View file

@ -1862,6 +1862,18 @@
<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>