Fix Greek lookup: auto-prepend G prefix and use search endpoint for English words
This commit is contained in:
+35
-5
@@ -857,10 +857,40 @@ const App = () => {
|
||||
if (!word || !word.query.trim()) return;
|
||||
updateChunkWord(chunkId, wordId, { loading: true });
|
||||
try {
|
||||
const query = encodeURIComponent(word.query.trim());
|
||||
const response = await fetch(`https://bolls.life/dictionary-definition/BDBT/${query}/`);
|
||||
const raw = word.query.trim();
|
||||
|
||||
// Normalize Strong's numbers to always use the G prefix for Greek.
|
||||
// A bare number like "4102" would otherwise match Hebrew H4102.
|
||||
let normalized;
|
||||
if (/^\d+$/.test(raw)) {
|
||||
normalized = `G${raw}`;
|
||||
} else if (/^[gGhH]\d+$/.test(raw)) {
|
||||
normalized = raw.toUpperCase();
|
||||
} else {
|
||||
normalized = raw;
|
||||
}
|
||||
|
||||
const isStrongsNumber = /^[GH]\d+$/.test(normalized);
|
||||
const encoded = encodeURIComponent(normalized);
|
||||
|
||||
let definitions;
|
||||
if (isStrongsNumber) {
|
||||
// Direct Strong's number lookup in the combined Greek/Hebrew dictionary.
|
||||
const response = await fetch(`https://bolls.life/dictionary-definition/BDBT/${encoded}/`);
|
||||
if (!response.ok) throw new Error('Lookup failed.');
|
||||
const definitions = await response.json();
|
||||
definitions = await response.json();
|
||||
} else {
|
||||
// English word search — use the search-dictionaries endpoint.
|
||||
// Filter results to Greek entries only (topic starts with G).
|
||||
const response = await fetch(`https://bolls.life/search-dictionaries/BDBT/${encoded}/`);
|
||||
if (!response.ok) throw new Error('Lookup failed.');
|
||||
const results = await response.json();
|
||||
const greekResults = Array.isArray(results)
|
||||
? results.filter((r) => String(r.topic ?? '').startsWith('G'))
|
||||
: [];
|
||||
definitions = greekResults.length > 0 ? [greekResults[0]] : [];
|
||||
}
|
||||
|
||||
if (!Array.isArray(definitions) || definitions.length === 0) {
|
||||
updateChunkWord(chunkId, wordId, {
|
||||
strongNumber: '',
|
||||
@@ -872,7 +902,7 @@ const App = () => {
|
||||
const first = definitions[0];
|
||||
const extractedPartOfSpeech = extractPartOfSpeech(first.definition || '');
|
||||
updateChunkWord(chunkId, wordId, {
|
||||
strongNumber: first.topic || word.query,
|
||||
strongNumber: first.topic || normalized,
|
||||
lexeme: first.lexeme || '',
|
||||
transliteration: first.transliteration || '',
|
||||
partOfSpeech: extractedPartOfSpeech || word.partOfSpeech || '',
|
||||
@@ -1607,7 +1637,7 @@ const App = () => {
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') { e.preventDefault(); lookupGreekWord(selectedChunk.id, word.id); }
|
||||
}}
|
||||
placeholder="G4102 or faith"
|
||||
placeholder="G4102, 4102, or faith (Greek)"
|
||||
className="mt-2 block w-full rounded-2xl border border-slate-300 bg-slate-50 px-3 py-2 text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
||||
/>
|
||||
</label>
|
||||
|
||||
+7
-7
@@ -289,18 +289,18 @@ async function goToStudyAndAddGreekWord(fetchMock) {
|
||||
fireEvent.click(screen.getByRole('button', { name: /begin studying/i }));
|
||||
await screen.findByText(/chunk editor/i);
|
||||
fireEvent.click(screen.getByRole('button', { name: /add greek word/i }));
|
||||
await screen.findByPlaceholderText(/G4102 or faith/i);
|
||||
await screen.findByPlaceholderText(/G4102, 4102/i);
|
||||
}
|
||||
|
||||
describe('Greek word lookup', () => {
|
||||
test('adds a Greek word entry form', async () => {
|
||||
await goToStudyAndAddGreekWord();
|
||||
expect(screen.getByPlaceholderText(/G4102 or faith/i)).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/G4102, 4102/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('populates fields after a successful lookup', async () => {
|
||||
await goToStudyAndAddGreekWord(buildFetchMock({ greekData: mockGreekDefinition }));
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102 or faith/i), { target: { value: 'G4102' } });
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102, 4102/i), { target: { value: 'G4102' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /look up/i }));
|
||||
await screen.findByDisplayValue('πίστις');
|
||||
expect(screen.getByDisplayValue('pistis')).toBeInTheDocument();
|
||||
@@ -309,7 +309,7 @@ describe('Greek word lookup', () => {
|
||||
|
||||
test('shows "No definition found." when the API returns an empty array', async () => {
|
||||
await goToStudyAndAddGreekWord(buildFetchMock({ greekData: [] }));
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102 or faith/i), { target: { value: 'G4102' } });
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102, 4102/i), { target: { value: 'G4102' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /look up/i }));
|
||||
await screen.findByDisplayValue('No definition found.');
|
||||
});
|
||||
@@ -326,7 +326,7 @@ describe('Greek word lookup', () => {
|
||||
return Promise.reject(new Error('Network error'));
|
||||
}),
|
||||
);
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102 or faith/i), { target: { value: 'G4102' } });
|
||||
fireEvent.change(screen.getByPlaceholderText(/G4102, 4102/i), { target: { value: 'G4102' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /look up/i }));
|
||||
await screen.findByDisplayValue('Lookup failed.');
|
||||
});
|
||||
@@ -343,10 +343,10 @@ describe('Greek word lookup', () => {
|
||||
|
||||
test('removes a Greek word entry', async () => {
|
||||
await goToStudyAndAddGreekWord();
|
||||
expect(screen.getByPlaceholderText(/G4102 or faith/i)).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/G4102, 4102/i)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: /^delete$/i }));
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByPlaceholderText(/G4102 or faith/i)).not.toBeInTheDocument();
|
||||
expect(screen.queryByPlaceholderText(/G4102, 4102/i)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user