diff --git a/app/styles.css b/app/styles.css
index 84dca07..71b89b9 100644
--- a/app/styles.css
+++ b/app/styles.css
@@ -3683,6 +3683,13 @@
letter-spacing: 0.03em;
}
+ .alpha-text-verse-counts {
+ color: #a1a1aa;
+ font-size: 11px;
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ }
+
.alpha-text-verse-text {
margin: 0;
color: #e4e4e7;
diff --git a/app/ui-alphabet-text.js b/app/ui-alphabet-text.js
index 8fa0bc5..c404585 100644
--- a/app/ui-alphabet-text.js
+++ b/app/ui-alphabet-text.js
@@ -165,6 +165,65 @@
return String(value || "").trim();
}
+ function extractVerseCountText(verse, source, displayPreferences, translationText = "") {
+ const mode = displayPreferences?.textMode || "translation";
+ const originalText = normalizeTextValue(verse?.originalText);
+ const transliterationText = getVerseTransliteration(verse, source);
+
+ if (mode === "original") {
+ return originalText || normalizeTextValue(translationText);
+ }
+ if (mode === "transliteration") {
+ return transliterationText || normalizeTextValue(translationText);
+ }
+ return normalizeTextValue(translationText)
+ || originalText
+ || transliterationText;
+ }
+
+ function getTextCounts(value) {
+ const normalized = String(value || "")
+ .normalize("NFD")
+ .replace(/[\u0300-\u036f]/g, "");
+ const words = normalized.match(/[\p{L}\p{N}]+(?:['’-][\p{L}\p{N}]+)*/gu) || [];
+ const letters = normalized.match(/\p{L}/gu) || [];
+ const vowels = normalized.match(/[AEIOUYaeiouy]/g) || [];
+ const consonants = letters.length - vowels.length;
+
+ return {
+ words: words.length,
+ letters: letters.length,
+ consonants: Math.max(0, consonants),
+ vowels: vowels.length
+ };
+ }
+
+ function formatCountSummary(counts) {
+ return `W:${counts.words} L:${counts.letters} C:${counts.consonants} V:${counts.vowels}`;
+ }
+
+ function sumPassageCounts(passage, source, displayPreferences) {
+ const verses = Array.isArray(passage?.verses) ? passage.verses : [];
+
+ return verses.reduce((totals, verse) => {
+ const translationText = source?.features?.hasTokenAnnotations
+ ? buildTokenTranslationText(verse?.tokens, verse?.text)
+ : verse?.text;
+ const counts = getTextCounts(extractVerseCountText(verse, source, displayPreferences, translationText));
+
+ totals.words += counts.words;
+ totals.letters += counts.letters;
+ totals.consonants += counts.consonants;
+ totals.vowels += counts.vowels;
+ return totals;
+ }, {
+ words: 0,
+ letters: 0,
+ consonants: 0,
+ vowels: 0
+ });
+ }
+
const GREEK_TRANSLITERATION_MAP = {
α: "a", β: "b", γ: "g", δ: "d", ε: "e", ζ: "z", η: "e", θ: "th",
ι: "i", κ: "k", λ: "l", μ: "m", ν: "n", ξ: "x", ο: "o", π: "p",
@@ -982,6 +1041,18 @@
`;
metaGrid.appendChild(overviewCard);
+ const totalsCard = createCard("Entry Totals");
+ const totals = sumPassageCounts(passage, source, displayPreferences);
+ totalsCard.innerHTML += `
+
+ - Words
- ${totals.words}
+ - Letters
- ${totals.letters}
+ - Consonants
- ${totals.consonants}
+ - Vowels
- ${totals.vowels}
+
+ `;
+ metaGrid.appendChild(totalsCard);
+
if (displayPreferences.capabilities.hasAnyExtras) {
const extraCard = createCard("Extra");
extraCard.classList.add("alpha-text-extra-card");
@@ -1057,6 +1128,8 @@
function createPlainVerse(verse) {
const source = getSelectedSource();
const displayPreferences = getSourceDisplayPreferences(source, state.currentPassage);
+ const translationText = verse.text || "";
+ const verseCounts = getTextCounts(extractVerseCountText(verse, source, displayPreferences, translationText));
const article = document.createElement("article");
article.className = "alpha-text-verse";
article.classList.toggle("is-highlighted", isHighlightedVerse(verse));
@@ -1068,9 +1141,13 @@
reference.className = "alpha-text-verse-reference";
reference.textContent = verse.reference || (verse.number ? `Verse ${verse.number}` : "");
- head.append(reference);
+ const stats = document.createElement("span");
+ stats.className = "alpha-text-verse-counts";
+ stats.textContent = formatCountSummary(verseCounts);
+
+ head.append(reference, stats);
article.append(head);
- appendVerseTextLines(article, verse, source, displayPreferences, verse.text || "");
+ appendVerseTextLines(article, verse, source, displayPreferences, translationText);
return article;
}
@@ -1128,6 +1205,8 @@
}
function createTokenVerse(verse, lexiconId, displayPreferences, source) {
+ const translationText = buildTokenTranslationText(verse?.tokens, verse?.text);
+ const verseCounts = getTextCounts(extractVerseCountText(verse, source, displayPreferences, translationText));
const article = document.createElement("article");
article.className = "alpha-text-verse";
article.classList.toggle("alpha-text-verse--interlinear", Boolean(displayPreferences?.showInterlinear));
@@ -1140,6 +1219,10 @@
reference.className = "alpha-text-verse-reference";
reference.textContent = verse.reference || (verse.number ? `Verse ${verse.number}` : "");
+ const stats = document.createElement("span");
+ stats.className = "alpha-text-verse-counts";
+ stats.textContent = formatCountSummary(verseCounts);
+
const tokenGrid = document.createElement("div");
tokenGrid.className = "alpha-text-token-grid";
@@ -1174,9 +1257,9 @@
tokenGrid.appendChild(tokenEl);
});
- head.append(reference);
+ head.append(reference, stats);
article.append(head);
- appendVerseTextLines(article, verse, source, displayPreferences, buildTokenTranslationText(verse?.tokens, verse?.text));
+ appendVerseTextLines(article, verse, source, displayPreferences, translationText);
if (displayPreferences?.showInterlinear) {
article.appendChild(tokenGrid);
}
diff --git a/index.html b/index.html
index 3dbe91a..93f3450 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@
-
+
@@ -997,7 +997,7 @@
-
+