Module: Howdoc::Narrator
- Defined in:
- lib/howdoc/narrator.rb
Overview
Turns an action and its payload into a sentence. The engine never contains a sentence itself -- every one of them is an I18n key, so the vocabulary is translatable and an application can reword any instruction without touching the code that records it.
Nothing here is settled while a test runs. A guide is recorded once and written out in every language it is published in, so a sentence is composed at writing time, once per language.
Defined Under Namespace
Classes: Field
Constant Summary collapse
- ROOT =
'howdoc'- ACTIONS =
:actions- FIELDS =
:fields- DOCUMENTS =
:documents
Class Method Summary collapse
- .call(action, locale:, **payload) ⇒ Object
-
.document_text(field, key:, locale:, default: nil) ⇒ Object
A guide's own words -- its title, its introduction -- come from the test that recorded it and are therefore written in one language.
-
.field(locator) ⇒ Object
Wraps a form field locator so it is named in the language of whichever edition is being written, rather than in the one the test ran in.
-
.field_label(locator, locale:) ⇒ Object
The label a reader would recognise for a form field.
-
.humanize_locator(locator) ⇒ Object
Rails names fields after the model that owns them, which is noise to anyone who does not know the schema, so the leading segment is dropped.
-
.known?(action, locales) ⇒ Boolean
Whether any of the languages a guide is published in has a sentence for this action.
-
.missing_keys ⇒ Object
Keys that were asked for but not translated, reported once at the end of a run rather than silently producing a guide with holes in it.
-
.phrase(*path, locale:, default: nil) ⇒ Object
The gem's own words -- the ones its templates print rather than the ones it narrates a step with.
- .reset_missing_keys ⇒ Object
- .translated?(action, locale) ⇒ Boolean
Class Method Details
.call(action, locale:, **payload) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/howdoc/narrator.rb', line 48 def call(action, locale:, **payload) sentence = lookup(ACTIONS, action, locale:) if sentence.nil? record_missing(action_key(action), locale) return nil end values = resolve(payload, locale) values.empty? ? sentence : I18n.interpolate(sentence, values) end |
.document_text(field, key:, locale:, default: nil) ⇒ Object
A guide's own words -- its title, its introduction -- come from the test
that recorded it and are therefore written in one language. Translating
howdoc.documents.
92 93 94 95 96 |
# File 'lib/howdoc/narrator.rb', line 92 def document_text(field, key:, locale:, default: nil) return default if key.nil? || key.empty? lookup(DOCUMENTS, key, field, locale:) || default end |
.field(locator) ⇒ Object
Wraps a form field locator so it is named in the language of whichever edition is being written, rather than in the one the test ran in.
44 45 46 |
# File 'lib/howdoc/narrator.rb', line 44 def field(locator) Field.new(locator) end |
.field_label(locator, locale:) ⇒ Object
The label a reader would recognise for a form field.
A translation under howdoc.fields wins, which is how a field whose generated name reads badly gets a proper name without any code knowing about it. Otherwise the configured convention applies.
82 83 84 85 86 |
# File 'lib/howdoc/narrator.rb', line 82 def field_label(locator, locale:) return '' if locator.nil? lookup(FIELDS, locator, locale:) || Howdoc.config.field_label.call(locator) end |
.humanize_locator(locator) ⇒ Object
Rails names fields after the model that owns them, which is noise to anyone who does not know the schema, so the leading segment is dropped.
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/howdoc/narrator.rb', line 108 def humanize_locator(locator) string = locator.to_s if string.include?('[') string.split('[').last.tr(']', '').tr('_', ' ').strip elsif string.include?('_') string.split('_').drop(1).join(' ') else string end end |
.known?(action, locales) ⇒ Boolean
Whether any of the languages a guide is published in has a sentence for this action. A step no language can say anything about is not recorded at all -- it would otherwise leave a numbered instruction with nothing in it, or an illustration of nothing.
64 65 66 67 68 69 70 71 |
# File 'lib/howdoc/narrator.rb', line 64 def known?(action, locales) return false if action.nil? return true if locales.any? { |locale| translated?(action, locale) } locales.each { |locale| record_missing(action_key(action), locale) } false end |
.missing_keys ⇒ Object
Keys that were asked for but not translated, reported once at the end of a run rather than silently producing a guide with holes in it. A key is missing in a particular language, so the language is part of it.
34 35 36 |
# File 'lib/howdoc/narrator.rb', line 34 def missing_keys @missing_keys ||= [] end |
.phrase(*path, locale:, default: nil) ⇒ Object
The gem's own words -- the ones its templates print rather than the ones it narrates a step with. Looked up the safe way, so an application whose I18n cascades cannot answer an untranslated "howdoc.index.intro" with some unrelated top-level "intro" of its own.
102 103 104 |
# File 'lib/howdoc/narrator.rb', line 102 def phrase(*path, locale:, default: nil) lookup(*path, locale:) || default end |
.reset_missing_keys ⇒ Object
38 39 40 |
# File 'lib/howdoc/narrator.rb', line 38 def reset_missing_keys @missing_keys = [] end |
.translated?(action, locale) ⇒ Boolean
73 74 75 |
# File 'lib/howdoc/narrator.rb', line 73 def translated?(action, locale) !lookup(ACTIONS, action, locale:).nil? end |