fixed translation bug
This commit is contained in:
54
common.php
54
common.php
@ -279,10 +279,11 @@ function qdb_app_ui_string_entries(): array {
|
|||||||
$order = 0;
|
$order = 0;
|
||||||
foreach ($catalog['keys'] ?? [] as $key) {
|
foreach ($catalog['keys'] ?? [] as $key) {
|
||||||
$entries[] = [
|
$entries[] = [
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'type' => 'app_string',
|
'displayKey' => $key,
|
||||||
'entityId' => $key,
|
'type' => 'app_string',
|
||||||
'sortOrder' => $order++,
|
'entityId' => $key,
|
||||||
|
'sortOrder' => $order++,
|
||||||
'germanDefault' => $defaults[$key] ?? $key,
|
'germanDefault' => $defaults[$key] ?? $key,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -382,6 +383,24 @@ function qdb_put_translation(PDO $pdo, string $type, string $id, string $lang, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Short label for translation UI (Key column); full text stays in `key` for API lookup. */
|
||||||
|
function qdb_translation_display_key(array $e): string {
|
||||||
|
if (!empty($e['displayKey'])) {
|
||||||
|
return $e['displayKey'];
|
||||||
|
}
|
||||||
|
if (($e['type'] ?? '') === 'question' || ($e['type'] ?? '') === 'answer_option') {
|
||||||
|
$id = $e['entityId'] ?? '';
|
||||||
|
$pos = strrpos($id, '__');
|
||||||
|
return $pos !== false ? substr($id, $pos + 2) : $id;
|
||||||
|
}
|
||||||
|
return $e['key'] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function qdb_short_entity_label(string $entityId): string {
|
||||||
|
$pos = strrpos($entityId, '__');
|
||||||
|
return $pos !== false ? substr($entityId, $pos + 2) : $entityId;
|
||||||
|
}
|
||||||
|
|
||||||
function qdb_require_non_empty_german(string $text, string $label = 'German text'): void {
|
function qdb_require_non_empty_german(string $text, string $label = 'German text'): void {
|
||||||
if ($text === '') {
|
if ($text === '') {
|
||||||
json_error('MISSING_FIELDS', "$label is required", 400);
|
json_error('MISSING_FIELDS', "$label is required", 400);
|
||||||
@ -407,10 +426,11 @@ function qdb_translation_entry_lists(PDO $pdo, string $qnID): array {
|
|||||||
foreach ($dbQuestions as $dbQ) {
|
foreach ($dbQuestions as $dbQ) {
|
||||||
$qOrder = (int)($dbQ['orderIndex'] ?? 0);
|
$qOrder = (int)($dbQ['orderIndex'] ?? 0);
|
||||||
$contentEntries[] = [
|
$contentEntries[] = [
|
||||||
'key' => $dbQ['defaultText'],
|
'key' => $dbQ['defaultText'],
|
||||||
'type' => 'question',
|
'displayKey' => qdb_short_entity_label($dbQ['questionID']),
|
||||||
'entityId' => $dbQ['questionID'],
|
'type' => 'question',
|
||||||
'sortOrder' => $qOrder * 1000,
|
'entityId' => $dbQ['questionID'],
|
||||||
|
'sortOrder' => $qOrder * 1000,
|
||||||
];
|
];
|
||||||
|
|
||||||
$aoStmt = $pdo->prepare("
|
$aoStmt = $pdo->prepare("
|
||||||
@ -420,10 +440,11 @@ function qdb_translation_entry_lists(PDO $pdo, string $qnID): array {
|
|||||||
$aoStmt->execute([':qid' => $dbQ['questionID']]);
|
$aoStmt->execute([':qid' => $dbQ['questionID']]);
|
||||||
foreach ($aoStmt->fetchAll(PDO::FETCH_ASSOC) as $ao) {
|
foreach ($aoStmt->fetchAll(PDO::FETCH_ASSOC) as $ao) {
|
||||||
$contentEntries[] = [
|
$contentEntries[] = [
|
||||||
'key' => $ao['defaultText'],
|
'key' => $ao['defaultText'],
|
||||||
'type' => 'answer_option',
|
'displayKey' => qdb_short_entity_label($ao['answerOptionID']),
|
||||||
'entityId' => $ao['answerOptionID'],
|
'type' => 'answer_option',
|
||||||
'sortOrder' => $qOrder * 1000 + 10 + (int)($ao['orderIndex'] ?? 0),
|
'entityId' => $ao['answerOptionID'],
|
||||||
|
'sortOrder' => $qOrder * 1000 + 10 + (int)($ao['orderIndex'] ?? 0),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,10 +470,11 @@ function qdb_translation_entry_lists(PDO $pdo, string $qnID): array {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$stringEntries[] = [
|
$stringEntries[] = [
|
||||||
'key' => $sk,
|
'key' => $sk,
|
||||||
'type' => 'string',
|
'displayKey' => $sk,
|
||||||
'entityId' => $sk,
|
'type' => 'string',
|
||||||
'sortOrder' => $stringOrder++,
|
'entityId' => $sk,
|
||||||
|
'sortOrder' => $stringOrder++,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1103,12 +1103,13 @@ function bindEditorTransFiltering(entries) {
|
|||||||
let visibleMissing = 0;
|
let visibleMissing = 0;
|
||||||
root.querySelectorAll('.trans-list-item').forEach(row => {
|
root.querySelectorAll('.trans-list-item').forEach(row => {
|
||||||
const key = row.dataset.key?.toLowerCase() || '';
|
const key = row.dataset.key?.toLowerCase() || '';
|
||||||
|
const label = row.dataset.label?.toLowerCase() || '';
|
||||||
const rowType = row.dataset.type || '';
|
const rowType = row.dataset.type || '';
|
||||||
const german = row.querySelector('.trans-source-text')?.textContent?.toLowerCase()
|
const german = row.querySelector('.trans-source-text')?.textContent?.toLowerCase()
|
||||||
|| row.querySelector('[data-field="german"]')?.value?.toLowerCase() || '';
|
|| row.querySelector('[data-field="german"]')?.value?.toLowerCase() || '';
|
||||||
const val = row.querySelector('[data-field="translation"]')?.value?.toLowerCase() || '';
|
const val = row.querySelector('[data-field="translation"]')?.value?.toLowerCase() || '';
|
||||||
const show = (!type || rowType === type) &&
|
const show = (!type || rowType === type) &&
|
||||||
(!text || key.includes(text) || german.includes(text) || val.includes(text));
|
(!text || key.includes(text) || label.includes(text) || german.includes(text) || val.includes(text));
|
||||||
row.classList.toggle('trans-row-hidden', !show);
|
row.classList.toggle('trans-row-hidden', !show);
|
||||||
if (show) {
|
if (show) {
|
||||||
visible++;
|
visible++;
|
||||||
|
|||||||
@ -350,14 +350,15 @@ function applyFilters() {
|
|||||||
let visibleMissing = 0;
|
let visibleMissing = 0;
|
||||||
|
|
||||||
items.forEach(row => {
|
items.forEach(row => {
|
||||||
const key = row.dataset.key?.toLowerCase()
|
const key = row.dataset.key?.toLowerCase() || '';
|
||||||
|
const label = row.dataset.label?.toLowerCase()
|
||||||
|| row.querySelector('.trans-key-text')?.textContent?.toLowerCase() || '';
|
|| row.querySelector('.trans-key-text')?.textContent?.toLowerCase() || '';
|
||||||
const rowType = row.dataset.type || '';
|
const rowType = row.dataset.type || '';
|
||||||
const german = row.querySelector('.trans-source-text')?.textContent?.toLowerCase()
|
const german = row.querySelector('.trans-source-text')?.textContent?.toLowerCase()
|
||||||
|| row.querySelector('[data-field="german"]')?.value?.toLowerCase() || '';
|
|| row.querySelector('[data-field="german"]')?.value?.toLowerCase() || '';
|
||||||
const val = row.querySelector('[data-field="translation"]')?.value?.toLowerCase() || '';
|
const val = row.querySelector('[data-field="translation"]')?.value?.toLowerCase() || '';
|
||||||
const show = (!type || rowType === type) &&
|
const show = (!type || rowType === type) &&
|
||||||
(!text || key.includes(text) || german.includes(text) || val.includes(text));
|
(!text || key.includes(text) || label.includes(text) || german.includes(text) || val.includes(text));
|
||||||
row.classList.toggle('trans-row-hidden', !show);
|
row.classList.toggle('trans-row-hidden', !show);
|
||||||
if (show) {
|
if (show) {
|
||||||
visible++;
|
visible++;
|
||||||
|
|||||||
@ -25,6 +25,17 @@ export function germanFor(entry) {
|
|||||||
return entry.germanText || normalizeTranslations(entry.translations)[SOURCE_LANG] || entry.key || '';
|
return entry.germanText || normalizeTranslations(entry.translations)[SOURCE_LANG] || entry.key || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Key column label (short id for questions/options; catalog key for UI strings). */
|
||||||
|
export function entryDisplayKey(entry) {
|
||||||
|
if (entry.displayKey) return entry.displayKey;
|
||||||
|
if (entry.type === 'question' || entry.type === 'answer_option') {
|
||||||
|
const id = entry.entityId || '';
|
||||||
|
const sep = id.lastIndexOf('__');
|
||||||
|
return sep >= 0 ? id.slice(sep + 2) : id;
|
||||||
|
}
|
||||||
|
return entry.key || '';
|
||||||
|
}
|
||||||
|
|
||||||
export function translationFor(entry, lang) {
|
export function translationFor(entry, lang) {
|
||||||
return normalizeTranslations(entry.translations)[lang] || '';
|
return normalizeTranslations(entry.translations)[lang] || '';
|
||||||
}
|
}
|
||||||
@ -188,7 +199,8 @@ export function translationListHeaderHTML(targetLangLabel, sourceLabel = 'German
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function translationRowHTML(entry, idx, { targetLang, editable = true }) {
|
export function translationRowHTML(entry, idx, { targetLang, editable = true }) {
|
||||||
const key = entry.key || '';
|
const lookupKey = entry.key || '';
|
||||||
|
const label = entryDisplayKey(entry);
|
||||||
const german = germanFor(entry);
|
const german = germanFor(entry);
|
||||||
const val = translationFor(entry, targetLang);
|
const val = translationFor(entry, targetLang);
|
||||||
const missing = !val.trim();
|
const missing = !val.trim();
|
||||||
@ -201,10 +213,10 @@ export function translationRowHTML(entry, idx, { targetLang, editable = true })
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="trans-list-item ${missing ? 'trans-list-item-missing' : ''}"
|
<div class="trans-list-item ${missing ? 'trans-list-item-missing' : ''}"
|
||||||
data-idx="${idx}" data-type="${entry.type}" data-key="${escHtml(key)}" data-missing="${missing ? '1' : '0'}">
|
data-idx="${idx}" data-type="${entry.type}" data-key="${escHtml(lookupKey)}" data-label="${escHtml(label)}" data-missing="${missing ? '1' : '0'}">
|
||||||
<div class="trans-list-key">
|
<div class="trans-list-key">
|
||||||
${typeBadge(entry.type)}
|
${typeBadge(entry.type)}
|
||||||
<span class="trans-key-text" title="${escHtml(key)}">${escHtml(key)}</span>
|
<span class="trans-key-text" title="${escHtml(lookupKey)}">${escHtml(label)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="trans-list-source">${sourceCell}</div>
|
<div class="trans-list-source">${sourceCell}</div>
|
||||||
<input type="text" class="trans-cell-input ${missing ? 'trans-input-missing' : ''}"
|
<input type="text" class="trans-cell-input ${missing ? 'trans-input-missing' : ''}"
|
||||||
|
|||||||
Reference in New Issue
Block a user