Module: Bible270::Translations

Defined in:
lib/bible270/translations.rb

Overview

The translations a reader may choose between, and how each maps onto the external reader's own code. Kept free of Rails so it can be unit tested.

The distinction matters: readers know the NASB 1995 as "NASB95", but Bible Gateway's parameter for it is "NASB1995". Sending the display code straight through would land every link on a search page instead of the passage.

Constant Summary collapse

VERSIONS =

label is the full name, for prose. short is what goes in the select, where "New American Standard Bible 1995" overflows the box.

{
  'NKJV' => { label: 'New King James Version', short: 'New King James Version', gateway: 'NKJV', blue_letter: 'nkjv' },
  'NASB95' => { label: 'New American Standard Bible 1995', short: 'New American Standard 1995', gateway: 'NASB1995', blue_letter: 'nasb95' },
  'LSB' => { label: 'Legacy Standard Bible', short: 'Legacy Standard Version', gateway: 'LSB', blue_letter: 'lsb' },
  'ESV' => { label: 'English Standard Version', short: 'English Standard Version', gateway: 'ESV', blue_letter: 'esv' },
  'KJV' => { label: 'King James Version', short: 'King James Version', gateway: 'KJV', blue_letter: 'kjv' },
  'YLT' => { label: 'Young\'s Literal Translation', short: 'Young\'s Literal Translation', gateway: 'YLT', blue_letter: 'ylt' },
  'HEB/GRK' => { label: 'Hebrew and Greek', short: 'Hebrew and Greek', gateway: 'WLC', blue_letter: 'wlc/mgnt' },
  'ALLGRK' => { label: 'LXX Old Testament and Greek New Testament', short: 'LXX OT and Greek NT', gateway: 'LXX', blue_letter: 'mgnt' }
}.freeze
DEFAULT =
'NKJV'
ORIGINAL_LANGUAGES =
'HEB/GRK'
ALL_GREEK =
'ALLGRK'
ORIGINAL_LANGUAGE_CODES =
[ORIGINAL_LANGUAGES, ALL_GREEK].freeze
BLUE_LETTER_BASE_URL =
'https://www.blueletterbible.org'
BIBLE_COM_BASE_URL =
'https://www.bible.com/bible'
BIBLE_COM_VERSIONS =
{
  'NKJV' => [114, 'NKJV'], 'NASB95' => [100, 'NASB1995'], 'LSB' => [3345, 'LSB'],
  'ESV' => [59, 'ESV'], 'KJV' => [1, 'KJV'], 'YLT' => [821, 'YLT98']
}.freeze
BIBLE_COM_ORIGINAL_LANGUAGES =
{
  old_testament: [3585, 'WLC'], new_testament: [2270, 'THGNT']
}.freeze
BIBLE_COM_ALL_GREEK =
{
  old_testament: [2503, 'GRCBRENT'], new_testament: [2270, 'THGNT']
}.freeze
BLUE_LETTER_BOOK_CODES =
%w[
  gen exo lev num deu jos jdg rut 1sa 2sa 1ki 2ki 1ch 2ch ezr neh est job psa pro ecc sng
  isa jer lam eze dan hos joe amo oba jon mic nah hab zep hag zec mal mat mar luk joh act rom
  1co 2co gal eph php col 1th 2th 1ti 2ti tit phm heb jas 1pe 2pe 1jo 2jo 3jo jud rev
].freeze
BIBLE_COM_BOOK_CODES =
%w[
  GEN EXO LEV NUM DEU JOS JDG RUT 1SA 2SA 1KI 2KI 1CH 2CH EZR NEH EST JOB PSA PRO ECC SNG
  ISA JER LAM EZK DAN HOS JOL AMO OBA JON MIC NAM HAB ZEP HAG ZEC MAL MAT MRK LUK JHN ACT ROM
  1CO 2CO GAL EPH PHP COL 1TH 2TH 1TI 2TI TIT PHM HEB JAS 1PE 2PE 1JN 2JN 3JN JUD REV
].freeze

Class Method Summary collapse

Class Method Details

.bible_com_url(reference, version) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/bible270/translations.rb', line 131

def bible_com_url(reference, version)
  start = reference_start(reference)
  return BIBLE_COM_BASE_URL unless start

  book_index, chapter, = start
  version_id, version_code = bible_com_version(version, book_index)
  return BIBLE_COM_BASE_URL unless version_id && version_code

  "#{BIBLE_COM_BASE_URL}/#{version_id}/#{BIBLE_COM_BOOK_CODES[book_index]}." \
    "#{chapter}.#{version_code}"
end

.bible_com_version(version, book_index) ⇒ Object



143
144
145
146
147
148
149
150
# File 'lib/bible270/translations.rb', line 143

def bible_com_version(version, book_index)
  normalized = normalize(version)
  testament = book_index >= Versification::VERSES.keys.index('Matthew') ? :new_testament : :old_testament
  return BIBLE_COM_ORIGINAL_LANGUAGES[testament] if normalized == ORIGINAL_LANGUAGES
  return BIBLE_COM_ALL_GREEK[testament] if normalized == ALL_GREEK

  BIBLE_COM_VERSIONS[normalized]
end

.blue_letter_url(reference, version = ORIGINAL_LANGUAGES) ⇒ Object

Blue Letter Bible identifies a verse with its canonical chapter number times 1,000 plus the verse number: Genesis 1:1 is 1001 and Matthew 1:1 is 930001. A plan reference can span chapters or books; BLB has no equivalent passage query URL, so link to the first chapter/verse and let its chapter navigation carry the reader onward.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/bible270/translations.rb', line 109

def blue_letter_url(reference, version = ORIGINAL_LANGUAGES)
  start = reference_start(reference)
  return "#{BLUE_LETTER_BASE_URL}/" unless start

  book_index, chapter, verse = start
  books = Versification::VERSES.keys
  canonical_chapter = books.first(book_index).sum { |prior| Versification::VERSES[prior].length } + chapter
  new_testament = book_index >= books.index('Matthew')
  reader = if normalize(version) == ORIGINAL_LANGUAGES
             new_testament ? 'mgnt' : 'wlc'
           elsif normalize(version) == ALL_GREEK
             'mgnt'
           else
             VERSIONS.dig(normalize(version), :blue_letter)
           end
  return "#{BLUE_LETTER_BASE_URL}/" if reader.to_s.empty?

  anchor = (canonical_chapter * 1000) + verse
  "#{BLUE_LETTER_BASE_URL}/#{reader}/#{BLUE_LETTER_BOOK_CODES[book_index]}/" \
    "#{chapter}/#{verse}/s_#{anchor}"
end

.codesObject

The codes offered to readers, narrowed by config.bible_versions if the host only wants some of them.



58
59
60
61
62
# File 'lib/bible270/translations.rb', line 58

def codes
  allowed = Bible270.config.bible_versions if Bible270.config.respond_to?(:bible_versions)
  requested = Array(allowed).map { |code| code.to_s.upcase }.select { |code| VERSIONS.key?(code) }
  requested.any? ? requested : VERSIONS.keys
end

.gateway_code(code) ⇒ Object

The code the external reader expects, which is not always the code readers recognise.



86
87
88
# File 'lib/bible270/translations.rb', line 86

def gateway_code(code)
  VERSIONS.dig(normalize(code), :gateway) || normalize(code)
end

.label(code) ⇒ Object



76
77
78
# File 'lib/bible270/translations.rb', line 76

def label(code)
  VERSIONS.dig(normalize(code), :label)
end

.normalize(code) ⇒ Object



68
69
70
# File 'lib/bible270/translations.rb', line 68

def normalize(code)
  code.to_s.strip.upcase
end

.optionsObject

[[label, code], ...] for a select field.



91
92
93
# File 'lib/bible270/translations.rb', line 91

def options
  codes.map { |code| ["#{code}#{short_label(code)}", code] }
end

.original_languages?(code) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/bible270/translations.rb', line 72

def original_languages?(code)
  ORIGINAL_LANGUAGE_CODES.include?(normalize(code))
end

.passage_url(reference, version, blue_letter: false, bible_com: false) ⇒ Object



95
96
97
98
99
100
101
102
# File 'lib/bible270/translations.rb', line 95

def passage_url(reference, version, blue_letter: false, bible_com: false)
  return bible_com_url(reference, version) if bible_com
  return blue_letter_url(reference, version) if blue_letter || original_languages?(version)

  search = URI.encode_www_form_component(reference)
  gateway = URI.encode_www_form_component(gateway_code(version))
  "https://www.biblegateway.com/passage/?search=#{search}&version=#{gateway}"
end

.reference_start(reference) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/bible270/translations.rb', line 152

def reference_start(reference)
  books = Versification::VERSES.keys
  book_index = books.index { |book| reference.to_s.start_with?("#{book} ") }
  return unless book_index

  book = books[book_index]
  match = reference.to_s.delete_prefix("#{book} ").match(%r{\A(\d+)(?::(\d+))?})
  return unless match

  chapter = match[1].to_i
  verse = match[2]&.to_i || 1
  chapter_verses = Versification::VERSES[book]
  return unless chapter.between?(1, chapter_verses.length)
  return unless verse.between?(1, chapter_verses[chapter - 1])

  [book_index, chapter, verse]
end

.resolve(code) ⇒ Object

Falls back to the configured default, then to ESV, so a link is never built with a blank version.



172
173
174
175
176
177
178
179
# File 'lib/bible270/translations.rb', line 172

def resolve(code)
  return normalize(code) if valid?(code)

  configured = Bible270.config.bible_version if Bible270.config.respond_to?(:bible_version)
  return normalize(configured) if valid?(configured)

  codes.include?(DEFAULT) ? DEFAULT : codes.first
end

.short_label(code) ⇒ Object



80
81
82
# File 'lib/bible270/translations.rb', line 80

def short_label(code)
  VERSIONS.dig(normalize(code), :short) || label(code)
end

.valid?(code) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/bible270/translations.rb', line 64

def valid?(code)
  codes.include?(normalize(code))
end