{% extends "dashboard/base.html" %} {% block title %}{{ lang_name }} Translations - Translator{% endblock %} {% block extra_css %} {% endblock %} {% block breadcrumb %} {% endblock %} {% block content %}
Clear
{% if is_privileged and no_refs_filter == 'true' and translations|length > 0 %}
{% csrf_token %}
{% endif %}
{% for item in translations %} {% empty %} {% endfor %}
Translation Source Status Actions
{{ item.ref_value }}
{% if ref_col == 'key' and item.comment %}
{{ item.comment }}
{% endif %}
{% if item.value %} {{ item.value }} {% else %} {% endif %}
{{ item.source|default:"—" }} {% if item.verified %} Verified {% else %} Pending {% endif %}
Edit {% if item.verified %} {% else %} {% endif %} {% if is_privileged %} {% endif %}
No translations found matching your filters
{% for item in translations %}
{{ item.key }}
{% if item.value %}{{ item.value }}{% else %}{% endif %}
{% if item.comment %}
{{ item.comment }}
{% endif %}
{% empty %}
No translations found matching your filters
{% endfor %} {% if is_privileged %} {% endif %} const csrfToken = '{{ csrf_token }}'; const langCode = '{{ lang_code }}'; let deleteId = null; let searchTimeout = null; async function toggleVerify(id, verified) { try { const response = await fetch(`/translate/api/dashboard/translations/${id}/verify/`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, }, credentials: 'include', body: JSON.stringify({ lang: langCode, verified }), }); if (response.ok) { window.location.reload(); } else { const data = await response.json(); alert(data.error || 'Failed to update verification'); } } catch (err) { alert('Network error: ' + err.message); } } function changeRefCol(value) { const url = new URL(window.location.href); if (value && value !== 'key') url.searchParams.set('ref', value); else url.searchParams.delete('ref'); window.location.href = url.toString(); } function applyFilters() { const url = new URL(window.location.href); const verified = document.getElementById('filter-verified').value; const source = document.getElementById('filter-source').value; const search = document.getElementById('filter-search').value; const noRefs = document.getElementById('filter-no-refs').checked; const sort = document.getElementById('filter-sort').value; if (verified) url.searchParams.set('verified', verified); else url.searchParams.delete('verified'); if (source) url.searchParams.set('source', source); else url.searchParams.delete('source'); if (search) url.searchParams.set('search', search); else url.searchParams.delete('search'); if (noRefs) url.searchParams.set('no_refs', 'true'); else url.searchParams.delete('no_refs'); if (sort && sort !== 'default') url.searchParams.set('sort', sort); else url.searchParams.delete('sort'); // Preserve ref column selection const ref = document.getElementById('ref-col-select').value; if (ref && ref !== 'key') url.searchParams.set('ref', ref); else url.searchParams.delete('ref'); window.location.href = url.toString(); } stapelDom.register({ applyFilters: applyFilters, changeRefCol: (node) => changeRefCol(node.value), toggleVerify: (node) => toggleVerify(node.dataset.id, node.dataset.verified === 'true'), }); // Live search with debounce document.getElementById('filter-search').addEventListener('input', function(e) { if (searchTimeout) clearTimeout(searchTimeout); searchTimeout = setTimeout(applyFilters, 1500); }); document.getElementById('filter-search').addEventListener('keypress', function(e) { if (e.key === 'Enter') { if (searchTimeout) clearTimeout(searchTimeout); applyFilters(); } }); {% if is_privileged %} function confirmDelete(id, key) { deleteId = id; document.getElementById('delete-key-display').textContent = key; document.getElementById('delete-modal').style.display = 'flex'; } function closeDeleteModal() { document.getElementById('delete-modal').style.display = 'none'; deleteId = null; } async function deleteTranslation() { if (!deleteId) return; try { const response = await fetch(`/translate/api/dashboard/translations/${deleteId}/`, { method: 'DELETE', headers: { 'X-CSRFToken': csrfToken, }, credentials: 'include', }); if (response.ok) { window.location.reload(); } else { const data = await response.json(); alert(data.error || 'Failed to delete translation'); } } catch (err) { alert('Network error: ' + err.message); } } document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeDeleteModal(); }); document.getElementById('delete-modal').addEventListener('click', function(e) { if (e.target === this) closeDeleteModal(); }); function confirmDeleteOrphans(count) { if (confirm(`This will soft-delete all ${count} translations with no refs. This action cannot be undone.\n\nProceed?`)) { document.getElementById('delete-orphans-form').submit(); } } stapelDom.register({ confirmDelete: (node) => confirmDelete(node.dataset.id, node.dataset.key), closeDeleteModal: closeDeleteModal, deleteTranslation: deleteTranslation, confirmDeleteOrphans: (node) => confirmDeleteOrphans(node.dataset.count), }); {% endif %} {% endblock %}