diff --git a/src/components/settings/DataSection.jsx b/src/components/settings/DataSection.jsx
index f23386d..2d0c840 100644
--- a/src/components/settings/DataSection.jsx
+++ b/src/components/settings/DataSection.jsx
@@ -106,7 +106,7 @@ export default function DataSection() {
Chapters you read are kept automatically. To read anywhere, save a whole Bible while you’re connected (about 4 MB). The ESV, NLT, CSB and NASB can’t be saved: their licences don’t allow it.
{offline.job ? : (
- {['BSB', 'NET'].map((t) => (
+ {['BSB', 'NET', 'KJV', 'ASV', 'LSV'].map((t) => (
offline.saveBible(t)} className={btn}>
{(offline.saved[t] ?? []).length >= 66 ? `✓ The whole ${t} is saved` : `Save the whole ${t}`}
diff --git a/src/utils/bibleText.js b/src/utils/bibleText.js
index 3b2ba90..d491971 100644
--- a/src/utils/bibleText.js
+++ b/src/utils/bibleText.js
@@ -8,6 +8,9 @@ export const READER_TRANSLATIONS = [
notice: 'Scripture quotations are from the ESV® Bible (The Holy Bible, English Standard Version®), © 2001 by Crossway, a publishing ministry of Good News Publishers. Used by permission. All rights reserved.' },
{ id: 'NET', name: 'NET Bible', helloao: 'eng_net',
notice: 'Scripture quoted by permission. Quotations designated (NET) are from the NET Bible® copyright ©1996-2017 by Biblical Studies Press, L.L.C. http://netbible.com All rights reserved.' },
+ { id: 'KJV', name: 'King James Version', helloao: 'eng_kjv', notice: 'The King James Version is in the public domain.' },
+ { id: 'ASV', name: 'American Standard Version (1901)', helloao: 'eng_asv', notice: 'The American Standard Version (1901) is in the public domain.' },
+ { id: 'LSV', name: 'Literal Standard Version', helloao: 'eng_lsv', notice: 'Literal Standard Version © 2020 Covenant Press and the Covenant Christian Coalition. Free to read and share. lsvbible.com' },
{ id: 'NLT', name: 'New Living Translation', licensed: true,
notice: 'Holy Bible, New Living Translation, Copyright © 2014, Tyndale House Publishers. All rights reserved. tyndale.com' },
{ id: 'CSB', name: 'Christian Standard Bible', licensed: true,
@@ -16,6 +19,8 @@ export const READER_TRANSLATIONS = [
notice: 'New American Standard Bible®, Copyright © 1995, The Lockman Foundation. All rights reserved. lockman.org' },
];
+// The address code helloao uses for a translation (NET is 'eng_net', the KJV 'eng_kjv'; BSB is its own)
+export const helloaoCode = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.helloao ?? id ?? 'BSB';
export const translationName = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.name ?? id;
export const isLicensed = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.licensed === true;
diff --git a/src/utils/bibleUtils.jsx b/src/utils/bibleUtils.jsx
index 922ede7..61ca529 100644
--- a/src/utils/bibleUtils.jsx
+++ b/src/utils/bibleUtils.jsx
@@ -485,7 +485,7 @@ export function parseBibleChapter(data) {
.filter((item) => item?.type === 'verse')
.map((item) => ({
number: item.number,
- text: renderVerseContent(item.content).replace(/\s+/g, ' ').trim(),
+ text: renderVerseContent(item.content).replace(/¶\s*/g, '').replace(/\s+/g, ' ').trim(),
}));
}
diff --git a/src/utils/offline.test.js b/src/utils/offline.test.js
index 6631345..0225b1d 100644
--- a/src/utils/offline.test.js
+++ b/src/utils/offline.test.js
@@ -57,3 +57,21 @@ test('a study works offline once every book in it is saved in its translation',
test('licensed translations cannot be saved offline', () => {
expect(offlineStatus({ translation: 'ESV', chapters: [{ book: 'John', bookAbbrev: 'JHN' }] }, {}).state).toBe('licensed');
});
+
+import { READER_TRANSLATIONS, helloaoCode } from './bibleText.js';
+import { parseBibleChapter } from './bibleUtils.jsx';
+
+test('the KJV, ASV and LSV are free translations that can be saved offline and are fetched by their helloao code', () => {
+ for (const [id, code] of [['KJV', 'eng_kjv'], ['ASV', 'eng_asv'], ['LSV', 'eng_lsv'], ['NET', 'eng_net'], ['BSB', 'BSB']]) {
+ expect(READER_TRANSLATIONS.some((t) => t.id === id)).toBe(true);
+ expect(helloaoCode(id)).toBe(code);
+ expect(canSaveOffline(id)).toBe(true);
+ }
+ expect(canSaveOffline('ESV')).toBe(false);
+ expect(READER_TRANSLATIONS.find((t) => t.id === 'LSV').notice).toMatch(/Covenant Press/);
+});
+
+test('a paragraph mark in the KJV text is dropped from the verse', () => {
+ const verses = parseBibleChapter({ chapter: { content: [{ type: 'verse', number: 16, content: [{ text: '¶ For God so loved the world' }] }] } });
+ expect(verses[0].text).toBe('For God so loved the world');
+});
diff --git a/src/utils/studyText.js b/src/utils/studyText.js
index 5aaa818..7b6b42e 100644
--- a/src/utils/studyText.js
+++ b/src/utils/studyText.js
@@ -1,8 +1,10 @@
// Fetches a chapter's raw text for building a study (the free Bible source). The Reader's "Save for
// offline" downloads go through the same address, so a saved book builds a study with no connection.
// Failures say what's wrong and what to do, instead of a generic error.
+import { helloaoCode } from './bibleText.js';
+
export async function fetchStudyChapter(translation, bookAbbrev, chapter, { signal } = {}) {
- const code = translation === 'NET' ? 'eng_net' : (translation || 'BSB');
+ const code = helloaoCode(translation || 'BSB');
let res;
try {
res = await fetch(`https://bible.helloao.org/api/${code}/${bookAbbrev}/${chapter}.json`, { signal });