Skip to content

Commit 1663edf

Browse files
committed
Release 1.1.1: Feature - incomplete translation highlight indicator
1 parent 378011b commit 1663edf

11 files changed

Lines changed: 271 additions & 3 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.1.1 - 2024-xx-xx (Aktuelles Release)
4+
### Hinzugefügt
5+
- **Übersetzungs-Check:** Im Sprach-Dropdown gibt es nun die Option "Fehlende hervorheben". Ist diese aktiv, werden Einträge, die nicht für alle im System *auf online geschalteten* Sprachen übersetzt sind, in der Listenansicht mit einem dezenten roten Indikator-Punkt versehen.
6+
37
## 1.1.0 - 2024-xx-xx (Aktuelles Release)
48
### Hinzugefügt
59
- **Sprachumschalter in der YForm-Listenansicht:** Über ein neues Dropdown in der Toolbar kann die angezeigte Sprache für alle Sprachfelder in der Liste live umgeschaltet werden.

assets/lang-fields.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,20 @@ body.rex-theme-dark .yform-lang-field .lang-field-add-section .lang-select-new {
535535
color: inherit;
536536
border: 1px solid rgba(128, 128, 128, 0.2);
537537
}
538+
539+
/* Highlight incomplete translations */
540+
body.ylf-show-incomplete .ylf-is-incomplete {
541+
position: relative;
542+
}
543+
544+
body.ylf-show-incomplete .ylf-is-incomplete::before {
545+
content: '';
546+
position: absolute;
547+
left: -14px;
548+
top: calc(50% - 3px);
549+
width: 6px;
550+
height: 6px;
551+
border-radius: 50%;
552+
background-color: #d9534f;
553+
box-shadow: 0 0 4px rgba(217, 83, 79, 0.4);
554+
}

assets/lang-fields.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,9 +612,30 @@
612612
+ ' <small>' + self.escapeHtml(c.name) + '</small>'
613613
+ '</a></li>';
614614
}
615+
var showIncomplete = localStorage.getItem('ylf_show_incomplete') === 'true';
616+
var iconClass = showIncomplete ? 'fa-check-square-o' : 'fa-square-o';
617+
menuHtml += '<li role="separator" class="divider"></li>';
618+
menuHtml += '<li><a href="#" class="ylf-toggle-incomplete"><i class="fa fa-fw ' + iconClass + '"></i> <small>Fehlende hervorheben</small></a></li>';
615619
menuHtml += '</ul>';
616620
$group.append(menuHtml);
617621

622+
// Klick auf Incomplete Toggle
623+
$group.on('click', '.ylf-toggle-incomplete', function(e) {
624+
e.preventDefault();
625+
e.stopPropagation();
626+
var isEnabled = localStorage.getItem('ylf_show_incomplete') === 'true';
627+
isEnabled = !isEnabled;
628+
localStorage.setItem('ylf_show_incomplete', isEnabled ? 'true' : 'false');
629+
630+
var $icon = $(this).find('.fa');
631+
if (isEnabled) {
632+
$icon.removeClass('fa-square-o').addClass('fa-check-square-o');
633+
} else {
634+
$icon.removeClass('fa-check-square-o').addClass('fa-square-o');
635+
}
636+
self.applyIncompleteHighlighting();
637+
});
638+
618639
// Klick auf Menüeintrag
619640
$group.on('click', 'a[data-ylf-switch]', function(e) {
620641
e.preventDefault();
@@ -634,6 +655,16 @@
634655

635656
// Initiale Anzeige
636657
self.applyActiveLang(activeClang.id);
658+
self.applyIncompleteHighlighting();
659+
},
660+
661+
applyIncompleteHighlighting: function() {
662+
var isEnabled = localStorage.getItem('ylf_show_incomplete') === 'true';
663+
if (isEnabled) {
664+
$('body').addClass('ylf-show-incomplete');
665+
} else {
666+
$('body').removeClass('ylf-show-incomplete');
667+
}
637668
},
638669

639670
/**

fix_css2.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import re
2+
with open('assets/lang-fields.css', 'r') as f:
3+
text = f.read()
4+
5+
bad = """body.ylf-show-incomplete .ylf-is-incomplete::before {
6+
content: '';
7+
position: absolute;
8+
left: -12px;
9+
top: 5px;"""
10+
11+
new = """body.ylf-show-incomplete .ylf-is-incomplete::before {
12+
content: '';
13+
position: absolute;
14+
left: -14px;
15+
top: calc(50% - 3px);"""
16+
17+
text = text.replace(bad, new)
18+
19+
with open('assets/lang-fields.css', 'w') as f:
20+
f.write(text)

fix_highlighting_js.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import re
2+
3+
with open('assets/lang-fields.js', 'r') as f:
4+
text = f.read()
5+
6+
bad1 = """ menuHtml += '</ul>';
7+
$group.append(menuHtml);
8+
9+
// Klick auf Menüeintrag"""
10+
11+
new1 = """ var showIncomplete = localStorage.getItem('ylf_show_incomplete') === 'true';
12+
var iconClass = showIncomplete ? 'fa-check-square-o' : 'fa-square-o';
13+
menuHtml += '<li role="separator" class="divider"></li>';
14+
menuHtml += '<li><a href="#" class="ylf-toggle-incomplete"><i class="fa fa-fw ' + iconClass + '"></i> <small>Fehlende hervorheben</small></a></li>';
15+
menuHtml += '</ul>';
16+
$group.append(menuHtml);
17+
18+
// Klick auf Incomplete Toggle
19+
$group.on('click', '.ylf-toggle-incomplete', function(e) {
20+
e.preventDefault();
21+
e.stopPropagation();
22+
var isEnabled = localStorage.getItem('ylf_show_incomplete') === 'true';
23+
isEnabled = !isEnabled;
24+
localStorage.setItem('ylf_show_incomplete', isEnabled ? 'true' : 'false');
25+
26+
var $icon = $(this).find('.fa');
27+
if (isEnabled) {
28+
$icon.removeClass('fa-square-o').addClass('fa-check-square-o');
29+
} else {
30+
$icon.removeClass('fa-check-square-o').addClass('fa-square-o');
31+
}
32+
self.applyIncompleteHighlighting();
33+
});
34+
35+
// Klick auf Menüeintrag"""
36+
37+
bad2 = """ // Initiale Anzeige
38+
self.applyActiveLang(activeClang.id);
39+
},
40+
41+
/**"""
42+
43+
new2 = """ // Initiale Anzeige
44+
self.applyActiveLang(activeClang.id);
45+
self.applyIncompleteHighlighting();
46+
},
47+
48+
applyIncompleteHighlighting: function() {
49+
var isEnabled = localStorage.getItem('ylf_show_incomplete') === 'true';
50+
if (isEnabled) {
51+
$('body').addClass('ylf-show-incomplete');
52+
} else {
53+
$('body').removeClass('ylf-show-incomplete');
54+
}
55+
},
56+
57+
/**"""
58+
59+
text = text.replace(bad1, new1)
60+
text = text.replace(bad2, new2)
61+
62+
with open('assets/lang-fields.js', 'w') as f:
63+
f.write(text)
64+

fix_highlighting_php.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import re
2+
3+
with open('lib/KLXM/YformLangFields/LangHelper.php', 'r') as f:
4+
text = f.read()
5+
6+
bad1 = """ public static function buildListPopover(array $parsed, string $mode = 'text', int $preferredClangId = 0): string
7+
{
8+
if (empty($parsed)) {
9+
return '<span>-</span>';
10+
}
11+
12+
$spans = [];
13+
$firstNonEmpty = null;
14+
15+
foreach ($parsed as $item) {"""
16+
17+
new1 = """ public static function buildListPopover(array $parsed, string $mode = 'text', int $preferredClangId = 0): string
18+
{
19+
$onlineClangs = rex_clang::getAll(true);
20+
$totalOnline = count($onlineClangs);
21+
22+
if (empty($parsed)) {
23+
$classes = $totalOnline > 0 ? 'ylf-list-entry ylf-is-incomplete' : 'ylf-list-entry';
24+
return '<span class="' . $classes . '" data-ylf-default="0"><span>-</span></span>';
25+
}
26+
27+
$spans = [];
28+
$firstNonEmpty = null;
29+
$translatedOnlineCount = 0;
30+
31+
foreach ($parsed as $item) {"""
32+
33+
bad2 = """ if ('' === $text) {
34+
continue;
35+
}
36+
37+
if (null === $firstNonEmpty) {
38+
$firstNonEmpty = $clangId;
39+
}"""
40+
41+
new2 = """ if ('' === $text) {
42+
continue;
43+
}
44+
45+
if (isset($onlineClangs[$clangId])) {
46+
$translatedOnlineCount++;
47+
}
48+
49+
if (null === $firstNonEmpty) {
50+
$firstNonEmpty = $clangId;
51+
}"""
52+
53+
bad3 = """ return '<span class="ylf-list-entry" data-ylf-default="' . $default . '">'
54+
. implode('', $spans)
55+
. '</span>';"""
56+
57+
new3 = """ $isIncomplete = $translatedOnlineCount < $totalOnline;
58+
$classes = 'ylf-list-entry';
59+
if ($isIncomplete) {
60+
$classes .= ' ylf-is-incomplete';
61+
}
62+
63+
return '<span class="' . $classes . '" data-ylf-default="' . $default . '">'
64+
. implode('', $spans)
65+
. '</span>';"""
66+
67+
68+
text = text.replace(bad1, new1)
69+
text = text.replace(bad2, new2)
70+
text = text.replace(bad3, new3)
71+
72+
with open('lib/KLXM/YformLangFields/LangHelper.php', 'w') as f:
73+
f.write(text)
74+

fix_package.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import re
2+
3+
with open('package.yml', 'r') as f:
4+
c = f.read()
5+
6+
# Replace specifically the php version
7+
c = re.sub(r"php:\n\s*version:\s*'1\.1\.0'", "php:\n version: '^8.1'", c)
8+
9+
with open('package.yml', 'w') as f:
10+
f.write(c)
11+
print("package.yml fixed")
12+

lib/KLXM/YformLangFields/LangHelper.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,17 @@ public static function getLanguageSelectHtml(string $name, ?int $selectedId = nu
128128
*/
129129
public static function buildListPopover(array $parsed, string $mode = 'text', int $preferredClangId = 0): string
130130
{
131+
$onlineClangs = rex_clang::getAll(true);
132+
$totalOnline = count($onlineClangs);
133+
131134
if (empty($parsed)) {
132-
return '<span>-</span>';
135+
$classes = $totalOnline > 0 ? 'ylf-list-entry ylf-is-incomplete' : 'ylf-list-entry';
136+
return '<span class="' . $classes . '" data-ylf-default="0"><span>-</span></span>';
133137
}
134138

135139
$spans = [];
136140
$firstNonEmpty = null;
141+
$translatedOnlineCount = 0;
137142

138143
foreach ($parsed as $item) {
139144
if (empty($item['value'])) {
@@ -161,6 +166,10 @@ public static function buildListPopover(array $parsed, string $mode = 'text', in
161166
continue;
162167
}
163168

169+
if (isset($onlineClangs[$clangId])) {
170+
$translatedOnlineCount++;
171+
}
172+
164173
if (null === $firstNonEmpty) {
165174
$firstNonEmpty = $clangId;
166175
}
@@ -179,7 +188,13 @@ public static function buildListPopover(array $parsed, string $mode = 'text', in
179188
// data-ylf-default: statischer Fallback wenn kein JS / kein localStorage
180189
$default = $preferredClangId > 0 ? $preferredClangId : (int) $firstNonEmpty;
181190

182-
return '<span class="ylf-list-entry" data-ylf-default="' . $default . '">'
191+
$isIncomplete = $translatedOnlineCount < $totalOnline;
192+
$classes = 'ylf-list-entry';
193+
if ($isIncomplete) {
194+
$classes .= ' ylf-is-incomplete';
195+
}
196+
197+
return '<span class="' . $classes . '" data-ylf-default="' . $default . '">'
183198
. implode('', $spans)
184199
. '</span>';
185200
}

package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package: yform_lang_fields
2-
version: '1.1.0'
2+
version: '1.1.1'
33
author: 'KLXM Crossmedia / Thomas Skerbis'
44
supportpage: 'https://klxm.de'
55

release_1_1_1.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import re
2+
3+
# package.yml
4+
with open('package.yml', 'r') as f:
5+
c = f.read()
6+
c = re.sub(r"version:\s*'1\.1\.0'", "version: '1.1.1'", c)
7+
with open('package.yml', 'w') as f:
8+
f.write(c)
9+
10+
# CHANGELOG.md
11+
with open('CHANGELOG.md', 'r') as f:
12+
chl = f.read()
13+
14+
new_log = """# Changelog
15+
16+
## 1.1.1 - 2024-xx-xx (Aktuelles Release)
17+
### Hinzugefügt
18+
- **Übersetzungs-Check:** Im Sprach-Dropdown gibt es nun die Option "Fehlende hervorheben". Ist diese aktiv, werden Einträge, die nicht für alle im System *auf online geschalteten* Sprachen übersetzt sind, in der Listenansicht mit einem dezenten roten Indikator-Punkt versehen.
19+
20+
## 1.1.0"""
21+
22+
chl = chl.replace("# Changelog\n\n## 1.1.0", new_log)
23+
with open('CHANGELOG.md', 'w') as f:
24+
f.write(chl)
25+
26+
print("package and changelog updated")

0 commit comments

Comments
 (0)