Fix Greek word lookup: replace broken Bolls BDAG with OpenScriptures Strong's dictionary

The Bolls.life BDAG endpoint (/dictionary-definition/BDAG/) now returns
empty arrays for all queries, and the search endpoint returns 404.

Switched Greek lookups to the OpenScriptures Strong's Greek Dictionary
served via jsDelivr CDN. The ~1.2 MB dictionary is fetched once on first
lookup and cached in a useRef for the session, so subsequent lookups are
instant. Hebrew lookups (Bolls BDBT) are unchanged and still working.

Supports Strong's number lookup (G4102, 4102) and English word search
(faith, apostle), returning lemma, transliteration, short definition,
and an extended definition with derivation and KJV keyword list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmert
2026-05-28 07:49:55 -04:00
parent 6034aa26a2
commit 48b3790cd2
2 changed files with 69 additions and 25 deletions
+2 -1
View File
@@ -5,7 +5,8 @@
"name": "study-app", "name": "study-app",
"runtimeExecutable": "npm", "runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"], "runtimeArgs": ["run", "dev"],
"port": 5173 "port": 5173,
"autoPort": false
} }
] ]
} }
+67 -24
View File
@@ -892,36 +892,79 @@ const App = () => {
]; ];
}; };
const fetchBollsDefinition = async (query) => { // Module-level cache for the Greek Strong's dictionary (loaded once, ~1.2 MB)
const isGreek = isGreekStrongNumber(query); const _greekDictRef = useRef(null);
const isHebrew = isHebrewStrongNumber(query); const _greekDictLoadingRef = useRef(null);
if (isGreek || isHebrew) { const loadGreekDict = async () => {
// The bolls.life API uses bare numbers in the URL (no G/H prefix). if (_greekDictRef.current) return _greekDictRef.current;
// We filter returned results by topic prefix to get the right language. if (_greekDictLoadingRef.current) return _greekDictLoadingRef.current;
const bare = query.trim().replace(/^[GgHh]/, ''); _greekDictLoadingRef.current = fetch(
const response = await fetch(`https://bolls.life/dictionary-definition/BDBT/${encodeURIComponent(bare)}/`); 'https://cdn.jsdelivr.net/gh/openscriptures/strongs@master/greek/strongs-greek-dictionary.js',
)
.then((res) => res.text())
.then((text) => {
const start = text.indexOf('{');
const end = text.lastIndexOf('}') + 1;
const dict = JSON.parse(text.slice(start, end));
_greekDictRef.current = dict;
_greekDictLoadingRef.current = null;
return dict;
});
return _greekDictLoadingRef.current;
};
const buildGreekDefinitionHtml = (key, entry) => {
let html = '';
if (entry.strongs_def) html += `<p>${entry.strongs_def.trim()}</p>`;
if (entry.derivation) html += `<p><em>Derivation:</em> ${entry.derivation}</p>`;
if (entry.kjv_def) html += `<p><em>KJV uses:</em> ${entry.kjv_def}</p>`;
return html;
};
const fetchBollsDefinition = async (query) => {
const encoded = encodeURIComponent(query.trim());
if (isHebrewStrongNumber(query)) {
const response = await fetch(`https://bolls.life/dictionary-definition/BDBT/${encoded}/`);
if (!response.ok) return null; if (!response.ok) return null;
let defs; let defs;
try { defs = await response.json(); } catch { return null; } try { defs = await response.json(); } catch { return null; }
if (!Array.isArray(defs) || defs.length === 0) return null; return Array.isArray(defs) && defs.length > 0 ? defs : null;
const prefix = isGreek ? 'G' : 'H';
const filtered = defs.filter((d) => String(d.topic ?? '').toUpperCase().startsWith(prefix));
return filtered.length > 0 ? filtered : defs;
} }
// English word — full-text search, filter to Greek entries only // Greek — look up in the cached OpenScriptures Strong's dictionary.
const encoded = encodeURIComponent(query.trim()); const dict = await loadGreekDict();
try { const key = isGreekStrongNumber(query) ? query.trim().toUpperCase() : null;
const searchResponse = await fetch(`https://bolls.life/search-dictionaries/BDBT/${encoded}/`);
if (searchResponse.ok) { if (key) {
const results = await searchResponse.json(); const entry = dict[key];
const greekResults = Array.isArray(results) if (!entry) return null;
? results.filter((r) => String(r.topic ?? '').startsWith('G')) return [{
: []; topic: key,
if (greekResults.length > 0) return [greekResults[0]]; lexeme: entry.lemma || '',
} transliteration: entry.translit || '',
} catch { /* fall through */ } short_definition: entry.kjv_def || '',
definition: buildGreekDefinitionHtml(key, entry),
}];
}
// English word search — scan kjv_def and strongs_def for the query term.
const lowerQ = query.trim().toLowerCase();
const match = Object.entries(dict).find(([, entry]) =>
(entry.kjv_def || '').toLowerCase().split(/[,\s]+/).some((w) => w === lowerQ) ||
(entry.strongs_def || '').toLowerCase().includes(lowerQ),
);
if (match) {
const [matchKey, entry] = match;
return [{
topic: matchKey,
lexeme: entry.lemma || '',
transliteration: entry.translit || '',
short_definition: entry.kjv_def || '',
definition: buildGreekDefinitionHtml(matchKey, entry),
}];
}
return null; return null;
}; };